0.1+0.2 等于 0.3 吗?(数字相加结果有无限小数的原因及解决方式)
文章目录
- 0.1+0.2 等于 0.3 吗?
- 0.1+0.2 的计算过程。
- 转成浮点数
- 浮点数相加
- 浮点数转成十进制
- 结果如下所示:
- 答案
- 拓展
- 解决方式
点击打开视频讲解
0.1+0.2 等于 0.3 吗?
前言:去互联网金融或电商行业的公司面试时,一般都会遇类似“ 0.1+0.2 等于 0.3吗?”这道题,对于非科班出身的前端人是一道送命题,有些知道 0.1+0.2 不等于 0.3,但是继续深问为什么,就无法很清晰地回答。
0.1+0.2 的计算过程。
1、十进制转成二进制
在JS内部所有的计算都是以二进制方式计算的。 所以运算 0.1+ 0.2 时要先把 0.1和 0.2 从十进制转成二进制。
0.1转化成二进制的算法:0.1*2=0.2======取出整数部分00.2*2=0.4======取出整数部分00.4*2=0.8======取出整数部分00.8*2=1.6======取出整数部分10.6*2=1.2======取出整数部分1接下来会无限循环0.2*2=0.4======取出整数部分00.4*2=0.8======取出整数部分00.8*2=1.6======取出整数部分10.6*2=1.2======取出整数部分1
所以0.1转化成二进制是:0.0001 1001 1001 1001......0.2转化成二进制的算法:0.2*2=0.4======取出整数部分00.4*2=0.8======取出整数部分00.8*2=1.6======取出整数部分10.6*2=1.2======取出整数部分1接下来会无限循环0.2*2=0.4======取出整数部分00.4*2=0.8======取出整数部分00.8*2=1.6======取出整数部分10.6*2=1.2======取出整数部分1
所以0.2转化成二进制是:0.0011 0011 0011 0011......
这里要注意 0.1 和 0.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… 转成浮点数形式的二进制,转换结果如下图所示:
浮点数相加
浮点数相加时,需要先比较指位数是否一致,如果一致则小数位直接相加,如果不一致,要先把指位数调成一致的,指位数小的向大的调整。
为了行文方便,把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,如下所示:
101100110011001100110011001100110011001100110011001111011001100110011001100110011001100110011001100110100
截掉小数位的最后一位相当把小数点向左移了一位,故指数位要加1,此时的指数是0.2的指数1021 ,加1后变成1021 ,转成二进制为01111111101 ,那么相加后的浮点数如下所示:
浮点数转成十进制
二进制浮点数计算结束后,把结果(二进制的浮点数)转成十进制,其转换公式为
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来解决精度误差,四舍五入。可以用Math.pow来做个简单的封装Math.round(Math.pow(10, m) * number) / Math.pow(10, m),其中number是要四舍五入的数,m是保留几位小数。
若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!!!
0.1+0.2 等于 0.3 吗?(数字相加结果有无限小数的原因及解决方式)相关推荐
- verilog 浮点转定点_浮点数0.1+0.2为何不等于0.3
来自公众号:印记中文 本文由扇贝的前端工程师景国凯撰写,跟随作者一起了解浮点数的计算过程,掌握为何会出现精度丢失的根本原因. 之前简单介绍了二进制下整数的加减乘除基本运算,建议没看过的先去了解一下,这 ...
- input 0.1无法相加_你真的知道0.1+0.2为何不等于0.3吗?
打开chrome控制台,给一个特别简单的输入如下: 0.1 + 0.2 // 0.30000000000000004 复制代码 不知道你有没有吃惊,这么简单的一个计算,无论在js中还是在python中 ...
- 0.1+0.2真不等于0.3?你知道不
先看下代码: <script>console.log(0.1+0.2) </script> 打印出来的值 有什么办法解决呢? bignumber.js 1.引入到项目中: &l ...
- 当x大于时,y等于1;当x等于0时,y等于0;当x小于0时,y等于-1。
#include<stdio.h> int main() {int x,y;scanf("%d",&x);if(x > 0)y = 1;else if(x ...
- JS 0.1+0.2为什么不等于0.3
出现现象 0.1 + 0.2 === 0.3; // false 为什么会这样? 简单地说,number在内存中是以64位二进制存储的,所以0.1 和 0.2 的二进制表示形式是不精确的,所以它们相加 ...
- 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的控制台也是输出这个数 ...
- 实数系的基本定理_初中篇1|知实数-为什么0.9的循环等于1?
(初一下学期)弘毅: 为什么0.9的循环等于1? 我:说来话长,你坐下听我慢慢说. 摘要:1. 该问题的普遍性2. 有理数3. 从有理数到实数4. 真正理解实数-极限与拓扑5. 关于高中及以前的数学- ...
- 如何解决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) ...
- 解决JS中0.1+0.2不等于0.3
console.log(0.1+0.2===0.3)// true or false?? 在正常的数学逻辑思维中,0.1+0.2=0.3这个逻辑是正确的,但是在JavaScript中0.1+0.2!= ...
- 算法-----三数之和等于0
三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件 且不重复的三元组. 注意:答案中不可以包含重 ...
最新文章
- 【hdu】4521 小明序列【LIS变种】【间隔至少为d】
- SQL 2014 in-memory中的storage部分
- 动态库、静态库、运行时库、引入库之间的区别
- Spring Cloud 系列之 Nacos 配置中心
- 创业者谈:畏惧失败,但也要拥抱失败
- 用scikit-learn学习主成分分析(PCA)
- php 的html文件怎么打开,什么是html文件?html格式如何打开?(图)
- html label 两端对齐,如果实现表单的label文字两端对齐
- Linux Redis安装及使用
- 364 页 PyTorch 版《动手学深度学习》分享(全中文,支持 Jupyter 运行)
- 计算机大学毕业好考公务员,哪些大学的毕业生更容易考上公务员?
- linux java keytool_JDK自带的keytool证书工具详解
- 软件工程毕业论文mysql英文翻译_软件工程毕业论文文献翻译中英文对照
- 计算机桌面图标变小了,电脑桌面图标变小了怎么办
- 远程桌面控制计算机,如何远程控制电脑?远程控制别人计算机(2种实用方法)...
- Window系列 (一) — WindowManager 详解
- 写给立志进入网络行业的朋友的一些忠告
- n维立方体角、面、边的个数
- C#入门学习——飞行棋
- 迅为-iMX6ULL开发板上配置AP热点
热门文章
- csu1164 Dominating
- UVa 12304 2D Geometry 110 in 1!(圆的处理)
- 【原创】《矩阵的史诗级玩法》连载十七:用矩阵研究二次贝塞尔曲线和抛物线的关系(上)
- 计步器 c语言,ADXL345单片机计步器程序
- 面向对象:上得厅堂,下得厨房,站起来杀猪,坐下来写书
- vue alert内含有html,vue一步步实现alert功能
- 路由器:什么是软路由,看完本篇文章你就懂了
- android wifi分析 实现原理,android framework wifi 开启原理
- Git报错Kex_exchange_identification
- 论文阅读 之 Person Re-identification in the Wild