关于0.1+0.2≠0.3的问题

发现问题

啥也不说,我们先看一段python代码的执行情况:
在这里插入图片描述
1+2=3,0.1+0.3=0.4没毛病,但是:0.1+0.2=0.30000000000000004,什么鬼???
在这里插入图片描述
很多老猿估计都清楚是啥情况,但还有些小伙伴可能不太了解,不管怎样,还是要给大家娓娓道来。
我们都知道,在计算机中所有的数据最终都会被转化为0和1进行存储,所以我们需要清楚以下两点问题:

  1. 浮点数如何转化为二进制

  2. 浮点数的二进制如何存储

浮点数如何转化为二进制

首先我们要了解浮点数的二进制表示,有以下两个原则:

  1. 整数部分对2取余然后逆序排列

  2. 小数部分乘2取整数部分,然后顺序排列

接下来我们来看看0.1的二进制表示,由于0.1的整数部分是0,所以直接计算小数部分即可。下面我们来看小数部分的计算,按照“小数部分乘2取整数部分,然后顺序排列”的计算方式:

0.1*2 = 0.2 //整数部分为0,所以小数点后第一位为0

0.2*2 = 0.4 //整数部分为0,所以小数点后第二位为0

0.4*2 = 0.8 //整数部分为0,所以小数点后第三位为0

0.8*2 = 1.6 //整数部分为1,所以小数点后第四位为1

0.6*2 = 1.2 //整数部分为1,所以小数点后第五位为1 (整数部分不在乘2的范围)

0.2*2 = 0.4 //整数部分为0,所以小数点后第6位为0

……

按这种方式计算你会发现,0.1的二进制表示是0.00011001100110011001100110011……0011,0011作为二进制小数的循环数进行无限循环。这是不是就意味着你永远都存不下0.1的二进制小数。所以引出第二个问题:浮点数的二进制如何存储。

浮点数的二进制如何存储

简要介绍下IEEE754浮点格式:它采用科学计数法以底数为2的小数来表示浮点数。单精度浮点数(32位)用1个bit作为符号位表示正数还是负数,用8个bit表示指数,剩下的23个bit用来表示尾数(即小数部分)。此处指数用移码存储,尾数则是原码(没有符号位)。双精度浮点数(64位)最高位第1个bit为用来作为符号位,然后顺下的11个bit来存储指数部分,最后,剩下的52个bit存储尾数部分。
下图为64位浮点数的存储示意图:
在这里插入图片描述

回到最初的问题

在这里插入图片描述
我们回到问题:为什么0.1+0.2=0.30000000000000004?首先声明一点:这不是bug,这是十进制与二进制的转换导致的精度问题!就好比十进制无法精确表示1/3(0.33333333……)一样,二进制也有无法精确表示的值。其次,这个问题出现在很多的编程语言中,如:c/c++、java、js、python。准确的说:采用了IEEE754规范来存储浮点数的任何编程语言都有这个问题。下面我们分析下整个运算过程:

a. 0.1的二进制表示为:

1.1001100110011001100110011001100110011001100110011001 1(0011)+ * 2^-4;

b. 按64bit的存储空间以及IEEE 754 Floating-point采用round to nearest, tie to
even的舍入模式计算,0.1实际存储时的位模式是0-01111111011-1001100110011001100110011001100110011001100110011010;

c. 0.2的二进制表示为 :

1.1001100110011001100110011001100110011001100110011001 1(0011)+ * 2^-3;

d.同样的计算方式,0.2实际存储时的位模式是0-01111111100-1001100110011001100110011001100110011001100110011010;

e. 实际存储的位模式作为操作数进行浮点数加法,得到
0-01111111101-0011001100110011001100110011001100110011001100110100,转换为十进制即为0.30000000000000004。

原来0.30000000000000004是这么来的。借用虎扑名言:我好了!不知道在屏幕前的您“好了吗”?

到文末了,在这里出一道题:1.1+2.2等于多少?您可以用python运行试试看,提前告诉您,结果既不是3.3也不是3.30000000000000004,很有意思哦,试试吧!

欢迎留言讨论,同时有兴趣的朋友可以关注微信公众号:麻辣软硬件,精彩内容不要错过!

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值