g Mit ++ 4.9.2 wenn ichUnsigned 64-Bit-Doppelwandler: warum dieser Algorithmus von g ++
bool int_dbl_com(const unsigned long long x, const double y)
{
return x <= y;
}
kompilieren
dann der Assembler Ausgabe lautet:
testq %rcx, %rcx
js .L2
pxor %xmm0, %xmm0
cvtsi2sdq %rcx, %xmm0
ucomisd %xmm0, %xmm1
setae %al
ret
Der Befehl cvtsi2sdq
unterzeichnet Umwandlung, und die erste Test- und Sprungkombination ist zu prüfen, ob %rcx < 0
. Wenn ja, gehen wir zu L2, und das verstehe ich nicht:
.L2:
movq %rcx, %rax
andl $1, %ecx
pxor %xmm0, %xmm0
shrq %rax
orq %rcx, %rax
cvtsi2sdq %rax, %xmm0
addsd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
setae %al
ret
Naiv Sie %rcx
halbieren könnte, konvertieren zu einem Doppel in %xmm0
, und fügen Sie dann %xmm0
sich den ursprünglichen Wert zurück (Akzeptieren Sie natürlich, dass Sie eine Genauigkeit niedriger Ordnung verloren haben, die von einer 64-Bit-Ganzzahl in eine 64-Bit-Gleitzahl übergeht.
Aber das ist nicht, was der Code tut: Es scheint das niedrigste Bit von %rcx
zu speichern und dann zurück zum Ergebnis. Warum?? Und warum sollten Sie sich die Mühe machen, wenn diese Bits niedriger Ordnung sowieso verloren gehen (oder irre ich mich hier)?
(Der gleiche Algorithmus scheint unabhängig von der Optimierung verwendet werden, ich O3 hier verwendet, um es einfacher zu sehen.)
Großartig! Ich möchte den Link ziehen Sie als wirklich gab eine große Erklärung von _why_ Runde ungerade sein: http://www.exploringbinary.com/gcc-avoids-double-rounding-errors-with-round-to-odd/ –
@MatthewDaws Der gesamte Blog "Exploring Binary" ist großartig. :) –