Vorrei il codice assembly per calcolare sin(x)
(utilizzando "Taylor Expansion") in Linux.Codice assembly per sin (x)
risposta
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.
ottimo link. Grazie! – kenny
qualcuno mi indica in direzione della matematica per i principianti .. per favore.Questo collegamento mi sta dando degli incubi :) –
@ 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
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
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
Probabilmente è un esercizio di compiti a casa. –
ha fatto questo una volta, anni fa ... non divertente –