Assembly 计算sin(x)的mips程序

Assembly 计算sin(x)的mips程序,assembly,mips,Assembly,Mips,我有一个等式: 我试图通过在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 e

我有一个等式:

我试图通过在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
#读取整数
李$v0,5
系统调用
addi$a0,$v0,0#sin函数的参数,a0=x
li$t4,1#n从1开始
addi$s7$v0,0#总和=x
日新
j端
罪:
循环:
slti$t5、$t4、5#t0<5(n<5)
beq$t5,0,出口
addi$sp,$sp,-8#调整2个项目的堆栈
sw$ra,4($sp)#保存回信地址
sw$a0,0($sp)#保存参数
li$a0,-1#pow函数的参数,数字=-1
addi$a1,$t4,pow函数的0#参数,幂=t4
日航电力
addi$s0,$v0,0#s0=v0(功率返回值)
lw$a0,0($sp)#恢复原始x
sll$a1,$t4,1#a1=2n
addi$a1,$a1,1#a1=2n+1
日航电力
addi$s1,$v0,0#s0=v0(功率返回值)
sll$a0,$t4,1#a0=2n
addi$a0,$a0,1#a0=2n+1
日航阶乘
addi$s2,$v0,0#s0=v0(功率返回值)
lw$a0,0($sp)#恢复原始状态n
lw$ra,4($sp)#和回信地址
mult$s0,$s1#LO=(-1)^n*x^(2n+1)
mflo$s3#s3=LO
部门$s3,$s2#s3/(2n+1!)
mflo$s3
加上$s7、$s7、$s3#总和=总和+s3
加上$t4,$t4,1#n++
j环
exitLoop:
addi$v1、$s7、0
附加$sp,$sp,8
jr$ra
权力:
addi$t0$a0,0#t0=a0
li$t1,0#i=0
循环:
slt$t3、$t1、$a1#如果i
正如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;
}
double
qsin(双x)
{
双x2;
双电流;
int neg;
双xpow;
双n2m1;
双nfac;
国际热核试验堆;
双和;
//x的平方
x2=x*x;
//初始项的值,其中n==0:
xpow=x;
n2m1=1.0;
nfac=1.0;
负=1;
总和=0.0;
//注:
//(1)通过上述设置,我们可以只使用循环,而无需任何特殊设置
//套管
//(2)这将对……进行不必要的计算[被扔掉]
//最后一次迭代,但这是一个简单性的折衷
//(3)当转换为asm时,应易于重组以避免
//这(即,这里更难在循环中表达)
对于(iters=5;iters>0;--iters){
//计算当前值
cur=xpow/nfac;
//将其应用于求和
如果(负<0)
sum-=cur;
其他的
sum+=cur;
//现在计算下一个和项的中间值
//获取下一个幂项
xpow*=x2;
//从阶乘(2n+1)到阶乘(2n+1+1)
n2m1+=1.0;
nfac*=n2m1;
//现在得到阶乘(2n+1+1+1)
n2m1+=1.0;
nfac*=n2m1;
//翻转标志
负=-负;
}
回报金额;
}

使用整数算法不会让您走得很远,您知道
-1对于这两个函数(幂函数和阶乘函数),我不会每次都进行完整的计算。存储上一个值,然后只计算下一个值所需的最后两个步骤
x^7是(x^5)(存储在上一个循环中)*x*x
x^19是(x^17)*x*x