I'm trying to calculate the Taylor Series
1 + x + x2 / 2! + x3 / 3! + ... + x10 / 10!.
My program gives me infinity every time, I'm brand new to MIPS. I am only concerned about the input when it is between 0 and 10, inclusive. we are stopping at xn/n! when n = 10. Heres what I came up with:
# A program to first, find the power of x^n and the factorial of n. x,n are both between 0-10 inclusive. Then it finds the taylor series
.data
pr1: .asciiz "Enter Float x: "
.text
.globl main
main:
la $a0, pr1 # prompt user for x
li $v0,4 # print string
syscall
li $v0, 6 # read single
syscall
mtc1 $v0, $f0 # f0 <--- x
exponent: # f0 --> x
mul.s $f1, $f0, $f0 # f1 --> x^2
mul.s $f2, $f1, $f0 # f2 --> x^3
mul.s $f3, $f2, $f0 # f3 --> x^4
mul.s $f4, $f3, $f0 # f4 --> x^5
mul.s $f5, $f4, $f0 # f5 --> x^6
mul.s $f6, $f5, $f0 # f6 --> x^7
mul.s $f7, $f6, $f0 # f7 --> x^8
mul.s $f8, $f7, $f0 # f8 --> x^9
mul.s $f9, $f8, $f0 # f9 --> x^10
factorial:
li $s0, 1 # n = 10
li $t0, 1
add $t0, $t0, $s0 # t0 = 2! = 2
add $t1, $t0, $s0 # t1 = 3
mul $t1, $t1, $t0 # t1 = 3! = 6
add $t2, $t0, $t0 # t2 = 4
mul $t2, $t2, $t1 # t2 = 4! = 24
addi $t3, $t1, -1 # t3 = 5
mul $t3, $t3, $t2 # t3 = 5! = 120
add $t4, $t1, $zero # t4 = 6
mul $t4, $t4, $t3 # t4 = 6! = 720
addi $t5, $t1, 1 # t5 = 7
mul $t5, $t5, $t4 # t5 = 7! = 5040
add $t6, $t1, $t0 # t6 = 8
mul $t6, $t6, $t5 # t6 = 8! = 40320
add $t7, $t1, $t0
addi $t7, $t7, 1 # t7 = 9
mul $t7, $t7, $t6 # t7 = 9! = 362880
mul $s1, $t0, 5 # s1 = 10
mul $s1, $s1, $t7 # s1 = 10! = 3628800
taylor:
mtc1 $s0, $f10 # $f10 = 1
cvt.s.w $f10, $f10 # convert to float
add.s $f0, $f0, $f10 # = 1 + x
mtc1 $t0, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f1 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^2/2!
mtc1 $t1, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f2 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x +.. + x^3/3!
mtc1 $t2, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f3 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x +..+ x^4/4!
mtc1 $t3, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f4 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^5/5!
mtc1 $t4, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f5 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^6/6!
mtc1 $t5, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f6 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^7/7!
mtc1 $t6, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f7 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^8/8!
mtc1 $t7, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f8 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^9/9!
mtc1 $s1, $f10 # move n! to cp1
cvt.s.w $f10, $f10 # convert to float
div.s $f10, $f10, $f9 # divide x^n/ n
add.s $f0, $f0, $f10 # = 1 + x + x^10/10!
end:
mov.s $f12, $f0 # argument
li $v0, 2 # print float
syscall
li $v0, 10
syscall
To start with, you have a few bugs:
(1) As Jester mentioned, your "read float" syscall had a bug.
(2) You're calculating
factorial(n)
but the Taylor cosine series usesfactorial(2n)
, so it increases more quickly.(3) Another problem you may be having [would be having with the correct factorial] is that you're using integer math for the factorial. When calculating to 10 iterations, the factorial will overflow a 32 bit integer. For 10 iterations, we end up with [at least]
factorial(18)
which is ~6.4e15 (i.e. does not fit in a 32 integer). With integer math, the factorial, instead of increasing steadily, will "oscillate" whenever the value wraps 32 bits.I've taken a slightly different approach.
Rather than pre-calculate everything [as you've done], I created a solution that uses a loop. That may or may not help you with debugging your own implementation, but I'd be remiss if I didn't recommend refactoring.
Below is asm code for the loop implementation. There is also a C version that I used to debug the algorithm first. There is also an asm version with some debug statements.
Rationale:
You're trying to calculate
cos
using Taylor Series summation/expansion [to 10 iterations]. The formula does use a "summation" operator, after all.You're precalculating all
x^n
terms and all factorial terms and putting them in different registers. That's fine as MIPS has 32 FP registers. But, with double precision, we'd have to use two registers, so that would mean only 16 numbers. In a way, what you did is the equivalent of a compiler doing "loop unrolling".Another issue is that it can be hard to keep track of all those registers. What is holding what value.
And, suppose, the problem were to use 20 iterations instead of 10. We'd probably run out of registers. In practice, this might be necessary for other series expansions because we might not get convergence as quickly.
So, I'd recommend using a loop. Each power term is easily calculated from the previous one. Likewise, for each factorial.
Another advantage to using the loop approach is that rather than using a fixed number of iterations, we can monitor the term value [
cur
] (which is getting smaller and smaller) and if it changes by less than a certain amount [or is smaller than that amount] (e.g. for double precision, 1e-14) we can stop because our values won't get any better than the precision our floating point format [and hardware] affords us.Note: This is not shown below but is easy enough to implement.
Here's the asm version. The variable names used in the comments refer to the variable names used in the C code [which follows afterward].
Here's the C code [it also has code for
sin(x)
]:Here's the asm version with debug statements I used. This is "printf debugging", just like in C.
Alternatively, both the
mars
andspim
simulators have builtin GUI debugging. You can single step the code by clicking on a single button. You can see a live display of all register values.Note: Personally, I prefer
mars
. This works withmars
but I don't know ifspim
supports.eqv
pseudo ops.Here's the debug output log for a single value: