微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么某些整数的双重转换浮点数和返回整数不保持等于其原始数字,而有些呢?

如何解决为什么某些整数的双重转换浮点数和返回整数不保持等于其原始数字,而有些呢?

我有两个整数变量:

int i1 = 0xdeadbeefint i2 = 0xffffbeef

(分别为11011110101011011011111011101111 or 37359285591111111111111111110111110111011111 or 4294950639)。


(int) (float) i1 == i1 评估为假,而 (int) (float) i2 == i2 评估为真。

这是为什么?在这个系统中,intsfloats 都存储在 4 个字节中。

解决方法

这是因为 float 的精度远低于 int,它无法存储所有可能的 int 值而不会对它们造成一些损害。有时这种伤害只会使您的值四舍五入,有时您的四舍五入值正好匹配。

A 32-bit float 只能存储 24 个“有效数位”或数字数据。其他位是为指数、NaN 标记、无穷大等保留的,它们会占用剩余的存储空间。

double 确实具有所需的精度,因为它通常是可以存储 53 位数字数据数据的 64 位表示。

,

正在进行大量转化。

int i1 = 0xdeadbeef; int i2 = 0xffffbeef 导致实现定义转换,因为常量超出了 int 范围。在这里,它们被“包裹”。

i2 是一个小值(15 个有效位),可以精确地表示为 float

i1 不是。 i1 有 30 个有效位,比 float 的 24 个多 6 个。那些较低的 6 不是 0,因此 (float) i1 结果是一个四舍五入值。

int main() {
  int i1 = 0xdeadbeef;
  int i2 = 0xffffbeef;
  printf("%d\n",(int) (float) i1 == i1);
  printf("%d\n",(int) (float) i2 == i2);
  printf("%u %10d %17f %10d\n",0xdeadbeef,i1,(float) i1,(int) (float) i1);
  printf("%u %10d %17f %10d\n",0xffffbeef,i2,(float) i2,(int) (float) i2);
}

输出

0
1
3735928559 -559038737 -559038720.000000 -559038720
4294950639     -16657     -16657.000000     -16657
,

C 实现通常使用 32 位 int,而 0xdeadbeef 不适合 32 位(一个符号位和 32 个值位)。使用 i1 初始化 0xdeadbeef 会导致转换为 int。这种转换是实现定义的。例如,GCC 将其定义为对模 232 进行包装,这种情况并不少见。

所以 int i1 = 0xdeadbeef;i1 初始化为 deadbeef16 − 232 = 3735928559 − 232 = −559038737 = −2152411116。正如您从“-21524111”中的 8 个十六进制数字中看到的那样,该数字从其前导 1 位到其尾随 1 位跨越 30 位(包括 8 位数字中的 32 位,但前两位为零)。 float 常用的格式,IEEE-754 binary32,其有效数只有 24 位。任何有效位超过 24 位的数字都不适合该格式,并且在转换为此 float 格式时将被四舍五入。所以i1 != (int) (float) i1

相反,int i12 = 0xffffbeef;i2 初始化为 ffffbeef16 − 232 = 4294950639 − 232 = −16657 = −411116。这跨越 15 位(4 位中有 16 位,但第一个是零)。因此它适合 float 有效数的 24 位,并且其值在转换为 float 时不会改变。所以i2 == (int) (float) i2

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。