2009-08-10 7 views
6

Ich möchte Assembler-Code für berechnen sin(x) (mit "Taylor-Erweiterung") in Linux.Assembly-Code für sin (x)

+0

dies einmal getan, vor Jahren ... kein Spaß –

Antwort

7

Würde dieser Artikel Ihnen helfen?

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

Es hat ein paar Algorithmen für die ungefähre sin Berechnung (x) Werte, sowohl mit C und Assembler-Versionen. Zugegeben, es ist ARM-Assembly, aber der Kern davon sollte leicht zu x86 oder ähnlichem übersetzen.

+0

toller Link. Vielen Dank! – kenny

+0

jemand zeigen mir in Richtung Mathe für Anfänger .. bitte.Dieser Link gibt mir Albträume :) –

+0

@ dark-star1: check out http://khanacademy.org - Es gibt eine Reihe von Videos über approximierende Funktionen etwa auf halbem Weg in die Calculus-Playlist, und es gibt Videos für jede Ebene der Mathematik im Vorfeld zu ihm. – Cogwheel

9

Sie geben nicht an, welche CPU-Architektur, also nehme ich x86 an.

Der einfachste (und möglicherweise ineffizienteste) Weg wäre, die Formel in RPN zu schreiben, die fast direkt auf FPU-Anweisungen abgebildet werden kann.

Beispiel,

algebraische Formel: x - (! X^3/3) + (! X^5/5)

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

, die wird:

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 

Es gibt einige offensichtliche Optimierungsstrategien -

  • statt x die Berechnung x x x, x x x x x usw. für jeden Begriff, speichern ein 'Produkt läuft' und nur multiplizieren von x * x jedes Mal
  • statt von die Fakultät für jeden Begriff Berechnung, das gleiche ‚laufende Produkt‘ do

Hier einige kommentierten Code für x86-FPU, zeigen die Kommentare nach jedem FPU-Befehl des Stapelzustand nach diesem Befehl ex hat ecuted, mit dem Stack-Top (ST0) auf der linken Seite, zum Beispiel:

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 

das Programm ausgeführt wird:

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

Warum? Es gibt bereits eine EKAS und FSIN Opcode seit dem 80387 (circa 1987) Prozessor

Quelle:

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

Wikipedia

persönlicher Freund von Demoszene

+0

Es ist wahrscheinlich eine Hausaufgabe. –