Java里float在乘以5之后为啥会出现很多小数

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。作者:慕容小匹夫链接:没有神话,聊聊decimal的“障眼法” - Runtime - 专栏来源:我们先来看一看一个十进制的小数0.1为何不能被二进制浮点数准确的表示出来吧。
如同在十进制中,1/3是无法被准确表示的,如果我们要将1/3转换成十进制小数的形式则是:
1/3 = 0.3333333....(3循环)
同理,十进制小数0.1也是无法被二进制小数准确表示,如果我们要将十进制的0.1转换为二进制小数则是:
0.1 = 0.00011001100....(1100循环)
我们可以看到,如果要将十进制的0.1转换为二进制小数,则会出现1100循环的状况。因此根据我在上一篇文章中提到过的IEEE 754标准以及在上一篇文章中最后所举的一个例子,我们首先将0.00011001100....进行逻辑移位,使之小数点左边第一位是1。那么结果是1.10011001100...,共移动了4位,因此指数相应的应该是-4。所以,表示十进制0.1的float二进制浮点数的结果如下:
符号位:0(表示正数)
指数部分:01111011(01111011换算成十进制是123,因为要减去-127故结果为-4)
尾数部分:10011001100110011001101(即通过移位之后,舍掉小数点左侧的1,留下的小数部分,保留23位)
那么这个用来“表示”十进制小数0.1的float二进制浮点数如果换算成十进制数到底是多少呢?它和0.1到底有多大的误差呢?下面我们就来换算一下:
指数部分:2^(-4) = 1/16
尾数部分:1 + 1/2 + 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536 + 1/131072 + 1/1048576 + 1/2097152 + 1/8388608 = 1.60000002384185791015625 (在换算成float时会把小数点左侧的1省略,这里需要再次加回来)
那么,换算之后实际的十进制数便是:1.60000002384185791015625 * 1/16 = 0.100000001490116119384765625
所以我们可以看到,二进制浮点数并不能准确的表示0.1这个十进制小数,它使用了0.100000001490116119384765625来代替0.1。
【Java里float在乘以5之后为啥会出现很多小数】 这便是直接使用二进制来表示小数的方式,很有可能会产生误差。

■网友
因为你觉得十进制是理所当然的,但是计算机觉得二进制是理所当然的。你看a是1.03,计算机看a是1.01001100110011001100……。不明白的回去罚站。
■网友
1.03用二进制表示是个无穷小数
■网友
想一下0.1在二进制里是多少位
■网友
因为float 是浮点型
■网友
Kenneth的答案说得准确,但是比较抽像。额外描述一下。首先,float类型是浮点型。 不是定点小数类型(一般编程语言不会蛋疼地提供定点小数).简单来说:float类型的内存表示,根据IEEE标准,分为三部分,符号位、指数、尾数。但是,指数是以2为底的。当你乘以4的时候,只是对指数部分的一个运算。并没有修改尾数。 乘以5的时候,指数和尾数都发生了变化,拼凑出最终的结果。而这个过程只可能是近似的
■网友
我记得乘以2没问题,超过3出现了?


    推荐阅读