在使用js进行数值计算是,有时候会有精度丢失问题,比如计算小数时:
整数计算精度丢失,一般是由于数值太大了,转二进制后超出了整数的最大位数; 小数计算精度丢失,一般是由于小数转二进制,长度超出了最大存储长度;
一、小数精度丢失原因
出现精度丢失,简单说就是因为计算机是二进制,而计算的是十进制的数字,而计算机存储二进制的容量又有限,有时候不能表示一个精准的十进制数。
1、十进制转二进制
整数部分:
整数部分除2取余,直到被除数为0,将余数倒过来
例子:将十进制4转为二进制
得到的余数是 0、0、1,倒过来就是 '100',就是二进制的4
小数部分: 小数部分乘2取整,知道小数部分为0
例子:将十进制0.25转为二进制
所以转为二进制后的小数部分就是 '01'
2、二进制转十进制
依次取每位的值,乘以权重,然后求和
例子:求二进制数 100.01的十进制数
3、精度问题分析
还是用 0.1 + 0.2这个问题看,0.1转为二进制,会得出0.0001100011...,是一个无限循环的,那么问题来了,电脑该怎么保存呢?答案就是取一个近似值,所以0.1在电脑中存储的是一个近似值,那么计算的结果必然会出现精度丢失了
二、整数精度丢失原因
js中存储数字采用的是双进度存储,总共64位:
- 1个符号位
- 11个指数位
- 52个尾数位
所以理论上来说,能保存最大整数应该为:
2^52 + 2^51 + 2^50 + ... + 2^0
js中存在一个常量,保存这个值:Number.MAX_SAFE_INTEGER,值为9007199254740991
当存储的整数大于这个值时,就会出问题了,我在最大值后面加了个1
如果超过最大值后,进行计算,也会出问题
- 其实上面的小数精度问题,也是一样的,超出了最大位数了
二、解决方案
- 将数字转为字符串,然后进行操作
- 小数计算精度问题,可以将小数转为整数后再计算,计算完成后再转回小数
- 整数问题,可以使用bigint类型
- 使用第三方库:bigNumber、number-precision