为什么从整型转换为浮点型时会四舍五入?

6
我正在阅读CS:APP,关于强制类型转换,它说当从int转换为float时,数字不能溢出,但可能会四舍五入。这让我感到奇怪,因为我不知道有什么需要四舍五入的,所以我尝试了一下。我认为这只会发生在非常大的整数(接近INT_MAX / INT_MIN)的情况下,但是在约一亿左右的值处也会发生舍入(不确定具体值在哪里)。为什么会这样呢?float的范围远远超过int。有人可能会说浮点数无法被精确表示,但是当从int转换为double时,其值不会改变。 double比float具有更大的范围和精度的优势。但是float仍然具有足够的范围来“封装”整数,并且精度实际上并不重要,因为整数没有小数位(全为0),或者我想错了吗?

这是我得到的一些输出(代码在这里:http://pastebin.com/K3E3A6Ni):

FLT_MAX = 340282346638528859811704183484516925440.000000  
INT_MAX     = 2147483647  
(float)INT_MAX = 2147483648.000000  
(double)INT_MAX = 2147483647.000000  
INT_MIN     = -2147483648  
(float)INT_MIN = -2147483648.000000  

====other values close to INT_MIN INT_MAX====  
INT_MAX-1     = 2147483646  
(float)INT_MAX-1 = 2147483648.000000  
INT_MIN+1     = -2147483647  
(float)INT_MIN+1 = -2147483648.000000  
INT_MAX-2      = 2147483645  
(float)INT_MAX-2  = 2147483648.000000  
INT_MAX-10     = 2147483637  
(float)INT_MAX-10 = 2147483648.000000  
INT_MAX-100         = 2147483547  
(float)INT_MAX-100  = 2147483520.000000  
INT_MAX-1000         = 2147482647  
(float)INT_MAX-1000 = 2147482624.000000  

(float)1.234.567.809 = 1234567808.000000  
(float)1.234.567.800 = 1234567808.000000  
(float)1.000.000.005 = 1000000000.000000  
(float)800.000.003   = 800000000.000000  
(float)500.000.007   = 500000000.000000  
(float)100.000.009   = 100000008.000000  

1
有趣的事实:2147483647.0f == 2147483648.0f - dmg
@dmg 这个有趣的事实不是取决于舍入模式吗? - chux - Reinstate Monica
2
浮点数通过否定证明了上帝的存在,因为它们显然是撒旦的杰作。 :-) - Bob Jarvis - Слава Україні
不开玩笑地说,浮点数之父和其他人设计了一个强大、高效、长期稳定的浮点数方案。 - chux - Reinstate Monica
2个回答

11
我假设您所说的float是指32位IEEE-754二进制浮点值,double是指64位IEEE-754二进制浮点值,int是指32位整数。

为什么会这样呢?float的范围远远超过了int

是的,但是float精度只有7-9个小数位。更具体地说,有效数字只有24位宽……因此,如果您尝试将32位信息存储在其中,您将会遇到问题。

但是,从int转换为double时,值不会改变

当然不会,因为double具有53位的有效数字——足够容纳32位整数!

换个角度来看,连续的int之间的差距始终为1……而连续的float值之间的差距开始非常小……但随着值的大小增加而增加。在达到int的限制之前,它就已经超过了"大于2"的阈值……因此你会发现并不是每个int都可以被精确表示。

再换一个角度,您可以简单地使用鸽巢原理……即使忽略NaN值,也最多只有2的32次方个float值,其中至少一个不是int的精确值——例如0.5。有2的32次方个int值,因此至少有一个int值没有精确的float表示方式。


我以前不知道鸽笼原理,但这就是我用通俗易懂的方式解释为什么并非所有整数都可以用浮点数表示的原因。 - bolov
我一直认为精度是指小数点后的位数。例如,float 可能有 6 位,而 double 可能有 15 位。那么精度为 7-9 个小数位到底意味着什么? - Beko
@Beko:这意味着 二进制 浮点数的精度有点难以确定,特别是当规范化发挥作用时。基本上,如果你在使用 float 时依赖于超过 7 个小数位,你会遇到麻烦。 - Jon Skeet

7
一个典型的使用32位IEEE-754表示的float类型仅有24位用于尾数,这样只能保留约7个十进制数字的精度。因此,一旦达到百万级别(2的24次方≈1600万),就会出现四舍五入的情况。
(对于double类型,尾数有53位,2的53次方≈9×10的15次方。)

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