目录

一、0.1+0.2的计算过程

1.十进制转成二进制

2.转成浮点数

3.浮点数相加

4.浮点数转成十进制

二、答案

三、拓展


一、0.1+0.2的计算过程

1.十进制转成二进制

在JS内部所有的计算都是以二进制方式计算的。 所以运算 0.1+ 0.2 时要先把 0.1和 0.2 从十进制转成二进制。

  • 0.1转化成二进制的算法:
    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.4*2=0.8======取出整数部分0
    0.8*2=1.6======取出整数部分1
    0.6*2=1.2======取出整数部分1
    所以0.1转化成二进制是:0.0001 1001 1001 1001......
  • 0.2转化成二进制的算法:
    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.4*2=0.8======取出整数部分0
    0.8*2=1.6======取出整数部分1
    0.6*2=1.2======取出整数部分1
    所以0.2转化成二进制是:0.0011 0011 0011 0011......

这里要注意 0.1 和 0.2 转成的二进制是无穷的。另外在现代浏览器中是用浮点数形式的二进制来存储二进制,所以还要把上面所转化的二进制转成浮点数形式的二进制。

2.转成浮点数

浮点数分为单精度对应32位操作系统和双精度对应64位操作系统。目前的操作系统大多是64位操作系统,故这里只解释一下二进制如何转成双精度浮点数的二进制。

双精度浮点数用1位表示符号位,11位表示指数位,52位表示小数位,如下图所示:

  • 符号位:正数为0,负数为1;
  • 指数位:阶数+偏移量,阶数是:

,e为阶码的位数。偏移量是把小数点移动到整数位只有1时移动的位数,正数表示向左移,负数表示向右移;

  • 小数位:即二进制小数点后面的数。

接下来把0.1转成的二进制0.0001100110011001 ......转成浮点数形式的二进制。

  • 先要把小数点移动到整数位只有1,要向右移动4位,故偏移量为−4,通过指位数的计算公式

,把1019转成二进制为1111111011,不够11位要补零,最终得出指位数为01111111011;

  • 小数位为100110011001...... ,因为小数位只能保留52位,第53位为1故进1。

转换结果如下图所示:

同理,再把 0.2 转成的二进制0.0011 0011 0011 0011...... 转成浮点数形式的二进制,转换结果如下图所示:

3.浮点数相加

浮点数相加时,需要先比较指位数是否一致,如果一致则小数位直接相加,如果不一致,要先把指位数调成一致的,指位数小的向大的调整。

为了行文方便,把0.1转成的浮点数称为为0.1,把0.2转成的浮点数称为0.2。

0.1的指数位是1019 ,0.2的指数位是1020 。故要把0.1的指数位加1,即把0.1的小数点向左移动1位,另外浮点数的整数位固定为1,过程如下所示

1.1001100110011001100110011001100110011001100110011010   原先
0.11001100110011001100110011001100110011001100110011010  移动后
0.1100110011001100110011001100110011001100110011001101   将小数的第53位舍去,因为为0故不需进1

导致0.1的小数位变成如下所示:

现在0.1和0.2的指数位相同了,把小数位直接相加。

    1100110011001100110011001100110011001100110011001101 0.1的小数位
+   1001100110011001100110011001100110011001100110011010 0.2的小数位
=  10110011001100110011001100110011001100110011001100111

会发现现在的小数位多出了一位,超出了52位,故要把小数位最后一位截掉,小数位最后一位是1,故要进1,如下所示:

10110011001100110011001100110011001100110011001100111
1011001100110011001100110011001100110011001100110100

截掉小数位的最后一位相当把小数点向左移了一位,故指数位要加1,此时的指数是0.2的指数1021 ,加1后变成1021 ,转成二进制为01111111101 ,那么相加后的浮点数如下所示:

4.浮点数转成十进制

二进制浮点数计算结束后,把结果(二进制的浮点数)转成十进制,其转换公式为

,s是符号位为0或1,e为浮点数指数位转成十进制的值,i表示小数位从左到右的位数,第一位 i=1 ,

表示每一位的值为0或1。

那么按着公式把二进制的浮点数转成十进制:

结果如下所示:

0.3000000000000000444089209850062616169452667236328125

由于精度问题,只取到0.30000000000000004。

二、答案

0.1+0.2 不等于 0.3 ,因为在 0.1+0.2 的计算过程中发生了两次精度丢失。第一次是在 0.1 和 0.2 转成双精度二进制浮点数时,由于二进制浮点数的小数位只能存储52位,导致小数点后第53位的数要进行为1则进1为0则舍去的操作,从而造成一次精度丢失。第二次在 0.1 和 0.2 转成二进制浮点数后,二进制浮点数相加的过程中,小数位相加导致小数位多出了一位,又要让第53位的数进行为1则进1为0则舍去的操作,又造成一次精度丢失。最终导致 0.1+0.2 不等于0.3 。

三、拓展

0.1+0.2 不等于 0.3 会引起那些BUG ?

会引起统计页面展示错乱的BUG,还有 300.01 优惠300 元后,支付金额不足0.01 元等类似的BUG。

怎么解决 0.1+0.2 不等于 0.3 ?

可以用Math.js数学计算库来解决,或者用toFixed()给计算结果四舍五入,但是toFixed()在chrome或者火狐浏览器下四舍五入也有精度误差。可以用Math.round来解决精度误差,比如要把 2.55 四舍五入保留 1 位小数,先把 2.55∗10 得到 25.5 ,再用Math.round取整25.5 ,会得到25,再把 25÷10 得到 2.5 ,就这样间接实现了四舍五入。可以用Math.pow来做个简单的封装Math.round(Math.pow(10, m) * number) / Math.pow(10, m),其中number是要四舍五入的数,m是保留几位小数。

0.1+0.2 为什么不等于0.3相关推荐

  1. 判断一个doule等于0的正确方法

    doule进行数学运算时会出现精度问题,判断double是否等于0是不能用"d==0" 要用下面的方法: public static void main(String[] args ...

  2. 【问题思考总结】拉格朗日法的条件极值中的λ可以等于0吗(三种方法)

    问题 在做这道题的时候,我在对变量消元的时候,直接放弃了λ=0的情况,原因很简单,这个λ=0不是就是无条件极值了嘛,怎么可能呢?然而经过查阅资料和思考发现,并不是这样.于是在前人的基础上通过比较无条件 ...

  3. 算法-----三数之和等于0

    三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件 且不重复的三元组. 注意:答案中不可以包含重 ...

  4. python0.1+0.2不等于0.3_为什么0.1 + 0.2不等于0.3?

    原标题:为什么0.1 + 0.2不等于0.3? 0.1 + 0.2不等于0.3这是一个普遍的问题,例如在JS控制台输入将得到0.30000000000000004 在python的控制台也是输出这个数 ...

  5. 有小数点是什么类型_为什么0.1+0.2不等于0.3?原来编程语言是这么算的……

    打开你的 Python,输入「0.1+0.2=」,结果是多少?0.30000000000000004 对不对?为什么结果不是 0.3?本文作者给出了详细的解释. 选自Medium,作者:Parul M ...

  6. Java黑皮书课后题第2章:2.3(将英尺转化为米)编写程序,读入英尺数,将其转换为米数并显示结果。1英尺等于0.305米

    2.3(将英尺转化为米)编写程序,读入英尺数,将其转换为米数并显示结果.1英尺等于0.305米 题目 题目描述 破题 代码块 方法评价 修改日志 题目 题目描述 2.3(将英尺转化为米)编写程序,读入 ...

  7. 进程P1、P2、P3、P4和P5的前趋图如下图所示。若用PV操作控制进程P1~P5并发执行的过程,则需要设置6个信号S1、S2、S3、S4,且信号量S1~S4的初值都等于0。下图中a和b处应分别填写(

    进程P1.P2.P3.P4和P5的前趋图如下图所示.若用PV操作控制进程P1-P5并发执行的过程,则需要设置6个信号S1.S2.S3.S4,且信号量S1-S4的初值都等于0.下图中a和b处应分别填写( ...

  8. 如何解决JavaScript中0.1+0.2不等于0.3

    原文转载自:https://www.cnblogs.com/weshare/archive/2018/02/20/8455470.html >console.log(0.1+0.2===0.3) ...

  9. matlab if m不等于0,matlab问题clearfor a=0.1:0.1:50for b=0.1:0.1:20for m=0.1:0.1:5

    来源:学生作业帮 编辑:作业帮 分类:综合作业 时间:2021/03/23 06:16:09 matlab问题 clear for a=0.1:0.1:50 for b=0.1:0.1:20 for ...

  10. 求两个数字的乘积,如果大于0,说明两个数字同号,如果小于0,说明两个数字异号,如果等于0,说明其中一个是0

    学了java基础东西,就写了这个编程,求两个数字的乘积,如果大于0,说明两个数字同号,如果小于0,说明两个数字异号,如果等于0,说明其中一个是0 首先程序要求我们输入两个数字,我就用了Scanner来 ...

最新文章

  1. [原]android2.3如何使用SharedPreferences存储字符串集合类型的元素
  2. java锁方法和锁代码块_java的同步方法和同步代码块,对象锁,类锁区别
  3. 20145212 《信息安全系统设计基础》第2周学习总结
  4. 智能电能计量管理系统
  5. 使用Flutter开发一个仿微信飞机大战游戏
  6. 智能随机分组系统(代码带备注)
  7. 数字化时代,银行如何建设管理小程序平台促进线上金融业务发展?
  8. Vue中router-link路由跳转以及传参方式
  9. js对象嵌套数组_使用角管过滤嵌套数组和对象的数组并突出显示结果
  10. Pollard-Rho Algorithm简述
  11. 微信公众号支付、支付查询、退款、退款查询、转账到零钱银行卡、转账查询接口整合(V2)
  12. python节日贺卡图片大全_简单漂亮三年级新年贺卡图片大全
  13. cmd sqlplus远程连接_sqlplus连接远程数据库
  14. Unity XR初始化设置
  15. 【无标题】STM32F767串口空闲中断+DMA实现不定帧长度的接收
  16. 人工智能机器人网站合集
  17. 三菱fx3u PLC 通讯设置
  18. 廿柒- 客制化爬虫以及爬虫调参
  19. 从 IT 时代到 DT 时代的转型
  20. 使用matlab求离散系统的频率响应分析和零、极点分布

热门文章

  1. python脚本报错-qt.qpa.plugin: Could not load the Qt platform plugin “xcb“
  2. 【Python-Numpy】numpy.random.binomial()的解析与使用
  3. 【基础】格林尼治时间转化
  4. ffmpeg生成透明背景视频
  5. php处理excel里面的重复数据,表格中删除重复项怎么操作
  6. incre在c语言,longest incresing sequence
  7. 用Python实现中文编程
  8. Android修行手册-看看Button都有哪些属性?
  9. 对指定网站渗透的一些总结
  10. The POODLE attack (SSLv3 supported) 漏洞修复