不仅在 JavaScript 中存在这个问题,所有的支持二进制浮点数运算(绝大部分都是 IEEE 754的实现)的系统都存在这个现象。
十进制中,科学计数法的形式是:
二进制中,科学计数法就是:
在有限的存储空间下,十进制小数 0.1 无论如何也不能用这种形式来表示
比如对于0.5,就可以表示成sign = 0, exponent = -1, fraction = 1
比如原数为0.5, 那么实际上会表示成
比如-1会表示成126,因为126-offest(127) = -1
比如0.5的单精度表示为:
0 01111110 00000000000000000000000
其中:
所以0.5f =
这种方法导致很多浮点数不能精确表示
0.1的浮点数表示为:
0 01111011 10011001100110011001101
实际上值为:
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)
双精度浮点数的小数部分最多支持 52 位
0.0100110011001100110011001100110011001100110011001100
(十进制)
0.30000000000000004
尾数位最大是52位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。
大于 9007199254740992 的可能会丢失精度:
IE6-10
chrome/firefox
四舍五入 or 四舍六入五成双:
各版本浏览器的测试结果
当5后有数时,舍5入1;
当5后无有效数字时,需要分两种情况来讲:
①5前为奇数,舍5入1;
②5前为偶数,舍5不进。
1. f = 2
3. x = 9.655
5. s = ''
8. a. n = 965
原因:
当 n = 965 时 n / 10^f – x = -0.004999999999999005
当 n = 966 时 n / 10^f – x = 0.005000000000000782
965更靠近0
b. m = '965'
c. i. k = 3
iii. a = '9', b = '65'
iv. m = a + '.' + b = '9.65'
9. Return s + m = '9.65'
1. f = 2
3. x = 9.955
5. s = ''
8. a. n = 996
原因:
当 n = 995 时 n / 10^f – x = -0.005000000000000782
当 n = 996 时 n / 10^f – x = 0.005000000000000782
同样靠近0, 选择大的那个
b. m = '996'
c. i. k = 3
iii. a = '9', b = '96'
iv. m = a + '.' + b = '9.96'
9. Return s + m = '9.96'
Math.formatFloat = function(f, digit) {
var m = Math.pow(10, digit);
return parseInt(f * m, 10) / m;
}
var numA = 0.1;
var numB = 0.2;
alert(Math.formatFloat(numA + numB, 1) === 0.3); //true
把需要计算的数字乘以 10 的 n 次幂,换算成计算机能够精确识别的整数,然后再除以 10 的 n 次幂
无限循环小数 => 分数 ?
纯循环小数
非纯循环小数
无限循环小数 => 分数 ?
不要用JavaScript来计算重要的高精度数据
不要用浮点数运算来进行条件判断
toFixed() 仅仅用来显示