2009-08-10 13 views
6

Vorrei il codice assembly per calcolare sin(x) (utilizzando "Taylor Expansion") in Linux.Codice assembly per sin (x)

+0

ha fatto questo una volta, anni fa ... non divertente –

risposta

7

Questo articolo ti può aiutare?

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

ha un paio di algoritmi per il calcolo approssimativo sin (x) i valori, sia con C e le versioni di assemblaggio. Certo, è assemblaggio ARM, ma il succo dovrebbe tradursi facilmente in x86 o simili.

+0

ottimo link. Grazie! – kenny

+0

qualcuno mi indica in direzione della matematica per i principianti .. per favore.Questo collegamento mi sta dando degli incubi :) –

+0

@ dark-star1: consulta http://khanacademy.org - C'è una serie di video sulle funzioni approssimative a metà strada nella playlist di Calculus, e ci sono video per ogni livello di matematica che porta ad esso. – Cogwheel

9

Non si specifica l'architettura della CPU, quindi sto assumendo x86.

Il modo semplicistico (e probabilmente il più inefficiente) sarebbe scrivere la formula in RPN, che può essere mappata quasi direttamente alle istruzioni della FPU.

Esempio,

formula algebrica: x - (! X^3/3) + (! X^5/5)

RPN: xxx * x * 3 2 */- xx * x * x * x * 5 4 * 3 * 2 */+

che diventa:

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 

ci sono alcune ovvie strategie di ottimizzazione -

  • invece di calcolare x, x x x, x x x x x ecc per ogni termine, memorizzare un 'esecuzione del prodotto' e basta moltiplicare da x * x ogni volta
  • invece di calcolare il fattoriale per ogni termine , fare lo stesso 'prodotto disattivato'

Ecco po 'di codice per x86 commentato FPU, i commenti dopo ogni istruzione FPU mostrare lo stato dello stack dopo che l'istruzione ha ex eseguita sempre, con la parte superiore dello stack (st0) sulla sinistra, ad esempio:

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 

l'esecuzione del programma:

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

Perché? Esiste già un codice operativo FCOS e FSIN dal momento che la (circa 1987) processore

fonte 80387:

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

Wikipedia

amico personale da scena demo

+0

Probabilmente è un esercizio di compiti a casa. –