代码之家  ›  专栏  ›  技术社区  ›  Vipoon

计算sin(x)的mips程序

  •  0
  • Vipoon  · 技术社区  · 9 年前

    我有一个方程式: 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 回复  |  直到 9 年前
        1
  •  0
  •   Craig Estey    9 年前

    正如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;
    }