在浏览器调试窗口中输入下面两段代码,会发现一个因吹斯挺的现象:
console.log(0.1+0.2===0.3) // false console.log(1.1+0.2===1.3) // true 12
明明都是浮点数的加法,为什么表现出来的效果不一样呢?让我们一步步来揭晓谜底。
首先我们需要知道十进制是怎么转为二进制的,下面以 6.1 为例来进行说明。
整数部分转为二进制如下图所示:
6 / 2 = 3...0 => 0 3 / 2 = 1...1 => 1 1 / 2 = 0...1 => 1 6 => 110 12345
也就是不断的将商除以二得到余数,直到商为0。
小数部分转为二进制如下图所示:
0.1 * 2 = 0.2 => 0 0.2 * 2 = 0.4 => 0 0.4 * 2 = 0.8 => 0 0.8 * 2 = 1.6 => 1 0.6 * 2 = 1.2 => 1 0.2 * 2 = 0.4 => 0 … 0.1 => 000110011001100110011001100110011001100110011001100110011... 12345678910
不断的乘以二然后拿掉整数部分,直到积为0。
结合两部分,得到:
110.00011001100110011001100110011001100110011001100110011
转化为科学计数法:
1.1000011001100110011001100110011001100110011001100110011×2^(2)
双精度浮点数在计算机中存储原理如下图所示:
其中,sign 为 0 表示正数,为 1 表示负数,exponent 表示科学计数法中的指数部分,加上一个偏移值 1023,fraction 表示小数点后的部分,整数部分永远为 1,计算机不存储,但是运算的时候会加上。
下面推导下 6.1 的表示方法:
sign: 0
exponent: 2 + 1023 => 10000000001
fraction: 1000011001 1001100110 0110011001 1001100110 0110011001 10 011 (只能保留52位,多余部分向偶舍入)
=> 1000011001 1001100110 0110011001 1001100110 0110011001 10
其中,向偶舍入可参考浮点数向偶数舍入的问题
知道了浮点数的表示方法,下面我们来看看0.1+0.2的运算过程(方括号表示实际不存储的整数部分):
0.1 => 0 01111111011[1]1001100110011001100110011001100110011001100110011010 + 0.2 => 0 01111111100[1]1001100110011001100110011001100110011001100110011010 1. 对齐指数,小的往大的对齐。所以 0.1 指数部分加一,小数点需要往左移一位,超出部分向偶舍入 0.1 => 0 01111111100[0]1100110011001100110011001100110011001100110011001101 0 0.1 => 0 01111111100[0]1100110011001100110011001100110011001100110011001101 2. 小数部分相加 0.1 => 0 01111111100[0]1100110011001100110011001100110011001100110011001101 + 0.2 => 0 01111111100[1]1001100110011001100110011001100110011001100110011010 Res => [10]0110011001100110011001100110011001100110011001100111 3. 小数部分相加的结果超出了52位,小数点要左移一位,多余部分要向偶舍入 Res => 0 01111111101[1]0011001100110011001100110011001100110011001100110011 1 Res => 0 01111111101[1]0011001100110011001100110011001100110011001100110100 4. 推导 0.3 的表示 0.3 => 0 01111111101[1]0011001100110011001100110011001100110011001100110011
123456789101112131415161718192021显然,小数部分最后四位是不相等的,并且通过对比我们可以知道 0.1+0.2 其实是大于 0.3 的。
下面继续推导 1.1+0.2 的运算过程:
1.1 => 0 01111111111[1]0001100110011001100110011001100110011001100110011010 + 0.2 => 0 01111111100[1]1001100110011001100110011001100110011001100110011010 1. 对齐指数,小的往大的对齐。所以 0.2 指数部分加三,小数点需要往左移三位,超出部分向偶舍入 0.2 => 0 01111111111[0]0011001100110011001100110011001100110011001100110011 010 0.2 => 0 01111111111[0]0011001100110011001100110011001100110011001100110011 2. 小数部分相加 1.1 => 0 01111111111[1]0001100110011001100110011001100110011001100110011010 + 0.2 => 0 01111111111[0]0011001100110011001100110011001100110011001100110011 Res => 0 01111111111[1]0100110011001100110011001100110011001100110011001101 3. 推导 1.3 的表示 1.3 => 0 01111111111[1]0100110011001100110011001100110011001100110011001101
1234567891011121314151617经过对比发现,两者确实是相等的。
可以再提供一个例子吗?
通过观察我们发现,造成不相等的原因是因为小数部分超过52位长度的时候有向偶进位的过程,所以我们只要绕过这个过程就好了。比如,我们对 0.1+0.2 稍加改造,变成这样:
0 01111111011[1]0000000000000000000000000000000000000000000000000000 + 0 01111111100[1]0000000000000000000000000000000000000000000000000000 => 0 01111111100[0]1000000000000000000000000000000000000000000000000000 0 + 0 01111111100[1]0000000000000000000000000000000000000000000000000000 => 0 01111111100[0]1000000000000000000000000000000000000000000000000000 + 0 01111111100[1]0000000000000000000000000000000000000000000000000000 = 0 01111111100[1]1000000000000000000000000000000000000000000000000000
1234567891011121314151617即 0.0625+0.125。
更一般的,我们有 2(-m) + 2(-n)。
或者使用Math.add(0.1,0.2)
相关知识
为什么 0.1 + 0.2 != 0.3
机器学习sk
利用Numpy进行鸢尾花数据集分析
【深度学习】实验02 鸢尾花数据集分析
Python机器学习基础教程——1.7第一个应用:鸢尾花分类——学习笔记
Jupiter Notebook:IRIS 数据集/鸢尾花数据集
使用机器学习按品种对鸢尾花进行分类
决策树分类器(保姆级教学) 定义+特性+原理及公式+鸢尾花分类经典问题示例(完整Python代码带详细注释、保姆级分部代码解释及结果说明、决策树可视化及解释)
花木秋季咋施肥用料呢?
农民施肥量计算公式.docx 全文免费
网址: 也许你知道 0.1 + 0.2 === 0.3 为 false,但是 1.1 + 0.2 === 1.3 呢? https://m.huajiangbk.com/newsview1101282.html
上一篇: python3 tesserac |
下一篇: keras笔记(3) |