We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前几天遇到一个问题,用“+”将一个数字字符串转成数字后,成功转成数字,但是数值不对了。查阅一下才发现Number还有MAX_SAFE_INTEGER 和 MAX_VALUE 的区别。
MAX_VALUE: JavaScript 中可表示的最大的数。它的近似值为 1.7976931348623157 x 10308。 MAX_SAFE_INTEGER:常量表示在 JavaScript 中最大的安全整数(maxinum safe integer)。
如果一个数字不是安全整数,那么在计算时,就会差生误差。
什么是最大安全整数? 他的“安全”意思是说能够one-by-one表示的整数,双精度数表示和整数是一一对应的,反过来说,在这个范围以内,所有的整数都有一个唯一的浮点数表示,这个浮点数也唯一表示一个对应的整数,这叫做安全整数。也就是说在计算机中,某个二进制串只表示一个数。最大安全整数范围:(-2^53, 2^53)
还是不明白?还有为什么是2^53次方呢? 这与浮点数的二进制表示有关。 根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:
v = (-1)^s * M * 2^E
举个栗子。十进制的5.0,写成二进制是101.0,相当于1.01×2^2。那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。十进制的-5.0,写成二进制是-101.0,相当于-1.01×2^2。那么,s=1,M=1.01,E=2。
JavaScript中所有数字包括整数和小数都只有一种类型 — Number。它的实现遵循 IEEE 754 标准,使用64位固定长度来表示,也就是标准的 double 双精度浮点数。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对于E 和 M还有一些规定:
关于M: 因为M的范围为 1 ≤ M < 2, 所以 M的个位数必定为1, 即M = 1.XXXXXX 。所以IEEE 754 规定M的第一位不需要保存。在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
比如保存1.01时,只保存01 ,在读取的时候才加上1. 这样可以节省1位有效数字。 所以64位的浮点数虽然只有52位用来M 其实最大可以表示53位的 M。
关于E:
2.然后,指数E还可以再分成三种情况:
(1)E不全为0或不全为1。这时,浮点数就采用上面的规则表示,即指数E的计算值减去1023,得到真实值,再将有效数字M前加上第一位的1。
(2)E全为0。这时,浮点数的指数E等于1-1023,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
(3)E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)。
回归正题,为什么Number的最大安全整数为2^53 -1 ? 回顾一下浮点数的表示:
v = (-1)^s * M * 2^E;
首先让 s=0, v = M * 2^E; 因为64位的浮点数,用52位去表示M,再加上 M 默认节省的一位, 所以M最大为 1. 111...111 总共53个1,当指数值E= 52时,得到一个最大的 数字。 2^53-1。 如果超过这个数值, 我们只能通过增大指数 E 来使 v 变大。 比如 2^53 , 则表示为 1.0000...00 * 2 ^53(M为52个0,E = 53)。 但是 2^53 + 1 同样表示为 1.0000...00* 2 ^53(M为52个0,E = 53)。 因为 1.0000...01* 2 ^53(M为51个0 ,1个1,E = 53),表示为 2^53 + 2。 1.0000...00* 2 ^53(M为52个0,E = 53) 其实表示了2个数字 。2^53(9007199254740992) 和 2^ 53 +1(9007199254740993)。所以当我们+ ' 9007199254740993 ' 时,得到的数字是9007199254740992。
还不明白? 那缩小范围 如果计算机用2位来储存 M, 即M最大为 1.11。 那么 E = 2时 我们得到最大的数 111,还想变大 则只能让 E=3,此时得到 1000 (1.00 *2^3),而此时计算机 能表示的下一个数字是 1010( 1.01 * 2^ 3), 无法表示1001, 所以 1001对应的数字在计算机内也只能表示为 1000, 这样就会造成计算误差。
所以js中Number的最大安全数字为 2^53 -1. 可以使用Number.isSafeInteger() 判断当前数字是否是安全数字。
参考文章: 阮一峰——浮点数的二进制表示
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前几天遇到一个问题,用“+”将一个数字字符串转成数字后,成功转成数字,但是数值不对了。查阅一下才发现Number还有MAX_SAFE_INTEGER 和 MAX_VALUE 的区别。
MAX_VALUE: JavaScript 中可表示的最大的数。它的近似值为 1.7976931348623157 x 10308。
MAX_SAFE_INTEGER:常量表示在 JavaScript 中最大的安全整数(maxinum safe integer)。
如果一个数字不是安全整数,那么在计算时,就会差生误差。
什么是最大安全整数?
他的“安全”意思是说能够one-by-one表示的整数,双精度数表示和整数是一一对应的,反过来说,在这个范围以内,所有的整数都有一个唯一的浮点数表示,这个浮点数也唯一表示一个对应的整数,这叫做安全整数。也就是说在计算机中,某个二进制串只表示一个数。最大安全整数范围:(-2^53, 2^53)
还是不明白?还有为什么是2^53次方呢?
这与浮点数的二进制表示有关。
根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:
v = (-1)^s * M * 2^E
举个栗子。十进制的5.0,写成二进制是101.0,相当于1.01×2^2。那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。十进制的-5.0,写成二进制是-101.0,相当于-1.01×2^2。那么,s=1,M=1.01,E=2。
JavaScript中所有数字包括整数和小数都只有一种类型 — Number。它的实现遵循 IEEE 754 标准,使用64位固定长度来表示,也就是标准的 double 双精度浮点数。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对于E 和 M还有一些规定:
关于M:
因为M的范围为 1 ≤ M < 2, 所以 M的个位数必定为1, 即M = 1.XXXXXX 。所以IEEE 754 规定M的第一位不需要保存。在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
比如保存1.01时,只保存01 ,在读取的时候才加上1. 这样可以节省1位有效数字。
所以64位的浮点数虽然只有52位用来M 其实最大可以表示53位的 M。
关于E:
比如,2^10的E是10,所以保存成64位浮点数时,必须保存成10+1023 =1033,即10000001001。
2.然后,指数E还可以再分成三种情况:
(1)E不全为0或不全为1。这时,浮点数就采用上面的规则表示,即指数E的计算值减去1023,得到真实值,再将有效数字M前加上第一位的1。
(2)E全为0。这时,浮点数的指数E等于1-1023,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
(3)E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)。
回归正题,为什么Number的最大安全整数为2^53 -1 ?
回顾一下浮点数的表示:
v = (-1)^s * M * 2^E;
首先让 s=0, v = M * 2^E;
因为64位的浮点数,用52位去表示M,再加上 M 默认节省的一位, 所以M最大为 1. 111...111 总共53个1,当指数值E= 52时,得到一个最大的 数字。 2^53-1。
如果超过这个数值, 我们只能通过增大指数 E 来使 v 变大。 比如 2^53 , 则表示为 1.0000...00 * 2 ^53(M为52个0,E = 53)。
但是 2^53 + 1 同样表示为 1.0000...00* 2 ^53(M为52个0,E = 53)。 因为 1.0000...01* 2 ^53(M为51个0 ,1个1,E = 53),表示为 2^53 + 2。 1.0000...00* 2 ^53(M为52个0,E = 53) 其实表示了2个数字 。2^53(9007199254740992) 和 2^ 53 +1(9007199254740993)。所以当我们+ ' 9007199254740993 ' 时,得到的数字是9007199254740992。
还不明白?
那缩小范围 如果计算机用2位来储存 M, 即M最大为 1.11。 那么 E = 2时 我们得到最大的数 111,还想变大 则只能让 E=3,此时得到 1000 (1.00 *2^3),而此时计算机 能表示的下一个数字是 1010( 1.01 * 2^ 3), 无法表示1001, 所以 1001对应的数字在计算机内也只能表示为 1000, 这样就会造成计算误差。
所以js中Number的最大安全数字为 2^53 -1.
可以使用Number.isSafeInteger() 判断当前数字是否是安全数字。
参考文章:
阮一峰——浮点数的二进制表示
The text was updated successfully, but these errors were encountered: