Veja este trecho:
int main() {
double v = 1.1;
return v == 1.1;
}
Em compilações de 32 bits, este programa retorna 0, se -fexcess-precision=standard
for especificado. Sem ele, o programa retorna 1.
Por que há uma diferença? Olhando para o código assembly ( godbolt ), parece que com -fexcess-precision=standard
, o gcc usa 1.1
como uma long double
constante (ele carrega a constante como TBYTE
). Por que ele faz isso?
Primeiro pensei que fosse um bug, mas encontrei este comentário de bug do gcc , parece que esse comportamento é intencional, ou pelo menos não é inesperado.
Isso é um problema de QoI? Eu entendo que a comparação é executada usando long double
precisão, mas ainda assim, my 1.1
não é um long double
literal. O estranho é que se eu lançar o 1.1
at na comparação to double
(que já é um double
), o problema desaparece.
(Outra coisa estranha é que o GCC faz o carregamento e a comparação duas vezes, veja as fucomip
instruções duplas. Mas ele faz isso mesmo no modo de 64 bits. Entendo que no meu link godbolt, a otimização está desativada, mas ainda assim, há apenas uma comparação no meu código, por que o GCC compara duas vezes?)
Aqui está o código asm, sem -fexcess-precision=standard
:
main:
push ebp
mov ebp, esp
and esp, -8
sub esp, 16
fld QWORD PTR .LC0
fstp QWORD PTR [esp+8]
fld QWORD PTR [esp+8]
fld QWORD PTR .LC0
fucomip st, st(1)
fstp st(0)
setnp al
mov edx, 0
fld QWORD PTR [esp+8]
fld QWORD PTR .LC0
fucomip st, st(1)
fstp st(0)
cmovne eax, edx
movzx eax, al
leave
ret
.LC0:
.long -1717986918
.long 1072798105
E aqui está:
main:
push ebp
mov ebp, esp
and esp, -8
sub esp, 16
fld QWORD PTR .LC0
fstp QWORD PTR [esp+8]
fld QWORD PTR [esp+8]
fld TBYTE PTR .LC1
fucomip st, st(1)
setnp al
mov edx, 0
fld TBYTE PTR .LC1
fucomip st, st(1)
fstp st(0)
cmovne eax, edx
movzx eax, al
leave
ret
.LC0:
.long -1717986918
.long 1072798105
.LC1:
.long -858993459
.long -1932735284
.long 16383