Kailang Blog

Javascript 精度2019-10-22Θ

Javascript 中的数字按照 IEEE754 标准,使用 64 位双精度(double)浮点型来表示(统一处理整数和小数,节省存储空间)。ES5规范:

  • S 1位符号位(Sign),为 +1 或 -1;
  • E 11位指数位(Exponent), 范围 [-1074, 971], 包括两端值;
  • M 52位尾数位(Mantissa),正整数并且小于 2^53。

js precision

数值表示#

大数精度#

总结#

[MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] 范围的整数可以精确展示,超出则会有精度问题。

精度问题#

问题分析#

十进制浮点数转二进制方法
  • 比如十进制 0.125,先乘 2, 得 0.25, 取整数部分 0;
  • 将小数部分 0.25 乘 2,等 0.5, 取得整数部分 0;
  • 将小数部分 0.5 乘 2,得到整数部分 1;
  • 得到二进制 0.001
浮点数二进制转十进制方法
  • 0.001,第一位为 0,十进制为 0 * 1 / 2;
  • 第二位为 0,十进制为 0 * 1 / 4;
  • 第二位为 1,十进制为 1 * 1 / 8;
  • 汇总得到十进制为: 0 * 1 / 2 + 0 * 1 / 4 + 1 * 1 / 8 = 0.125

解决思路#

  1. 浮点数运算偏差很小,可以直接进行四舍五入,比如 parseFloat((0.1 + 0.2).toFixed(12)) === 0.3;
  2. 浮点数转成整数运算,再做除法。比如 (0.1 * 10 + 0.2 * 10)/10 === 0.3;
  3. 把浮点转成字符串,模拟实际运算。
  • 第一种方案,在一些极端情况下还是会有问题;
  • 第三种方案有很多成熟的库,比如 bignumber.jsdecimal.jsbig.js。这些库修复了浮点精度、toFixed 问题,并且支持大数据计算。