内容简介:先看如下计算的输出:显然是0.3。但是在javascript中,结果是什么呢?这是程序语言在数值计算中很容易出现的精度问题,如下图饿了么账单页金额显示。
先看如下计算的输出:
0.1 + 0.2
显然是0.3。但是在javascript中,结果是什么呢?
0.30000000000000004
这是程序语言在数值计算中很容易出现的精度问题,如下图饿了么账单页金额显示。
问题产生的原因
先来看对Number类型数值二进制的表示,由3部分组成:
符号位 * 指数位 * 尾数位
由于js采用64位双精度浮点数编码,实际存储时为了节省空间,采用科学计数法表示,其二进制构成如下:
符号位占1位,指数位占11位,尾数占52位。
问题分解
0.1的二进制表示为:
0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 ...
其科学计数法表示为:
1.1001... * 2^-4
其中指数位采用偏置码处理,-4即为:01111111011。简单介绍下:
双精度采用的偏置码为1023, 比如指数位:01111111011,其值为1019, 1019 - 1023 = -4
由于尾数位仅为52位,因此需要截取前52位,并且如若第53位为1则进1,反之舍去,因此0.1的尾数位截取后为:
//10011001 10011001 1001100 110011001 10011001 10011001 10011001... //由于53位为1,进1,即为: 10011001 10011001 10011001 10011001 10011001 10011001 1010
可以看到0.1的值其实已经不准确了,由于进1操作,导致较原值偏大。其对应的二进制存储表示如下:
有的童鞋可能注意到了,尾数位存储的是小数部分,这是因为规格化后的值通式为1.x,因此可以略去1,节省了一个bit位空间。
同理0.2的二进制如下:
0.001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001...
科学计数法处理后的二进制存储为:
至此,已经清楚了javascript对数值的存储方式。
进制转换网址参见:http://www.binaryconvert.com/。
再看0.3的二进制表示:
0.010011001100110011001100110011001100110011001100110011...
使用科学计数法表示后存储为:
而计算机在处理0.1+0.2时(上面已经知道了其分别对应的二进制存储方式),需要通过对阶、尾数求和、规格化、舍入等操作(这里不再赘述),最终得到:
0.010011001100110011001100110011001100110011001100110100 //转为10进制即为:0.30000000000000004
可以知道,计算机在进行浮点数加减运算时,包括对阶、规格化过程都可能产生精度误差,核心还是因为尾数位的位数有限,0舍 1进 导入的误差。
如何在开发中避免此类问题?
1. 取固定精度
有的童鞋可能会采用toFixed()获取固定精度,如下
(0.1+0.2).toFixed(1) = 0.3;
对于精度要求不高的话,这种通过4舍5入获取固定精度的方式一般可以满足需求。
2. 先将小数转为整数再进行计算
0.1 + 0.2 //获取两者都能转化为整数的最小公倍数:RATE = 10
//将上式转换为:
(0.1*RATE + 0.2*RATE)/RATE
= 0.3
这是日常开发中最常用的方式,推荐。
扩展
如果清楚上面讲解的数值存储方式,那么可以知道js的安全整数范围为:
Math.pow(2, 53) - 1 // 可表示的安全整数范围: // Number.MIN_SAFE_INTEGER ~ Number.MAX_SAFE_INTEGER -9007199254740991 ~ 9007199254740991
超出这个范围的整数计算会出现精度丢失问题。
需要处理较大值的话,可以参考bignumber.js等;另外ES2020,加入了BigInt类型:
let number1 = BigInt(123); //方式1 let number2 = 123n; //方式2 number1 == number2; //true typeof number1; //"bigint"
谷歌浏览器已经支持了,可以尝试下~
获取更多干货分享,欢迎【点赞关注】~
随手点个 在看 鼓励下吧~
以上所述就是小编给大家介绍的《【3分钟技能get】js浮点数计算精度问题》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java 浮点型(Double,Float)精度丢失解决方案
- 除不断,理还乱的合约运算—— 浮点和精度处理不当
- 成都链安科技漏洞分析连载第十二期 —— 浮点和精度处理不当
- ARMCC和GCC编译ARM代码的软浮点和硬浮点问题
- 3. Go语言中的整型与浮点型
- 为什么不将“0f”视为C中的浮点文字?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Letting Go of the Words
Janice (Ginny) Redish / Morgan Kaufmann / 2007-06-11 / USD 49.95
"Redish has done her homework and created a thorough overview of the issues in writing for the Web. Ironically, I must recommend that you read her every word so that you can find out why your customer......一起来看看 《Letting Go of the Words》 这本书的介绍吧!