2016-04-02 5 views
0

Ich habe diese Gleichung: Summation of sin(x)Mips Programm zur Berechnung sin (x)

Ich versuche, dies zu berechnen, indem ein Programm auf MIPS zu schaffen. Es gibt jedoch falsche BIG-Nummern aus! Ich habe keine Ahnung, wo der dumme Fehler ist, den ich gemacht habe. Ich hatte drei Funktionen erstellt, eine, die die Fakultät berechnet, eine andere für die Macht, und die dritte große ist die Sünde-Funktion.

#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 
+2

Verwenden Ganzzahlarithmetik wird Sie nicht sehr weit, Sie wissen, dass -1 <= sin (x) <= 1, rechts ? – Jester

+0

für beide Funktionen (Power und Fakultät) würde ich nicht die ganze Berechnung jedes Mal tun. Speichern Sie die vorherigen Werte und berechnen Sie nur die letzten 2 Schritte, die für den nächsten Wert benötigt werden. 'x^7 ist (x^5) (was Sie in der vorherigen Schleife gespeichert haben) * x * x' wie' x^19 ist (x^17) * x * x' – Tommylee2k

Antwort

0

Wie Jester erwähnt, sollten Sie Gleitkommaarithmetik verwenden.

Sie können die Dinge auch erheblich vereinfachen, indem Sie die Tatsache ausnutzen, dass jeder Leistungsbegriff und jeder faktorielle Ausdruck in der Reihe ein einfaches Delta vom vorherigen ist. Keine Neuberechnung von Grund auf neu und keine Notwendigkeit, faktoriell rekursiv zu berechnen [es ist viel einfacher, eine Schleife zu verwenden].

Keine Notwendigkeit, separate Funktionen überhaupt zu haben. Hier ist die Funktion in C. Dies ist eine relativ einfache Übersetzung in 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; 
}