惊!0.1+0.2还要用电脑算,程序员都是小学没毕业?

如果你问一个小学生 0.1+0.2等于多少,我相信他会毫不犹豫地告诉你等于0.3。但是如果你去问一个程序员,他就会很谨慎地告诉你,稍等一下,然后飞快地在电脑上敲下几行代码:

public class Demo {

public static void main(String[] args) {

System.out.println(0.1 + 0.2);

}

}

这时候你心里肯定在说:”这哥们小学没毕业?这种问题还要用电脑算?“ 就在你即将不屑地转身离开时,电脑上出现了计算结果:

0.30000000000000004

”什么鬼?我读书少你别骗我,一定是电脑坏了!“

 

OK,电脑没有坏,那强大的电脑和聪明绝顶的程序员为什么比不上一个小学生呢?我们来一起分析一下:

首先我们来复习一下义务教育阶段学习的一个重要知识点:科学计数法

把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,n为整数)

我们都知道计算机中的数据都是以二进制形式来表示的,在内存中有两种存储方式:

float(单精度)1位符号位8位指数位23位尾数位

double(双精度)1位符号位11位指数位52位尾数位

首先将十进制0.1转换为二进制,十进制小数转二进制一般采用乘2取整法:

0.1 x 2 = 0.2  整数部分为 0 小数部分继续 x 2

0.2 x 2 = 0.4  整数部分为 0 小数部分继续 x 2

0.4 x 2 = 0.8  整数部分为 0 小数部分继续 x 2

0.8 x 2 = 1.6  整数部分为 1 小数部分继续 x 2

0.6 x 2 = 1.2  整数部分为 1 小数部分继续 x 2

0.2 x 2= 0.4   整数部分为 0 小数部分继续 x 2

...

 

重复计算得到64位二进制小数:

0.0001100110011001100110011001100110011001100110011001100110011001

以二进制科学计数法来表示,也就是a与2的n次幂相乘的形式(1≤|a|<2,n为整数),a就是尾数,n就是指数,即

1. 100110011001100110011001100110011001100110011001100110011001  * 2 ^ -4

先来处理尾数,JAVA浮点数默认为双精度,使用52位存储尾数,由于二进制的科学计数法整数位永远都是1,因此可以直接不存储,截取小数部分前52位为尾数位(0舍1入)

1001100110011001100110011001100110011001100110011010 

再来处理指数,由于指数位为11位,因此指数偏移值为2 ^ 10 -1 = 1023, 指数位实际值 x - 1023 = -4, 得到x为1019,转为二进制1111111011, 高位补0,满11位,得01111111011

正数符号位为0,得到0.1的双精度二进制表示为:

0   01111111011    (1.)1001100110011001100110011001100110011001100110011010

同理,得到0.2的双精度二进制表示为:

0   01111111100    (1.)1001100110011001100110011001100110011001100110011010

在相加之前将0.1的指数调整和0.2的指数相同(即-4调为-3),同时将尾数右移一位得到(0.)11001100110011001100110011001100110011001100110011010,根据0舍1入原则将最后一位0舍去得到

0  01111111100     (0.)1100110011001100110011001100110011001100110011001101 

 

现在可以将尾数相加了:

0.1100110011001100110011001100110011001100110011001101

+ 1.1001100110011001100110011001100110011001100110011010


10.0110011001100110011001100110011001100110011001100111

尾数计算结果规格化处理,向右移一位(最后一位1舍去),同时将指数+1得到双精度计算结果

0   01111111101 (1.) 0011001100110011001100110011001100110011001100110011(1)

由于右规了一位1,因此需要进行+1预算

0011001100110011001100110011001100110011001100110011

+  0000000000000000000000000000000000000000000000000001


0011001100110011001100110011001100110011001100110100

最终得到的结果为:

0 01111111101 0011001100110011001100110011001100110011001100110100 

转为10进制为:

 

0.30000000000000004440892098500626

这就是0.1+0.2不等于0.3的原因所在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值