Skip to content

Number

浮点数(IEEE 754)标准

JavaScript中数值通常以字面量形式表示。且没有单独的整数类型,日常使用的字面量数值是浮点数值,而不是整数。

浮点数拓展(IEEE 754)

浮点数拓展(IEEE 754)

IEEE二进制浮点数算术标准IEEE 754是20世纪80代以来最广泛使用的浮点数运算标准。javascript的浮点数运算就是采用了IEEE 754的标准。

IEEE 754规定了四种表示浮点数值的方式:

  1. 单精确度(32位)
  2. 双精确度(64位)
  3. 延伸单精确度(43比特以上,很少使用)
  4. 延伸双精确度(79比特以上,通常以80位实现)

其中javascript采用的是双精度(64位)浮点运算规则。这样的存储结构优点是可以归一化处理整数和小数,节省存储空间。


IEEE754在计算机中存储和运算规则:

一个浮点数 (Value) 可以这样表示:浮点数的实际值,等于符号位(sign bit)乘以指数偏移值(exponent bias)再乘以分数值(mantissa),没错,就是科学计数法。Value = sign * exponent * mantissa

  • 符号位S:第 1 位是正负数符号位(sign),0代表正数,1代表负数。
  • 指数位E:中间的 11 位存储指数(exponent),用来表示次方数。
  • 尾数位M:最后的 52 位是尾数(mantissa),超出的部分自动进一舍零。

将十进制数 10.625 转换为 IEEE 754 64 位浮点数示例

  1. 将整数部分和小数部分转化为二进制:
    • 整数部分 10 转换为二进制:1010
    • 小数部分 0.625 转换为二进制:0.101
    • 合并得到:1010.101
  2. 转化为二进制浮点数。
    • 科学计数法表示:1010.101 = 1.010101 × 2^3
  3. 确定符号位、指数位、尾数位:
    • 符号位S:0
    • 指数位E:3 + 1023 = 1026,转换为二进制:10000000010
    • 尾数位M:0101010000000000000000000000000000000000000000000000
  4. 最终表示为:0 10000000010 0101010000000000000000000000000000000000000000000000

浮点数精度问题 0.1 + 0.2 = 0.30000000000000004

浮点数精度丢失的原因

十进制的0.1和0.2会被转换成二进制的,但是由于浮点数用二进制表示时是无穷的:

0.1 -> 0.0001 1001 1001 1001...(1100循环)

0.2 -> 0.0011 0011 0011 0011...(0011循环)

IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持53位二进制位,所以两者相加之后得到二进制为:

0.0100110011001100110011001100110011001100110011001100

因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了0.30000000000000004。所以在进行算术计算时会产生误差。

构造函数

  • 作为 new Number(value) 构造函数,创建 Number 对象
  • 当作为函数调用时Number(value) ,它返回 Number 类型的原始值。
  • Number 构造函数包含常量和处理数值的方法。其他类型的值可以使用 Number() 函数转换为数字。

使用 Number() 将 BigInt 转换为数字

Number() 是唯一可以将 BigInt 转换为数字而不抛出错误的情况,因为这是完全显式的转换。

javascript
+1n // 报错
0 + 1n // 报错
Number(1n); // 1 不会报错
+1n // 报错
0 + 1n // 报错
Number(1n); // 1 不会报错

静态属性

Number.NaN

  • 描述:Number.NaN 静态数据属性表示非数字值,等同于 NaN。

Number.MIN_VALUE

  • 描述:JavaScript 中可表示的最小正数值,它是最接近 0 的数。

Number.MAX_VALUE

  • 描述:JavaScript 中可表示的最大数值。大于 MAX_VALUE 的值表示为 Infinity 并将丢失其实际值。

Number.MIN_SAFE_INTEGER

  • 描述: JavaScript 中最小的安全整数(-2^53 + 1)。要表示比这小的整数,请考虑使用 BigInt。

Number.MAX_SAFE_INTEGER

  • 描述: JavaScript 中最大的安全整数( 2^53 – 1)。要表示比这大的整数,请考虑使用 BigInt。

Number.EPSILON

  • 描述表示 1 与大于 1 的最小浮点数之间的差值。2^-52,或大约 2.2204460492503130808472633361816E-16。

Number.NEGATIVE_INFINITY

  • 描述:表示正无穷小值。

Number.POSITIVE_INFINITY

  • 描述:表示正无穷大值。

静态方法

Number.isNaN()

  • 描述:判断传入的值是否为 NaN,给定值是一个值为 NaN 的数字,则返回布尔值 true,否则返回 false。(貌似只判断NaN)

Number.isNaN() 和全局 isNaN() 之间的区别

  1. Number.isNaN() 不会尝试将参数转换为数字,因此非数字总是返回 false。
  2. 全局 isNaN() 函数会将参数强制转换为数字:

Number.isFinite()

  • 描述:判断传入值是否是一个有限数。

Number.isFinite() 和全局 isFinite() 之间的不同

与全局 isFinite() 函数相比,此方法不会先将参数转换为数字,这意味着只有类型为数字且为有限数的值才返回 true,而非数字的值始终返回 false。

javascript
isFinite("0"); // true;强制转换为数字 0
Number.isFinite("0"); // false
isFinite(null); // true;强制转换为数字 0
Number.isFinite(null); // false
isFinite("0"); // true;强制转换为数字 0
Number.isFinite("0"); // false
isFinite(null); // true;强制转换为数字 0
Number.isFinite(null); // false

Number.isInteger()

  • 描述:判断传入值是否为整数。
javascript
Number.isInteger(Math.PI); // false
Number.isInteger(NaN); // false
Number.isInteger(Infinity); // false
Number.isInteger(-Infinity); // false

Number.isInteger(5.0); // true
Number.isInteger(5.000000000000001); // false
Number.isInteger(5.0000000000000001); // true,因为精度损失
Number.isInteger(Math.PI); // false
Number.isInteger(NaN); // false
Number.isInteger(Infinity); // false
Number.isInteger(-Infinity); // false

Number.isInteger(5.0); // true
Number.isInteger(5.000000000000001); // false
Number.isInteger(5.0000000000000001); // true,因为精度损失

Number.isSafeInteger()

  • 描述:判断提供的值是否是一个安全整数。安全整数由 -2^53 + 1 到 2^53 - 1 的所有整数组成。
    1. 可以精确地表示为 IEEE-754 双精度数,并且
    2. 其 IEEE-754 表示形式不能是舍入任何其他整数以适应 IEEE-754 表示形式的结果。
javascript
Number.isSafeInteger(3); // true
Number.isSafeInteger(2 ** 53); // false
Number.isSafeInteger(2 ** 53 - 1); // true
Number.isSafeInteger(NaN); // false
Number.isSafeInteger(Infinity); // false
Number.isSafeInteger("3"); // false
Number.isSafeInteger(3.1); // false
Number.isSafeInteger(3.0); // true
Number.isSafeInteger(3); // true
Number.isSafeInteger(2 ** 53); // false
Number.isSafeInteger(2 ** 53 - 1); // true
Number.isSafeInteger(NaN); // false
Number.isSafeInteger(Infinity); // false
Number.isSafeInteger("3"); // false
Number.isSafeInteger(3.1); // false
Number.isSafeInteger(3.0); // true

Number.parseFloat()

  • 描述:析参数并返回浮点数。如果无法从参数中解析出一个数字,则返回 NaN。

TIP

  1. 此方法与全局函数 parseFloat() 具有相同的功能:
javascript
Number.parseFloat === parseFloat; // true
Number.parseFloat === parseFloat; // true
  1. 当整数太大以至于不能被转换时将失去精度。
javascript
parseFloat(900719925474099267n); // 900719925474099300
parseFloat("900719925474099267n"); // 900719925474099300
parseFloat(900719925474099267n); // 900719925474099300
parseFloat("900719925474099267n"); // 900719925474099300

Number.parseInt()

javascript
Number.parseInt(string, radix)
Number.parseInt(string, radix)
  • 描述:解析一个字符串参数并返回一个指定基数的整数。
  • 参数:要被解析的值,会被强制转化为字符串。字符串开头的空白符将会被忽略。
  • [可选参数]:radix 是 2-36 之间的整数,表示被解析字符串的基数。(数学记数系统中的基)。
    1. 如果 radix 为 undefined 或 0,则 radix 将被默认设置为 10。
    2. 以码元对 0x 或 0X 开头,在这种情况下,radix 将被默认设置为 16。
    3. 如果 radix 小于 2 或大于 36,或第一个非空白字符不能转换为数字,则返回 NaN。

TIP

  1. 此方法与全局函数 parseInt() 具有相同的功能:
javascript
Number.parseInt === parseInt; // true
Number.parseInt === parseInt; // true

进制转换

javascript
parseInt(num, 2) // 把num当作2进制 转成 10 进制

num.toString(radix) // 把10进制转为 radix 进制
parseInt(num, 2) // 把num当作2进制 转成 10 进制

num.toString(radix) // 把10进制转为 radix 进制

实例方法

Number.prototype.toExponential()

  • 描述:返回一个以指数表示法表示该数字的字符串。
  • [可选参数]:一个整数,用来指定小数点后有几位数字。默认设置为完整表示该数字所需要的数字。
  • 异常:如果可选参数不是介于 0 和 100 之间(包含两端)的整数,则抛出该错误。
javascript
const numObj = 77.1234;
numObj.toExponential() // 7.71234e+1
numObj.toExponential(4) // 7.7123e+1
numObj.toExponential(2) // 7.71e+1
const numObj = 77.1234;
numObj.toExponential() // 7.71234e+1
numObj.toExponential(4) // 7.7123e+1
numObj.toExponential(2) // 7.71e+1

Number.prototype.toFixed()

  • 描述:使用定点表示法来格式化该数值。
  • [可选参数]:小数点后的位数。应该是一个介于 0 和 100 之间的值,包括 0 和 100。如果这个参数被省略,则被视为 0。
    1. 返回一个表示 numObj 的字符串,但不使用指数计数法,并且小数点后有精确到 digits 位的数字。
    2. 如果需要截断,则将数字四舍五入;
    3. 如果小数位数不足,则小数部分用零填充,以使其具有指定长度。
  • 异常:如果可选参数不是介于 0 和 100 之间(包含两端)的整数,则抛出该错误。
javascript
const numObj = 12345.6789;
numObj.toFixed(); // '12346';四舍五入,没有小数部分
numObj.toFixed(1); // '12345.7';向上舍入
numObj.toFixed(6); // '12345.678900';用零补足位数
const numObj = 12345.6789;
numObj.toFixed(); // '12346';四舍五入,没有小数部分
numObj.toFixed(1); // '12345.7';向上舍入
numObj.toFixed(6); // '12345.678900';用零补足位数
toFixed 有时向上有时向下舍入 的 BUG
javascript
(2.55).toFixed(1); // '2.5'
// 它向下舍入,因为它无法用浮点数精确表示,并且最接近的可表示浮点数较小

(2.449999999999999999).toFixed(1); // '2.5'
// 向上舍入,因为它与 2.45 的差值小于 Number.EPSILON。
// 这个字面量实际上编码和 2.45 相同的数值
(2.55).toFixed(1); // '2.5'
// 它向下舍入,因为它无法用浮点数精确表示,并且最接近的可表示浮点数较小

(2.449999999999999999).toFixed(1); // '2.5'
// 向上舍入,因为它与 2.45 的差值小于 Number.EPSILON。
// 这个字面量实际上编码和 2.45 相同的数值

Number.prototype.toLocaleString()

javascript
toLocaleString(locales, options)
toLocaleString(locales, options)
  • 描述:方法返回这个数字特定于语言环境的表示字符串。在具有 Intl.NumberFormat API 支持的实现中,此方法仅仅简单调用了 Intl.NumberFormat。当格式化大量数字时,最好创建一个 Intl.NumberFormat 对象,并使用其提供的 format() 方法。
  • [可选参数]:缩写语言代码(BCP 47 language tag)的字符串或者这些字符串组成的数组。与 Intl.NumberFormat() 构造函数的 locales 参数相同。在无 Intl.NumberFormat 支持的实现中,往往使用主机的区域设置,这个参数是忽略的。
  • [可选参数]:调整输出格式的对象。与 Intl.NumberFormat() 构造函数的 options 参数相同。在无 Intl.NumberFormat 支持的实现中,这个参数是被忽略的。
javascript
const number = 123456.789;
number.toLocaleString() // '123,456.789' 如果区域设置为美国英语

// 德国使用逗号作为小数分隔符,分位周期为千位
number.toLocaleString("de-DE") // 123.456,789

// 在大多数阿拉伯语国家使用阿拉伯语数字
number.toLocaleString("ar-EG") // ١٢٣٤٥٦٫٧٨٩

// 印度使用千位/拉克(十万)/克若尔(千万)分隔
number.toLocaleString("en-IN") // 1,23,456.789

// nu 扩展字段要求编号系统,e.g. 中文十进制
number.toLocaleString("zh-Hans-CN-u-nu-hanidec") // 一二三,四五六.七八九
const number = 123456.789;
number.toLocaleString() // '123,456.789' 如果区域设置为美国英语

// 德国使用逗号作为小数分隔符,分位周期为千位
number.toLocaleString("de-DE") // 123.456,789

// 在大多数阿拉伯语国家使用阿拉伯语数字
number.toLocaleString("ar-EG") // ١٢٣٤٥٦٫٧٨٩

// 印度使用千位/拉克(十万)/克若尔(千万)分隔
number.toLocaleString("en-IN") // 1,23,456.789

// nu 扩展字段要求编号系统,e.g. 中文十进制
number.toLocaleString("zh-Hans-CN-u-nu-hanidec") // 一二三,四五六.七八九

Number.prototype.toPrecision()

  • 描述:返回一个以定点表示法或指数表示法表示 Number 对象的字符串,该字符串四舍五入到 precision 个有效数字。
  • [可选参数]:一个指定有效位数的整数。
  • 异常:如果 precision 不在 1 和 100 之间(包含两端),则抛出该错误。
javascript
let numObj = 5.123456;
console.log(numObj.toPrecision()); // 输出 '5.123456'
console.log(numObj.toPrecision(5)); // 输出 '5.1235'
console.log(numObj.toPrecision(2)); // 输出 '5.1'
console.log(numObj.toPrecision(1)); // 输出 '5'

numObj = 0.000123;

console.log(numObj.toPrecision()); // 输出 '0.000123'
console.log(numObj.toPrecision(5)); // 输出 '0.00012300'
console.log(numObj.toPrecision(2)); // 输出 '0.00012'
console.log(numObj.toPrecision(1)); // 输出 '0.0001'

// 请注意,在某些情况下可能会返回指数表示法字符串 (符点数失精度问题)
console.log((1234.5).toPrecision(2)); // 输出 '1.2e+3'
let numObj = 5.123456;
console.log(numObj.toPrecision()); // 输出 '5.123456'
console.log(numObj.toPrecision(5)); // 输出 '5.1235'
console.log(numObj.toPrecision(2)); // 输出 '5.1'
console.log(numObj.toPrecision(1)); // 输出 '5'

numObj = 0.000123;

console.log(numObj.toPrecision()); // 输出 '0.000123'
console.log(numObj.toPrecision(5)); // 输出 '0.00012300'
console.log(numObj.toPrecision(2)); // 输出 '0.00012'
console.log(numObj.toPrecision(1)); // 输出 '0.0001'

// 请注意,在某些情况下可能会返回指数表示法字符串 (符点数失精度问题)
console.log((1234.5).toPrecision(2)); // 输出 '1.2e+3'

Number.prototype.toString()

  • 描述:方法返回表示该数字值的字符串。
    1. Number 对象的重写了 Object 的 toString 方法;
    2. 它不会继承 Object.prototype.toString()。
    3. 对于 Number 值,toString 方法返回数字值指定基数的字符串表示。
  • [可选参数]:一个整数,范围在 2 到 36 之间,用于指定表示数字值的基数。默认为 10。
  • 异常:如果 radix 小于 2 或大于 36,则抛出该异常。
javascript
Number.prototype.toString = () => "重写了";
console.log(`${1}`); // "1"
console.log(`${new Number(1)}`); // "重写了"

(10).toString() // '10'
(6).toString(2) // "110"
(254).toString(16); // "fe"
Number.prototype.toString = () => "重写了";
console.log(`${1}`); // "1"
console.log(`${new Number(1)}`); // "重写了"

(10).toString() // '10'
(6).toString(2) // "110"
(254).toString(16); // "fe"
javascript
// 如果你有一个非十进制的数字的字符串,可以使用 parseInt() 和 toString() 将其转换为不同的基数。
const hex = "CAFEBABE";
const bin = parseInt(hex, 16).toString(2); // "11001010111111101011101010111110"
// 把hex当作16进制通过parseInt转为10进制,再把10进制通过toString转为2进制。
// 如果你有一个非十进制的数字的字符串,可以使用 parseInt() 和 toString() 将其转换为不同的基数。
const hex = "CAFEBABE";
const bin = parseInt(hex, 16).toString(2); // "11001010111111101011101010111110"
// 把hex当作16进制通过parseInt转为10进制,再把10进制通过toString转为2进制。

Number.prototype.valueOf()

  • 描述:一个表示指定 Number 对象的原始值的数字。该方法通常由 JavaScript 在内部调用,而非在 Web 代码中显式调用。
javascript
const numObj = new Number(10);
typeof numObj // object
typeof numObj.valueOf() // number
const numObj = new Number(10);
typeof numObj // object
typeof numObj.valueOf() // number