For 32-bit int
s, 64-bit int64
s, and IEEE 64-bit double
s, the following trick works (apart from violating aliasing rules and whatnot):
double convert(int x) {
double tricky = 0x1.8p53;
int64 hack = (int64 &)tricky + x;
return (double &)hack - 0x1.8p53;
}
Here I take tricky = 2^53 + 2^52
. The smallest representable change in this value is 1
, meaning the significand is measured in units of 1
. The significand is stored in the low-order 52 bits of a double
. I won't overflow or underflow the significand by adding x
to it (since x
is 32-bit), so hack
is the binary representation of 2^53 + 2^52 + x
as a double
. Subtracting off 2^53 + 2^52
gives me x
, but as a double
.
(What follows, I think, is sorta close to x86-64 assembly code. I don't see why it wouldn't do the right thing, but I haven't tested it. Or even assembled it.)
movsx rax, dword ptr [x]
add rax, [tricky]
mov [hack], rax
fld [hack]
fsub st(0), [tricky]
fstp [answer]