2009-08-10 73 views
6

我想在Linux中使用匯編代碼計算sin(x)(使用「泰勒展開」)。sin(x)的彙編代碼

+0

個人的朋友做這一次,年前...不好玩 – 2010-11-23 07:17:25

回答

7

這篇文章對您有幫助嗎?

http://www.coranac.com/2009/07/sines/

它有一對夫婦的算法用於計算近似的sin(x)的值,與C和彙編的版本。當然,這是ARM組裝,但它的要點應該很容易轉換成x86或類似的。

+0

偉大的鏈接。謝謝! – kenny 2009-08-15 12:28:54

+0

有人指點我的數學初學者的方向..請。這個鏈接給了我惡夢:) – 2009-08-15 12:56:04

+0

@ dark-star1:退房http://khanacademy.org - 有一組關於微積分播放列表中的近似函數的視頻,並且每個級別的數學引導都有視頻到它。 – Cogwheel 2010-07-16 18:29:30

9

你不說明哪個CPU架構,所以我假設x86。

簡單的(也可能是效率最低的)方法是將公式寫入RPN,它可以直接映射到FPU指令。

實施例,

代數公式:X - (!X^3/3)+(!X^5/5)

RPN:XXX * X * 3 2 */- XX * X * X * X * 5 4 * 3 * 2 */+

成爲:

fld x 
fld x 
fld x 
fmul 
fld x 
fmul 
fild [const_3] 
fild [const_2] 
fmul 
fdiv 
fsub 
fld x 
fld x 
fmul 
fld x 
fmul 
fld x 
fmul 
fld x 
fmul 
fild [const_5] 
fild [const_4] 
fmul 
fild [const_3] 
fmul 
fild [const_2] 
fmul 
fdiv 
fadd 

有一些明顯的優化策略 -

  • 代替計算X,X X X, X X X X X等每個術語,存儲 '投放產品' 和只是乘法 由X * X每次
  • 代替的 計算階乘每個 來看,做同樣的「運行產品」

下面是針對x86 FPU一些註釋代碼,每個FPU指令之後的評論顯示堆棧狀態後,該指令具有前ecuted,與棧頂(ST0)在左邊,如:

fldz ; 0 
fld1 ; 1, 0 

--snip--

bits 32 

section .text 

extern printf 
extern atof 
extern atoi 
extern puts 
global main 

taylor_sin: 
    push eax 
    push ecx 

    ; input : 
    ; st(0) = x, value to approximate sin(x) of 
    ; [esp+12] = number of taylor series terms 

    ; variables we'll use : 
    ; s = sum of all terms (final result) 
    ; x = value we want to take the sin of 
    ; fi = factorial index (1, 3, 5, 7, ...) 
    ; fc = factorial current (1, 6, 120, 5040, ...) 
    ; n = numerator of term (x, x^3, x^5, x^7, ...) 

    ; setup state for each iteration (term) 
    fldz ; s x 
    fxch st1 ; x s 
    fld1 ; fi x s 
    fld1 ; fc fi x s 
    fld st2 ; n fc fi x s 

    ; first term 
    fld st1 ; fc n fc fi x s 
    fdivr st0,st1 ; r n fc fi x s 
    faddp st5,st0 ; n fc fi x s 

    ; loop through each term 
    mov ecx,[esp+12] ; number of terms 
    xor eax,eax ; zero add/sub counter 

loop_term: 
    ; calculate next odd factorial 
    fld1 ; 1 n fc fi x s 
    faddp st3 ; n fc fi x s 
    fld st2 ; fi n fc fi x s 
    fmulp st2,st0 
    fld1 ; 1 n fc fi x s 
    faddp st3 ; n fc fi x s 
    fld st2 ; fi n fc fi x s 
    fmulp st2,st0 ; n fc fi x s 

    ; calculate next odd power of x 
    fmul st0,st3 ; n*x fc fi x s 
    fmul st0,st3 ; n*x*x fc fi x s 

    ; divide power by factorial 
    fld st1 ; fc n fc fi x s 
    fdivr st0,st1 ; r n fc fi x s 

    ; check if we need to add or subtract this term 
    test eax,1 
    jnz odd_term 
    fsubp st5,st0 ; n fc fi x s 
    jmp skip 
odd_term: 
    ; accumulate result 
    faddp st5,st0 ; n fc fi x s 
skip: 
    inc eax ; increment add/sub counter 
    loop loop_term 

    ; unstack work variables 
    fstp st0 
    fstp st0 
    fstp st0 
    fstp st0 

    ; result is in st(0) 

    pop ecx 
    pop eax 

    ret 

main: 

    ; check if we have 2 command-line args 
    mov eax, [esp+4] 
    cmp eax, 3 
    jnz error 

    ; get arg 1 - value to calc sin of 
    mov ebx, [esp+8] 
    push dword [ebx+4] 
    call atof 
    add esp, 4 

    ; get arg 2 - number of taylor series terms 
    mov ebx, [esp+8] 
    push dword [ebx+8] 
    call atoi 
    add esp, 4 

    ; do the taylor series approximation 
    push eax 
    call taylor_sin 
    add esp, 4 

    ; output result 
    sub esp, 8 
    fstp qword [esp] 
    push format 
    call printf 
    add esp,12 

    ; return to libc 
    xor eax,eax 
    ret 

error: 
    push error_message 
    call puts 
    add esp,4 
    mov eax,1 
    ret 

section .data 

error_message: db "syntax: <x> <terms>",0 
format: db "%0.10f",10,0 

運行程序:

$ ./taylor-sine 0.5 1 
0.4791666667 
$ ./taylor-sine 0.5 5 
0.4794255386 
$ echo "s(0.5)"|bc -l 
.47942553860420300027 
6

爲什麼?已經有自80387(大約1987)處理器

源的FCOS和FSIN操作碼:

http://ref.x86asm.net/coder32.html

維基百科

從演示現場

+0

這可能是一個家庭作業練習。 – 2010-11-23 07:18:02