Utilizzando g ++ 4.9.2 se compilosenza segno a 64 bit a doppia conversione: il motivo per cui questo algoritmo da g ++
bool int_dbl_com(const unsigned long long x, const double y)
{
return x <= y;
}
allora l'uscita assembler è:
testq %rcx, %rcx
js .L2
pxor %xmm0, %xmm0
cvtsi2sdq %rcx, %xmm0
ucomisd %xmm0, %xmm1
setae %al
ret
Il comando cvtsi2sdq
è firmato Conversione e la prima combinazione di test e salto è per verificare se %rcx < 0
. Se è così, andiamo a L2, e questo non capisco:
.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
Ingenuamente, si potrebbe dimezzare %rcx
, convertire in doppio in %xmm0
, e quindi aggiungere %xmm0
a se stesso per tornare al valore originale (accettando, ovviamente, di aver perso una certa precisione di ordine basso passando da un intero a 64 bit a un float a 64 bit).
Ma questo non è ciò che fa il codice: sembra salvare il bit di ordine più basso di %rcx
e restituirlo al risultato. Perché?? E perché preoccuparsi quando questi bit di basso ordine andranno persi lo stesso (o sbaglio qui)?
(Lo stesso algoritmo sembra essere utilizzato a prescindere dalla ottimizzazione; ho usato -O3 qui per rendere più facile da vedere.)
Grande! Voglio tirare fuori il link che hai dato come una grande spiegazione di _why_ round to odd: http://www.exploringbinary.com/gcc-avoids-double-rounding-errors-with-round-to-odd/ –
@MatthewDaws L'intero blog "Exploring Binary" è fantastico. :) –