现象
1
| console.log(.1 + .2 === .3);
|
JS进制互转
1 2
| (10).toString(2); parseInt('1010', 2);
|
整数十进制转二进制
除以 进制,取余,倒序
1 2 3 4 5 6 7 8 9
| 10 转 2
10 / 2 = 5, rem = 0 5 / 2 = 2, rem = 1 2 / 2 = 1, rem = 0 1 / 2 = 0, rem = 1
最终反着读: 1010
|
小数十进制转二进制
1 2
| (0.1).toString(2) '0.0001100110011001100110011001100110011001100110011001101'
|
乘以 进制,取整,正序
1 2 3 4 5 6 7 8 9 10 11
| .1 * 2 = .2, rem = 0 .2 * 2 = .4, rem = 0 .4 * 2 = .8, rem = 0 .8 * 2 = .6, rem = 1 .6 * 2 = .2, rem = 1 .2 * 2 = .4, rem = 0 .4 * 2 = .8, rem = 0 .8 * 2 = .6, rem = 1 .6 * 2 = .2, rem = 1
最终:小数位不变 0. 后边是多少取多少: 0.0001100110011...
|
更多案例
1 2 3 4 5 6 7 8 9 10
| .1 + .2
2.3 + 2.4
1.0 - .9
3 * .3
1.21 / 1.1
|
精度保留、四舍五入
Number.toPrecision
作用:不四舍五入,只保留精度(从第一个不为0的位数开始算精度)
1 2 3 4 5 6 7 8 9 10 11 12
| let numObj = 5.123456
console.log(numObj.toPrecision()) console.log(numObj.toPrecision(5)) console.log(numObj.toPrecision(2)) console.log(numObj.toPrecision(1)) console.log(numObj.toPrecision(20)) console.log(numObj.toPrecision(19)) console.log(numObj.toPrecision(18)) console.log(numObj.toPrecision(17)) console.log(numObj.toPrecision(16)) console.log((0.2).toPrecision(3));
|
Number.toFixed
作用:四舍五入,保留小数点位数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let numObj = 12345.6789
console.log(numObj.toFixed()); console.log(numObj.toFixed(1)); console.log(numObj.toFixed(6));
numObj = 0.105; console.log(numObj.toFixed()); console.log(numObj.toFixed(1)); console.log(numObj.toFixed(2)); console.log(numObj.toFixed(6)); console.log(numObj.toFixed(16)); console.log(numObj.toFixed(17)); console.log(numObj.toFixed(18));
|
原理
浮点数精度问题
浮点数在转二进制时,由于磁盘物理空间大小是有限的,所以无法存储一个无限的小数,导致浮点数转二进制有精度差
Number
64位 双精度浮点数
组成:
- 符号位:1 | 2 * 1
- 指数位:11 | 2 * 11 = 2048 = (2 ** -1024, 2 * 1024)
- 精度位:52 | 2 * 52 安全数
1 2 3 4 5 6 7 8 9 10
| Number.MAX_VALUE === 1.7976931348623157e+308 === 2 ** 1023 * 1.999999999999999;
Number.MAX_SAFE_INTEGER === 9007199254740991 === 2 ** 53 - 1; (这里多乘的2是符号位) 所以JS中最大精度数是 9007199254740991 位数:16
Number.MIN_SAFE_INTEGER === -9007199254740991 === -(2 ** 53 - 1);
|
解决方案
BigInt
1 2 3 4 5
| const a = BigInt(2); console.log(a);
const b = 233333n; console.log(typeof b);
|
对比:
1 2 3 4 5 6
| console.log(2 ** 53 === 2 ** 53 + 1);
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER)
const maxPlusOne = previousMaxSafe + 1n; console.log(previousMaxSafe === maxPlusOne);
|
Number.EPSILON
1 2 3 4 5
| x = 0.2; y = 0.3; z = 0.1; equal = (Math.abs(x - y + z) < Number.EPSILON); console.log(equal);
|
原理(polyfill)
1 2 3
| if (Number.EPSILON === undefined) { Number.EPSILON = Math.pow(2, -52); }
|
三方库