js中浮点数运算精度问题
在js中,我们有时会遇到计算,通过加减乘除处理某些业务。那么这时候如果不做任何处理,就会出现如下典型的精度丢失问题。
console.log(0.1 + 0.2) ; // 0.30000000000000004
下面简要分析下原因:
1、Number 类型
js中数字类型只有Number 类型,Number 类型相当于其他强类型语言中的double类型(双精度浮点型),不区分浮点型和整数型。Number 类型有四种进制表示方法,十进制,二进制,八进制和十六进制,这里只涉及到十进制和二进制。
二进制:0B或者0b (数字0和字母B或者小写字母b) ,后接1或者0表示二进制数
十进制:默认直接输入0-9都是十进制数
Number 类型使用 IEEE 754 格式表示整数和浮点值。
2、IEEE 754
64位二进制数表示一个数字,64位 = 1位符号位 + 11位指数位 + 52位小数位
符号位:用来表示数字的正负,-1^符号位数值,0为正数,1为负数
指数位:一般都用科学计数法表示数值大小,但是这里一般都是2进制的科学计数法,表示2的多少次方
小数位:科学计数法前面的数值,IEEE745标准,默认所有的该数值都转为1.xxxxx这种格式,优点是可以省略一位小数位,可以存储更多的数字内容,缺点是丢失精度。大概可以理解为这张图:
3、精度丢失
精度丢失的本质就是浮点数转化为该标准的二进制的过程中出现的丢失
整数转为二进制好理解,这里只介绍小数转二进制,问题出在小数转二进制上。由于也需要转化为指数形式,例如 1/2 = 1 * 2^-1, 1/4 = 1 * 2^-2,所以小数的转化二进制过程是通过判断小数是不是满 1/2,1/4,8/1以此类推,换成数学公式就是乘二取整法
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======取出整数部分10.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.1 => 0.0001 1001 1001 1001…(无限循环)
同理0.2的二进制是0.0011 0011 0011 0011…(无限循环)
转化为二进制后开始准备运算,计算机中的数字都是以二进制存储的,二进制浮点数表示法并不能精确的表示类似0.1这样的简单的数字。
如果要计算 0.1 + 0.2 的结果,计算机会先把 0.1 和 0.2 分别转化成二进制,然后相加,最后再把相加得到的结果转为十进制
但有一些浮点数在转化为二进制时,会出现无限循环 。比如上面的0.1和0.2。
而存储结构中的尾数部分最多只能表示 53 位。为了能表示 0.1,只能模仿十进制进行四舍五入,但二进制只有 0 和 1 , 于是变为 0 舍 1 入 。 因此,0.1和0.2在计算机里的二进制表示形式如下:
0.1 => 0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 101
0.2 => 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 001
用标准计数法表示如下:
0.1 => (−1)0 × 2^4 × (1.1001100110011001100110011001100110011001100110011010)2
0.2 => (−1)0 × 2^3 × (1.1001100110011001100110011001100110011001100110011010)2
最终,“0.1 + 0.2” 在计算机里的计算过程如下:
指数 小数位
-3 0.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 0
-3 + 1.1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001
------------------------------------------------------------------------------------
-3 10.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0111 0
写为标准形式,整数部分化为1:
-2 1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 10
保留有效数字,舍入(10刚好在000与100中间,其舍入取决于前一位的值,0则舍,1则入):
-2 1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100
经过上面的计算过程,0.1 + 0.2 得到的结果也可以表示为:
(−1)0 × 2−2 × (1.0011001100110011001100110011001100110011001100110100)2=>.0.30000000000000004
通过js将这个二进制结果转化为十进制表示:
(-1)0 * 2-2 * (0b10011001100110011001100110011001100110011001100110100 * 2**-52); //0.30000000000000004
因此会出现:
console.log(0.1 + 0.2) ; // 0.30000000000000004
这是一个典型的精度丢失案例,从上面的计算过程可以看出,0.1 和 0.2 在转换为二进制时就发生了一次精度丢失,而对于计算后的二进制又有一次精度丢失 。因此,得到的结果是不准确的。
4、解决办法
考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));
将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1*2)/3。
把浮点数转化为字符串,模拟实际运算的过程。
以上三点代码实现这里就不展示了,大家可以网上了解。
综上,建议使用第三种方案,目前已经有了很多较为成熟的库,我们可以根据自己的需求来选择对应的工具。并且,这些库不仅解决了浮点数的运算精度问题,还支持了大数运算,并且修复了原生toFixed结果不准确的问题。
以上内容有不足之处还请各位大佬指正。
js中浮点数运算精度问题相关推荐
- JS中浮点数运算误差处理
先来个简单的代码片段: > console.log(0.1 + 0.2) > 0.30000000000000004 好奇怪的结果,怎么会是0.30000000000000004呢?难道是 ...
- PHP浮点数运算精度问题
最近有客户反应商城订单金额总是不准确,总是相隔一分钱.检查相关代码逻辑都是正确的,就是运用了四则运算.大概推测问题可能出在浮点计算丢失精度.在<PHP程序员雷雪松的博客>中写过一篇关于JS ...
- 关于Java浮点数运算精度丢失问题
2019独角兽企业重金招聘Python工程师标准>>> 关于Java浮点数运算精度丢失问题 博客分类: java 前几天看了一个朋友的博客,说Java中浮点数运算精度丢失的问题,他给 ...
- js浮点数精度丢失问题及如何解决js中浮点数计算不精准
js浮点数精度丢失问题及如何解决js中浮点数计算不精准 参考文章: (1)js浮点数精度丢失问题及如何解决js中浮点数计算不精准 (2)https://www.cnblogs.com/ranyonsu ...
- JavaScript学习(六十四)—关于JS的浮点数计算精度问题解决方案
JavaScript学习(六十四)-关于JS的浮点数计算精度问题解决方案 您的语言没有中断,它正在执行浮点数学运算.计算机只能本地存储整数,因此它们需要某种表示十进制数字的方式.此表示并不完全准确.这 ...
- 浮点数运算精度丢失的问题
导入 在我们平时编码的过程中,你一定遇到过这样的问题: const a = 0.1; const b = 0.2; console.log(a + b); // 0.30000000000000004 ...
- MATLAB中控制运算精度
Matlab设置计算精度 #原理 MATLAB中控制运算精度 : format long 只能设置显示精度,并不能控制运算精度. 在MATLAB中,控制运算精度一般使用 digits 和 vpa. # ...
- python的浮点数_python中浮点数的精度
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! python中,浮点数运算,经常会碰到如下情况:? 出现上面的情况,主要还是因浮 ...
- MATLAB浮点数运算精度问题
matlab计算题: 而后用matlab进行了一些浮点数计算,但结果都出乎预料: 2+2*eps = 2.000 3 + eps = 3 ...
最新文章
- GPP加密破解工具gpp-decrypt
- weblogic启动方法
- leetcode刷题 66 67
- Java Object有哪些公用方法?
- 往年程序员是怎样过“1024程序员节”的!程序员,今年又准备怎么过?
- 逻辑回归、线性回归直观感受
- 注册表修改大全(浏览文章时可以使用CTRL+F查找)
- 鼠标移上去切换背景色
- Some Sites About .Net
- 产品配件类目税目分类_终于找到了!“税收分类编码大全”,有这一篇就够了!...
- wim linux u盘启动,在U盘启动中安装CDLinux
- ABAP-生成会计凭证
- 点云 数据增强(Data Augmentation):方法与python代码
- Android 使用Navigation 跳转页面时发生crash
- 2022-2027年中国汽油市场规模现状及投资规划建议报告
- 从零开始写一个简单的bootloader(1)
- DirectShow 09 - 音视频捕捉
- [kuanbin带我飞]的专题1---简单搜索
- 开荒手册3——构思一篇小论文
- 使用idea打包war包
热门文章
- 软件工程项目实训08
- 第二轮5G投票即将开启,华为能否战胜高通?
- 记2020年7月5日深圳福田凤凰楼嵌入式/物联网博客-公众号大佬面基聚会
- R语言的for循环等简单运用
- Ubuntu安装宝塔部分展示
- 国家高新技术企业门户与移动全生态开发套件-Zooma!逐浪CMS v8.1.4正式发布
- 图片下划线 html,HTML U下划线标签元素 HTML下划线标签
- python求数列数量积_python中矩阵运算(乘法和数量积)
- Eclipse设置Organize Import
- 把所阅读的文章背景/主题变成白色