Number
浮点数(IEEE 754)标准
JavaScript中数值通常以字面量形式表示。且没有单独的整数类型,日常使用的字面量数值是浮点数值,而不是整数。
浮点数拓展(IEEE 754)
浮点数拓展(IEEE 754)
IEEE二进制浮点数算术标准IEEE 754是20世纪80代以来最广泛使用的浮点数运算标准。javascript的浮点数运算就是采用了IEEE 754的标准。
IEEE 754规定了四种表示浮点数值的方式:
- 单精确度(32位)
- 双精确度(64位)
- 延伸单精确度(43比特以上,很少使用)
- 延伸双精确度(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 位浮点数示例:
- 将整数部分和小数部分转化为二进制:
- 整数部分 10 转换为二进制:1010
- 小数部分 0.625 转换为二进制:0.101
- 合并得到:1010.101
- 转化为二进制浮点数。
- 科学计数法表示:1010.101 = 1.010101 × 2^3
- 确定符号位、指数位、尾数位:
- 符号位S:0
- 指数位E:3 + 1023 = 1026,转换为二进制:10000000010
- 尾数位M:0101010000000000000000000000000000000000000000000000
- 最终表示为:
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 转换为数字而不抛出错误的情况,因为这是完全显式的转换。
+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() 之间的区别
- Number.isNaN() 不会尝试将参数转换为数字,因此非数字总是返回 false。
- 全局 isNaN() 函数会将参数强制转换为数字:
Number.isFinite()
- 描述:判断传入值是否是一个有限数。
Number.isFinite() 和全局 isFinite() 之间的不同
与全局 isFinite() 函数相比,此方法不会先将参数转换为数字,这意味着只有类型为数字且为有限数的值才返回 true,而非数字的值始终返回 false。
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()
- 描述:判断传入值是否为整数。
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 的所有整数组成。
- 可以精确地表示为 IEEE-754 双精度数,并且
- 其 IEEE-754 表示形式不能是舍入任何其他整数以适应 IEEE-754 表示形式的结果。
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
- 此方法与全局函数 parseFloat() 具有相同的功能:
Number.parseFloat === parseFloat; // true
Number.parseFloat === parseFloat; // true
- 当整数太大以至于不能被转换时将失去精度。
parseFloat(900719925474099267n); // 900719925474099300
parseFloat("900719925474099267n"); // 900719925474099300
parseFloat(900719925474099267n); // 900719925474099300
parseFloat("900719925474099267n"); // 900719925474099300
Number.parseInt()
Number.parseInt(string, radix)
Number.parseInt(string, radix)
- 描述:解析一个字符串参数并返回一个指定基数的整数。
- 参数:要被解析的值,会被强制转化为字符串。字符串开头的空白符将会被忽略。
- [可选参数]:radix 是 2-36 之间的整数,表示被解析字符串的基数。(数学记数系统中的基)。
- 如果 radix 为 undefined 或 0,则 radix 将被默认设置为 10。
- 以码元对 0x 或 0X 开头,在这种情况下,radix 将被默认设置为 16。
- 如果 radix 小于 2 或大于 36,或第一个非空白字符不能转换为数字,则返回 NaN。
TIP
- 此方法与全局函数 parseInt() 具有相同的功能:
Number.parseInt === parseInt; // true
Number.parseInt === parseInt; // true
进制转换
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 之间(包含两端)的整数,则抛出该错误。
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。
- 返回一个表示 numObj 的字符串,但不使用指数计数法,并且小数点后有精确到 digits 位的数字。
- 如果需要截断,则将数字四舍五入;
- 如果小数位数不足,则小数部分用零填充,以使其具有指定长度。
- 异常:如果可选参数不是介于 0 和 100 之间(包含两端)的整数,则抛出该错误。
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
(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()
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 支持的实现中,这个参数是被忽略的。
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 之间(包含两端),则抛出该错误。
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()
- 描述:方法返回表示该数字值的字符串。
- Number 对象的重写了 Object 的 toString 方法;
- 它不会继承 Object.prototype.toString()。
- 对于 Number 值,toString 方法返回数字值指定基数的字符串表示。
- [可选参数]:一个整数,范围在 2 到 36 之间,用于指定表示数字值的基数。默认为 10。
- 异常:如果 radix 小于 2 或大于 36,则抛出该异常。
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"
// 如果你有一个非十进制的数字的字符串,可以使用 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 代码中显式调用。
const numObj = new Number(10);
typeof numObj // object
typeof numObj.valueOf() // number
const numObj = new Number(10);
typeof numObj // object
typeof numObj.valueOf() // number