如何使用 Assembly MIPS {提供的公式}计算 sin(x)?

发布于 2024-11-01 22:32:49 字数 179 浏览 5 评论 0原文

我只是坚持如何使用以下公式在 Assembly MIPS 中计算 sin(x)

https://i .sstatic.net/YmxL4.jpg


如果您有任何想法,请写下来..

I'm just stuck with how to compute sin(x) in Assembly MIPS using the following formula

https://i.sstatic.net/YmxL4.jpg

plz if you have any idea write it down..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁梦 2024-11-08 22:32:49

此文章来自 Matthew Stanton

## Matthew Stanton
## Finds the value of sin(x)
## Register Use:
## $t0 value of n
## $f0 (Series*x^2)/(n(n-1))
## $f1 absolute value of (x^2)/(n(n-1))
## $f2 holds x^2
## $f3 holds remainders +or-(x^2)/(n(n-1))
## $f4 accuracey
## $f12 Holds sin(x)

.text
.globl main

main:
li $t0,3 # Initilize N
li.s $f4,1.0e-6 # Set Accuracey
li $v0,4 # syscall for Print String
la $a0, prompt1 # load address of prompt
syscall # print the prompt
li $v0,6 # Reads user number
syscall
mul.s $f2,$f0,$f0 # x^2
mov.s $f12,$f0 # Answer
for:
abs.s $f1,$f0 # compares to the non-negative value of the series
c.lt.s $f1,$f4 # is number < 1.0e-6?
bc1t endfor
subu $t1,$t0,1 # (n-1)
mul $t1,$t1,$t0 # n(n-1)
mtc1 $t1, $f3 # move n(n-1) to a floating register
cvt.s.w $f3, $f3 # converts n(n-1) to a float
div.s $f3,$f2,$f3 # (x^2)/(n(n-1))
neg.s $f3,$f3 # -(x^2)/(n(n-1))
mul.s $f0,$f0,$f3 # (Series*x^2)/(n(n-1))

add.s $f12,$f12,$f0 # Puts answer into $f12

addu $t0,$t0,2 # Increment n
b for # Goes to the beggining of the loop
endfor:
li $v0,2 # Prints answer in $f12
syscall
li $v0,10 # code 10 == exit
syscall # Halt the program.




.data
prompt1: .asciiz "Program will calculate sin(x). Please input a value for x!"

此代码来自

; FILE: Source:sinegen.ASM          REV: 31 --- 16-bit sinetable generator
; History
;  31     18th September 1998: 1st version.
;

    IFGT    0

Inspiration for this document and source came from PAC/#amycoders
who needed good&short sinetable generator. My friend ArtDent coded
this kind of routine years ago, but unfortunately he didn't backup
his amiga sources when he went pc. Anyways he still remembered the
principle well and he pointed me the algorithm to use. This whole
document and source was written by me (Piru) in 5 hours.

 sine&cosine table generation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lets have a look at sine and cosine graph:

      pi   2pi
     _ |   |
   |/|\| | |
 --/-+-\-+-/--
   | | |\|/|
   0 |   T
     |   |
   1/2pi 3/2pi

      pi 3/2pi
   _   | | _
   |\| | |/|
 --+-\-+-/-+--
   | |\_/| |
   0 |     |
    1/2pi  2pi


We notice that sine is phase shifted 90 degrees compared to
cosine. Also we notice that both sine and cosine are symmetrical
to 1/2pi and pi, thus can be easily mirrored. So we need to
calculate only 90 degrees of either sine or cosine and we can
derive whole table from it and also the other function.

These are the formulas to calculate sin x and cos x:

 sin x = x - x^3 / 3! + x^5 / 5! - x^7 / 7! + ...

 cos x = 1 - x^2 / 2! + x^4 / 4! - x^6 / 6! + ...

x is real, 0 <= x <= 1/2pi


Out of these two the latter (cos x) is easier to calculate.

You can save space by combining sine and cosine tables. Just
take last 90 degrees of cosine before cosine table and you
have sinetable at table - 90 degrees. :)

So after thinking a while I came up with this pseudocode
routine that calculates 90 degrees of sine + 360 degrees
cosine:

in: table, tablesize (90 degrees * 5)

quart = tablesize / 5
x = 0; x_add = (1/2 * pi) / quart
for q = 0 to (quart - 1)
  fact = 1; d = 0; cosx = 1; powx = 1
  powx_mul = - (x * x)   ; rem this will magically toggle sign
  repeat
    powx = powx * powx_mul
    d++; fact = fact * d
    d++; fact = fact * d
    cosx = cosx + powx / fact
  until d = 12
  table[quart - q] = cosx           ; rem  /¯
  table[quart + q] = cosx           ; rem    ¯\
  table[quart * 3 - q] = -cosx      ; rem      \_
  table[quart * 3 + q] = -cosx      ; rem        _/
  table[quart * 5 - q] =  cosx      ; rem          /¯
  x = x + x_add
endfor

Then I just coded this in 020+ asm adding fixedpoint math
and stuff:

    ENDC

TESTSINE    SET 0
    IFNE    TESTSINE

Main    lea (sine,pc),a0
    move.l  #256,d0
    bsr sinegen
    rts

sine    ds.w    256
cosine  ds.w    256*4
    ENDC

; 68020+ 16:16 fixedpoint sinetable generator.
; Coded by Harry "Piru" Sintonen.
; Not specially optimized as usually this thing is ran only once at
; init time. 68060 will woe on 64 bit muls & swaps - who cares ;)

; IN:  a0.l=pointer to array of word (will contain 450 degree 16-bit sinetable)
;      d0.l=wordsper90degrees
; OUT: d0.l=0
sinegen
    movem.l d0-d7/a0-a5,-(sp)

    move.l  #26353589,d1    ; pi/2*65536*256
    divu.l  d0,d1
    move.l  d1,a5

    add.l   d0,d0
    add.l   d0,a0
    lea 0(a0,d0.l*2),a2
    lea 0(a0,d0.l*4),a4
    move.l  a0,a1
    move.l  a2,a3
    addq.l  #2,a1       ; these two can be removed
    addq.l  #2,a2       ; really ;)

    moveq   #0,d0       ; x

    moveq   #12,d7

.oloop  move.l  d0,d5
    moveq   #1,d1
    lsr.l   #8,d5
    swap    d1      ; 1<<16 = cos x
    move.l  d1,d3

    mulu.l  d5,d4:d5
    move.w  d4,d5
    moveq   #0,d2       ; d
    swap    d5
    moveq   #1,d6       ; factorial
    neg.l   d5      ; change sign of powx

.iloop  muls.l  d5,d4:d3    ; calculate x^d
    move.w  d4,d3
    swap    d3
    move.l  d3,d4

    addq.l  #1,d2       ; calculate d!
    mulu.l  d2,d6
    addq.l  #1,d2
    mulu.l  d2,d6

    divs.l  d6,d4
    add.l   d4,d1       ; cos x += x^d / d!

    cmp.l   d7,d2
    bne.b   .iloop

    lsr.l   #1,d1
    tst.w   d1      ; if d1=$8000 then d1=d1-1 ;)
    dbpl    d1,.rule
.rule
    move.w  d1,(a0)+
    move.w  d1,-(a1)
    move.w  d1,-(a4)
    neg.w   d1
    move.w  d1,-(a2)
    move.w  d1,(a3)+

    add.l   a5,d0
    subq.l  #1,(sp)     ; watch out - don't mess with stack:)
    bne.b   .oloop

    movem.l (sp)+,d0-d7/a0-a5
    rts

this one is from Matthew Stanton

## Matthew Stanton
## Finds the value of sin(x)
## Register Use:
## $t0 value of n
## $f0 (Series*x^2)/(n(n-1))
## $f1 absolute value of (x^2)/(n(n-1))
## $f2 holds x^2
## $f3 holds remainders +or-(x^2)/(n(n-1))
## $f4 accuracey
## $f12 Holds sin(x)

.text
.globl main

main:
li $t0,3 # Initilize N
li.s $f4,1.0e-6 # Set Accuracey
li $v0,4 # syscall for Print String
la $a0, prompt1 # load address of prompt
syscall # print the prompt
li $v0,6 # Reads user number
syscall
mul.s $f2,$f0,$f0 # x^2
mov.s $f12,$f0 # Answer
for:
abs.s $f1,$f0 # compares to the non-negative value of the series
c.lt.s $f1,$f4 # is number < 1.0e-6?
bc1t endfor
subu $t1,$t0,1 # (n-1)
mul $t1,$t1,$t0 # n(n-1)
mtc1 $t1, $f3 # move n(n-1) to a floating register
cvt.s.w $f3, $f3 # converts n(n-1) to a float
div.s $f3,$f2,$f3 # (x^2)/(n(n-1))
neg.s $f3,$f3 # -(x^2)/(n(n-1))
mul.s $f0,$f0,$f3 # (Series*x^2)/(n(n-1))

add.s $f12,$f12,$f0 # Puts answer into $f12

addu $t0,$t0,2 # Increment n
b for # Goes to the beggining of the loop
endfor:
li $v0,2 # Prints answer in $f12
syscall
li $v0,10 # code 10 == exit
syscall # Halt the program.




.data
prompt1: .asciiz "Program will calculate sin(x). Please input a value for x!"

This code is from

; FILE: Source:sinegen.ASM          REV: 31 --- 16-bit sinetable generator
; History
;  31     18th September 1998: 1st version.
;

    IFGT    0

Inspiration for this document and source came from PAC/#amycoders
who needed good&short sinetable generator. My friend ArtDent coded
this kind of routine years ago, but unfortunately he didn't backup
his amiga sources when he went pc. Anyways he still remembered the
principle well and he pointed me the algorithm to use. This whole
document and source was written by me (Piru) in 5 hours.

 sine&cosine table generation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lets have a look at sine and cosine graph:

      pi   2pi
     _ |   |
   |/|\| | |
 --/-+-\-+-/--
   | | |\|/|
   0 |   T
     |   |
   1/2pi 3/2pi

      pi 3/2pi
   _   | | _
   |\| | |/|
 --+-\-+-/-+--
   | |\_/| |
   0 |     |
    1/2pi  2pi


We notice that sine is phase shifted 90 degrees compared to
cosine. Also we notice that both sine and cosine are symmetrical
to 1/2pi and pi, thus can be easily mirrored. So we need to
calculate only 90 degrees of either sine or cosine and we can
derive whole table from it and also the other function.

These are the formulas to calculate sin x and cos x:

 sin x = x - x^3 / 3! + x^5 / 5! - x^7 / 7! + ...

 cos x = 1 - x^2 / 2! + x^4 / 4! - x^6 / 6! + ...

x is real, 0 <= x <= 1/2pi


Out of these two the latter (cos x) is easier to calculate.

You can save space by combining sine and cosine tables. Just
take last 90 degrees of cosine before cosine table and you
have sinetable at table - 90 degrees. :)

So after thinking a while I came up with this pseudocode
routine that calculates 90 degrees of sine + 360 degrees
cosine:

in: table, tablesize (90 degrees * 5)

quart = tablesize / 5
x = 0; x_add = (1/2 * pi) / quart
for q = 0 to (quart - 1)
  fact = 1; d = 0; cosx = 1; powx = 1
  powx_mul = - (x * x)   ; rem this will magically toggle sign
  repeat
    powx = powx * powx_mul
    d++; fact = fact * d
    d++; fact = fact * d
    cosx = cosx + powx / fact
  until d = 12
  table[quart - q] = cosx           ; rem  /¯
  table[quart + q] = cosx           ; rem    ¯\
  table[quart * 3 - q] = -cosx      ; rem      \_
  table[quart * 3 + q] = -cosx      ; rem        _/
  table[quart * 5 - q] =  cosx      ; rem          /¯
  x = x + x_add
endfor

Then I just coded this in 020+ asm adding fixedpoint math
and stuff:

    ENDC

TESTSINE    SET 0
    IFNE    TESTSINE

Main    lea (sine,pc),a0
    move.l  #256,d0
    bsr sinegen
    rts

sine    ds.w    256
cosine  ds.w    256*4
    ENDC

; 68020+ 16:16 fixedpoint sinetable generator.
; Coded by Harry "Piru" Sintonen.
; Not specially optimized as usually this thing is ran only once at
; init time. 68060 will woe on 64 bit muls & swaps - who cares ;)

; IN:  a0.l=pointer to array of word (will contain 450 degree 16-bit sinetable)
;      d0.l=wordsper90degrees
; OUT: d0.l=0
sinegen
    movem.l d0-d7/a0-a5,-(sp)

    move.l  #26353589,d1    ; pi/2*65536*256
    divu.l  d0,d1
    move.l  d1,a5

    add.l   d0,d0
    add.l   d0,a0
    lea 0(a0,d0.l*2),a2
    lea 0(a0,d0.l*4),a4
    move.l  a0,a1
    move.l  a2,a3
    addq.l  #2,a1       ; these two can be removed
    addq.l  #2,a2       ; really ;)

    moveq   #0,d0       ; x

    moveq   #12,d7

.oloop  move.l  d0,d5
    moveq   #1,d1
    lsr.l   #8,d5
    swap    d1      ; 1<<16 = cos x
    move.l  d1,d3

    mulu.l  d5,d4:d5
    move.w  d4,d5
    moveq   #0,d2       ; d
    swap    d5
    moveq   #1,d6       ; factorial
    neg.l   d5      ; change sign of powx

.iloop  muls.l  d5,d4:d3    ; calculate x^d
    move.w  d4,d3
    swap    d3
    move.l  d3,d4

    addq.l  #1,d2       ; calculate d!
    mulu.l  d2,d6
    addq.l  #1,d2
    mulu.l  d2,d6

    divs.l  d6,d4
    add.l   d4,d1       ; cos x += x^d / d!

    cmp.l   d7,d2
    bne.b   .iloop

    lsr.l   #1,d1
    tst.w   d1      ; if d1=$8000 then d1=d1-1 ;)
    dbpl    d1,.rule
.rule
    move.w  d1,(a0)+
    move.w  d1,-(a1)
    move.w  d1,-(a4)
    neg.w   d1
    move.w  d1,-(a2)
    move.w  d1,(a3)+

    add.l   a5,d0
    subq.l  #1,(sp)     ; watch out - don't mess with stack:)
    bne.b   .oloop

    movem.l (sp)+,d0-d7/a0-a5
    rts
烈酒灼喉 2024-11-08 22:32:49

要计算 X*3,需要 3 次乘法。要计算 X*5,还需要进行 2 次乘法运算。为了获得合理的精度,需要进行大量的乘法运算。然后是方程的阶乘部分 - 为了获得合理的精度,它也需要进行大量的加法。

你不能用查找表来解决性能问题;因为查找表比拥有“sin”查找表的成本更高。

基本上,您需要找到适合计算机的不同公式。

我很想从 CORDIC 开始: http://en.wikipedia.org/wiki/CORDIC

To calculate X*3 it will take 3 multiplications. To calculate X*5 it'll cost 2 more multiplications. To get reasonable precision, it's going to add up to a lot of multiplications. Then there's the factorial part of the equation - for reasonable precision, it's a lot of addition too.

You can't solve the performance problems with lookup tables; as the lookup tables would cost more than having a lookup table for "sin" instead.

Basically, you need to find a different formula that's suitable for computers.

I'd be tempted to start with CORDIC: http://en.wikipedia.org/wiki/CORDIC

  • Brendan
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文