mips程序来计算sin(x)

时间:2016-04-02 20:29:10

标签: assembly mips

我有这个等式: Summation of sin(x)

我试图通过在MIPS上创建一个程序来计算它。但是,它会输出不正确的大数字!我不知道我犯了什么愚蠢的错误。 我创造了三个函数,一个计算阶乘,另一个计算幂,第三个函数是sin函数。

#read integer
li $v0, 5
syscall

addi $a0, $v0, 0 #argument of sin function, a0 = x
li $t4, 1 #n starting from 1
addi $s7, $v0, 0 #sum = x
jal sin
j end

sin:
    Loop:
    slti $t5, $t4, 5 #t0 < 5 (n < 5)
    beq $t5, 0, exitLoop
    addi $sp, $sp, -8 # adjust stack for 2 items
    sw $ra, 4($sp) # save return address
    sw $a0, 0($sp) # save argument
    li $a0, -1 #argument of pow function, number = -1
    addi $a1, $t4, 0 #argument of pow function, power = t4
    jal power
    addi $s0, $v0, 0 #s0 = v0 (return value of pow)
    lw $a0, 0($sp) # restore original x

    sll $a1, $t4, 1 #a1 = 2n 
    addi $a1, $a1, 1 #a1 = 2n+1
    jal power
    addi $s1, $v0, 0 #s0 = v0 (return value of pow)

    sll $a0, $t4, 1 #a0 = 2n
    addi $a0, $a0, 1 #a0 = 2n + 1
    jal factorial
    addi $s2, $v0, 0 #s0 = v0 (return value of pow)
    lw $a0, 0($sp) # restore original n
    lw $ra, 4($sp) # and return address

    mult $s0, $s1 # LO = (-1)^n * x^(2n+1)
    mflo $s3 # S3 = LO
    div $s3, $s2 # s3 / (2n+1!)
    mflo $s3
    add $s7, $s7, $s3 #sum = sum + s3
    addi $t4, $t4, 1 #n++

    j Loop  
    exitLoop:
addi $v1, $s7, 0
addi $sp, $sp, 8
jr $ra

power:
    addi $t0 $a0, 0 #t0 = a0
    li $t1, 0 #i = 0
    loop:
    slt $t3, $t1, $a1 #if i < n
    beq $t3, 0, exit 
    mult $t0, $a0 #t0 * a0
    mflo $t0 #LO = t0
    addi $t1, $t1, 1
    j loop
    exit:
    addi $v0, $t0, 0
    jr $ra

factorial:
    li $t0, 1
    bgt $a0, $t0, L1
    li $v0, 1
    jr $ra
    L1:
    addi $sp, $sp, -8 # adjust stack for 2 items
    sw $ra, 4($sp) # save return address
    sw $a0, 0($sp) # save argument
    addi $a0, $a0, -1 # decrement n
    jal factorial # recursive call
    lw $a0, 0($sp) # restore original n
    mul $v0, $a0, $v0 # multiply to get result
    lw $ra, 4($sp) # and return address
    addi $sp, $sp, 8 # pop 2 items from stack
    jr $ra # and return
end:
li $v0, 1
addi $a0, $v1, 0
syscall

1 个答案:

答案 0 :(得分:0)

正如Jester所说,你应该使用浮点运算。

通过利用系列中的每个幂项和每个因子项是前一个的简单增量,您还可以大大简化事物。无需从头开始重新计算,也无需递归计算阶乘[它更多 更容易使用循环]。

根本不需要单独的功能。这是C中的函数。这是对asm的一个相对简单的翻译:

double
qsin(double x)
{
    double x2;
    double cur;
    int neg;
    double xpow;
    double n2m1;
    double nfac;
    int iters;
    double sum;

    // square of x
    x2 = x * x;

    // values for initial terms where n==0:
    xpow = x;
    n2m1 = 1.0;
    nfac = 1.0;
    neg = 1;

    sum = 0.0;

    // NOTES:
    // (1) with the setup above, we can just use the loop without any special
    //     casing
    // (2) this _will_ do an unnecessary calculation [that gets thrown away] on
    //     the last iteration, but it's a tradeoff for simplicity
    // (3) when translated to asm, it should be easy to restructure to avoid
    //     this (i.e. just harder to express in a loop here)
    for (iters = 5;  iters > 0;  --iters) {
        // calculate current value
        cur = xpow / nfac;

        // apply it to sum
        if (neg < 0)
            sum -= cur;
        else
            sum += cur;

        // now calculate intermediate values for _next_ sum term

        // get _next_ power term
        xpow *= x2;

        // go from factorial(2n+1) to factorial(2n+1+1)
        n2m1 += 1.0;
        nfac *= n2m1;

        // now get factorial(2n+1+1+1)
        n2m1 += 1.0;
        nfac *= n2m1;

        // flip sign
        neg = -neg;
    }

    return sum;
}