Gewusst wie: pow(real, real) in x86
Ich bin auf der Suche nach der Umsetzung von pow(real, real)
in x86-Assembly. Auch ich würde gerne verstehen, wie der Algorithmus funktioniert.
verwenden Sie x87 oder SSE?
glibc-Implementierung der
Ich nehme an, glibc-code ist entweder genauer oder schneller als x87. Vielleicht beides, aber vielleicht nur genauer (richtig aufgerundet zur nächsten). Es muss nicht eine Schleife verwenden, obwohl, und single-stepping durch die Anweisungen, die gibt es nicht das für viele
glibc-Implementierung der
pow()
Funktion ist in sysdeps/ieee754/DZ-64/e_pow.c. Es verwendet einige integer-Prüfung der FP-bit-Muster, und einige FP multipliziert und addiert, aber nicht irgendwelche spezielle x87 Instruktionen. Für x86-64, es kompiliert wird, in __ieee754_pow_sse2()
(mit diesem code das #include-es). Trotzdem, x87 ist nicht der beste Weg, es zu tun auf modernen CPUs.Ich nehme an, glibc-code ist entweder genauer oder schneller als x87. Vielleicht beides, aber vielleicht nur genauer (richtig aufgerundet zur nächsten). Es muss nicht eine Schleife verwenden, obwohl, und single-stepping durch die Anweisungen, die gibt es nicht das für viele
pow(1.175, 33.75)
. FYL2X ist ein sehr langsamer Befehl (~100 Zyklen) auf modernen CPUs, also sollte es nicht schwer sein Sie zu schlagen.InformationsquelleAutor Maciej Ziarko | 2011-01-09
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einfach ausrechnen, wie
2^(y*log2(x))
.Gibt es eine x86-Instruktion FYL2X zu berechnen y*log2(x) und eine x86-Instruktion F2XM1 zu tun Potenzierung. F2XM1 erfordert ein argument in [-1,1] Bereich, so dass Sie würde haben, fügen Sie einige code, der in zwischen zum extrahieren der ganzzahlige Teil und der Rest, potenzieren den Rest verwenden FSCALE zu skalieren, das Ergebnis durch eine geeignete Potenz von 2 ist.
InformationsquelleAutor Eugene Smith
OK, habe ich umgesetzt
power(double a, double b, double * result);
im x86 genauso wie Sie empfohlen.Code: http://pastebin.com/VWfE9CZT
Getan, enthalten.
Sollten Sie
sub esp, 8
zu halten, ausgerichtet zum schieben ebx. Man könnte auch swap tmp und ControlWord, z.B.%define tmp DWORD [ebp-4]
, so ist es ausgerichtet.Es würde viel mehr Sinn, um wieder eine
double
statt einen Ausgang arg, so lassen Sie einfach den Wert inst0
. Oder wenn Sie darauf bestehen, wobei ein Zeiger Last den Zeiger in EAX, ECX oder EDX, so dass Sie nicht haben, um save/restore EBX überhaupt. Außerdem sollten Sie wieder die ursprüngliche Rundung-Modus, wenn Sie fertig sind. (z.B. speichern Sie das original in ein register, dann speichern undfldcw
es). Dies lässt es auf das abschneiden in Richtung null), nicht der Standard, round-to-nearest. efg2.com/Lab/Library/Delphi/MathFunctions/FPUControlWord.Txt.Auch, Rundung auf Ganzzahl, die mit der Faust/fild ist unnötig. Verwenden
frndint
. (fist/fild
kann überlaufen, wennb * log2(a)
hat Größenordnung höher als 2^31, weil Sie nur mit einem dword-vorübergehend!double
können zahlen darzustellen, die außerhalb des Bereichs von +-2^63, also die Rundung, die durch Konvertierung von/nach integer sollte vermieden werden, vor allem, weilfrndint
existiert und ist schneller!)InformationsquelleAutor Maciej Ziarko