Autor Thema: Potenzieren mit der FPU  (Gelesen 6054 mal)

Thunder

  • Beiträge: 24
    • Profil anzeigen
Gespeichert
« am: 27. June 2013, 12:13 »
Hallo Leute,

ich bräuchte sehr die Hilfe von jemandem, der sich mit der FPU auskennt. Denn ich bin erst kurz dabei, was den Koprozessor betrifft...
Gestern habe ich versucht, eine Art pow für double Werte zu implementieren. Zuerst dachte ich, die FPU würde sowieso einen ähnlichen Befehl bereitstellen, aber als ich den nicht gefunden hab, war ich mir sicher, dass ich über die Befehle fyl2x und f2xm1 zum Ziel kommen würde. Nämlich über die einfache Umformung, dass a^b = 2 ^ (b * log2(a)) ist.
Ich habe folgende Funktion:
public _bbFloatPow
_bbFloatPow:
fld qword [esp+12] ; power
fld qword [esp+4] ; base

fyl2x ; power * log2(base)

f2xm1 ; 2^(power*log2(base))-1

fld1
faddp ; 2^(power*log2(base))
ret

und für kleine Werte kommen richtige ergebnisse heraus: pow(1, 2) = 1; pow(sqrt(2), 2) = 2; pow(4, 0.5) = 2
aber pow(2,2) = 3 und pow(8, 2) = 7 ... die Ungenauigkeiten beginnen über 2 oder so...

Weiß jemand woran das liegt und kann mir helfen, diese Fehler zu beheben? :)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 27. June 2013, 15:37 »
In der libm von tyndur sieht das ein bisschen komplizierter aus. Was natürlich nicht heißt, dass es kompliziert sein muss. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 28. June 2013, 01:04 »
Ich glaube der Grund dafür ist, dass f2xm1 nur mit Exponenten zwischen -1 und 1 funktioniert. Du musst also den Exponenten vorher in Ganzzahlanteil und Nachkommaanteil zerlegen und beide getrennt potenzieren und die Ergebnisse wieder zusammenmultiplizieren.
Dieser Text wird unter jedem Beitrag angezeigt.

Thunder

  • Beiträge: 24
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 28. June 2013, 14:41 »
Ja, tyndur verwendet offenbar einfach exp(power * log(base)) (also wahrscheinlich den natürlichen Logarithmus, aber das sollte ja mit jedem anderen auch gehen)...
Danke erst Mal Jidder, für den Tipp mit f2xm1. Ich bekomme es nur nicht hin, denn es funktioniert noch immer nicht. Ich habe jetzt den Exponenten in Ganzzahlteil und Nachkommateil zerlegt:
public _bbFloatPow
_bbFloatPow:
push ebp
mov ebp, esp
sub esp, 8

fld qword [ebp+16] ; power
fld qword [ebp+8] ; base

fyl2x ; power * log2(base)
fld st0 ; copy

fistp qword [ebp-8]
fild qword [ebp-8]
; st0 = int( power * log2(base) )
; st1 = power * log2(base)
fxch
fsub st0, st1
; st0 = power * log2(base) - int( power * log2(base) )
; st1 = int( power * log2(base) )
f2xm1
fld1
faddp
; st0 = 2 ^ ( power * log2(base) - int( power * log2(base) ) )
; st1 = int( power * log2(base) )
fxch
f2xm1
fld1
faddp
; st0 = 2 ^ ( power * log2(base) - int( power * log2(base) ) )
; st1 = 2 ^ ( int( power * log2(base) ) )

fmulp
; st0 = 2 ^ ( power * log2(base) )

leave
ret

Was mache ich aber, wenn der Ganzzahlteil größer ist als 1 (oder kleiner -1) ?
Ich bekomme nämlich dieselben Ergebnisse und glaube, dass es daran liegt.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 28. June 2013, 16:08 »
Ich hab davon auch keine Ahnung, aber laut diesen Code ist die Instruktion fscale dafür da den Ganzzahlanteil zu potenzieren.
Dieser Text wird unter jedem Beitrag angezeigt.

Thunder

  • Beiträge: 24
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 29. June 2013, 22:32 »
Ah super, das hat geholfen! :) Jetzt hab ich richtige Ergebnisse, danke!

 

Einloggen