将大整数转换为浮点数

3
我将尝试将一个整数转换为浮点数,方法如下(简化版):

int64_t x = -((int64_t)1 << 63);
float y = x;

在64位Windows 7上使用MSVC 2013可以正常工作,但在Ubuntu 14.04 64位上使用gcc 4.8时,x的值为正数。我禁用了所有优化,并在gdb中查看了变量。我甚至尝试直接使用gdb进行评估,以找到问题的原因:

(gdb) print (float)(-((int64_t)1 << 63))
$33 = 9,22337204e+18

(gdb) print (float)(-9223372036854775808)
$39 = 9,22337204e+18

可以看出,即使添加显式转换也无法解决问题。我有点困惑,因为浮点数应该能够容纳更大的数字(绝对值)。如果有影响,sizeof(float) == 4sizeof(size_t) == 8。似乎-2^63这个值是某种魔法限制,因为-2^63+1可以完美转换:
(gdb) print (float)(-((int64_t)1 << 63) + 1)
$44 = -9,22337149e+18
为什么在值小于等于-2^63的转换中会丢失符号?int64_t和float都可以表示值-2^63,并且在其他平台上可以正常工作。

2
(int64_t)1 << 631 左移至符号位,因此是未定义行为。 - Weather Vane
1
@WeatherVane:啊,感谢您指出这一点。现在它可以使用(gdb) print (float)(-(int64_t)((uint64_t)1 << 63)) $48 = -9,22337204e+18 - Andreas Unterweger
1
如果可能的话,在取反之前将其强制转换为浮点数。 2 ^ 63和 - (2 ^ 63)都可以表示为浮点数。 - Patricia Shanahan
嗯...在gdb中可以工作,但在C代码中不行。有没有办法将-(1 << x)转换为浮点数,在运行时x=63? - Andreas Unterweger
@PatriciaShanahan:之前转换为浮点数是关键,谢谢。现在可以使用 (-(float)((uint64_t)1 << 63)) 进行操作了。非常感谢。 - Andreas Unterweger
显示剩余2条评论
2个回答

5

指令 (int64_t)1 << 63 将一个 1 左移至符号位,因此属于未定义行为。

即使左移成功并得到了 0x8000000000000000,这是可以支持的最小(也是负数)值,则通过取反该值:

-((int64_t)1 << 63)

将该值放在正有符号 64 位 int 的范围之外。


3
每个编译器都是绝对正确的,因为这又是未定义行为。 - gnasher729

2
为避免未定义行为,请使用标准函数ldexp将数字乘以2的幂: - ldexp(1.0, 63)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接