这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
C、JAVA等语言有多种数值类型:short、int、long、float、double 等。
而 JavaScript 只有一种数值类型:number,简洁明了,但是也存在许多问题。
number 类型的实现借用自 IEEE 754 标准,是 64 位的浮点数类型,其中包含 1 位符号位、11 位指数位以及 53 位有效位数。
一个 number 数值的计算公式:符号位(正/负)* 有效位值 * (2 ** 指数位值)
需要注意的是有效位的范围:0.5<= 有效位数值 < 1.0
。这样的话最高位始终是1,可以省略,能用的二进制位就多了一个。
下面可以写一个函数,用来分析数值类型的本质,该函数代码来自《JavaScript 悟道》。
function deconstruct(number) {
let sign = 1;
let coefficient = number;
let exponent = 0;
if (coefficient < 0) {
coefficient = -coefficient;
sign = -1;
}
if (Number.isFinite(number) && number !== 0) {
exponent = -1128;
let reduction = coefficient;
while (reduction !== 0) {
exponent += 1;
reduction /= 2;
}
reduction = exponent;
while (reduction > 0) {
coefficient /= 2;
reduction -= 1;
}
while (reduction < 0) {
coefficient *= 2;
reduction += 1;
}
}
return {
'符号位': sign,
'有效位': coefficient,
'有效位二进制': coefficient.toString(2),
'指数位': exponent,
'指数位二进制': exponent.toString(2),
'数值': number
}
}
看一下最大安全整数:
console.log(deconstruct(Number.MAX_SAFE_INTEGER));
// 输出如下:
{
'符号位': 1,
'有效位': 9007199254740991,
'有效位二进制': '11111111111111111111111111111111111111111111111111111',
'指数位': 0,
'指数位二进制': '0',
'数值': 9007199254740991
}
看一下 0.1+0.2 与 0.3的差别:
console.log(deconstruct(0.1));
console.log(deconstruct(0.2));
console.log(deconstruct(0.1+0.2));
console.log(deconstruct(0.3));
// 输出如下:
{
'符号位': 1,
'有效位': 7205759403792794,
'有效位二进制': '11001100110011001100110011001100110011001100110011010',
'指数位': -56,
'指数位二进制': '-111000',
'数值': 0.1
}
{
'符号位': 1,
'有效位': 7205759403792794,
'有效位二进制': '11001100110011001100110011001100110011001100110011010',
'指数位': -55,
'指数位二进制': '-110111',
'数值': 0.2
}
{
'符号位': 1,
'有效位': 10808639105689192,
'有效位二进制': '100110011001100110011001100110011001100110011001101000',
'指数位': -55,
'指数位二进制': '-110111',
'数值': 0.30000000000000004
}
{
'符号位': 1,
'有效位': 10808639105689190,
'有效位二进制': '100110011001100110011001100110011001100110011001100110',
'指数位': -55,
'指数位二进制': '-110111',
'数值': 0.3
}
可见 JavaScript 不擅长处理小数,所以 0.1+0.2 !== 0.3
。在跟金钱相关的数值计算中要留意。
记住,JavaScript 无法精确表示大多数小数,带小数点的数值基本上都是有误差的!