JavaScript中错误舍入的大量数字
请参阅此代码:JavaScript中错误舍入的大量数字,javascript,floating-point,floating-accuracy,ieee-754,Javascript,Floating Point,Floating Accuracy,Ieee 754,请参阅此代码: var jsonString='{“id”:714341252076979033,“type”:“FUZZY”}; var jsonParsed=JSON.parse(jsonString); log(jsonString,jsonParsed)它不是由此json解析器引起的。只需尝试将714341252076979033输入fbug的控制台。您将看到相同的714341252076979100 有关详细信息,请参阅此博客文章: JavaScript的数字类型的容量已满,有关详细
var jsonString='{“id”:714341252076979033,“type”:“FUZZY”};
var jsonParsed=JSON.parse(jsonString);
log(jsonString,jsonParsed)代码>它不是由此json解析器引起的。只需尝试将714341252076979033输入fbug的控制台。您将看到相同的714341252076979100
有关详细信息,请参阅此博客文章:
JavaScript的数字类型的容量已满,有关详细信息,请参阅。这些ID必须是字符串
IEEE-754双精度浮点(JavaScript使用的那种数字)当然不能精确地表示所有的数字。众所周知,0.1+0.2==0.3
是错误的。它可以影响整数,就像它影响分数一样;一旦超过9007199254740991(Number.MAX\u SAFE\u INTEGER
),它就会启动
除了Number.MAX_SAFE_INTEGER+1
(9007199254740992
),IEEE-754浮点格式不能再表示每个连续整数9007199254740991+1
是9007199254740992
,但是9007199254740992+1
也是9007199254740992
,因为9007199254740993
不能以该格式表示。下一个可以是9007199254740994
。然后9007199254740995
不能,但9007199254740996
可以
原因是我们已经用完了位,所以我们不再有1s位;最低阶位现在表示2的倍数。最终,如果我们继续下去,我们会失去这一点,只能以4的倍数工作。等等
您的值远远高于该阈值,因此它们会四舍五入到最接近的可表示值
从ES2020开始,可以对任意大的整数使用,但没有JSON表示。您可以使用字符串和恢复器函数:
constjsonstring='{“id”:“714341252076979033”,“type”:“FUZZY”};
//注意,这是一个字符串−−−−^−−−−−−−−−−−−−−−−−−^
const obj=JSON.parse(jsonString,(键,值)=>{
if(key==“id”&&typeof value==“string”&&value.match(/^\d+$/){
返回BigInt(值);
}
返回值;
});
控制台日志(obj)代码>
(看看真正的控制台,snippets控制台不理解BigInt。)
问题是您的数字需要比JavaScript更高的精度
你能以字符串的形式发送这个号码吗?分为两部分?您在这里看到的实际上是两个圆角的效果。ECMAScript中的数字在内部表示为双精度浮点。当id
设置为714341252076979033
(0x9e9d9958274c359
十六进制)时,它实际上被分配了最近的可表示双精度值,即714341252076979072
(0x9e9d9958274c380
)。当您打印出该值时,它被四舍五入到15位有效的十进制数字,这使得1434125207699100
JavaScript使用双精度浮点值,即总精度为53位,但您需要
ceil(lb 714341252076979033) = 60
位来精确表示值
最近的可精确表示的数字是714341252076979072
(将原始数字写成二进制,将最后7位数字替换为0
,并向上取整,因为替换的最高数字是1
)
您将得到714341252076979100
而不是这个数字,因为ECMA-262描述的ToString()
,§9.8.1以10的幂次运算,在53位精度下,所有这些数字都是相等的。JavaScript只能处理高达约9亿的精确整数(即9加15个零)。比这还高,你就会得到垃圾。通过使用字符串保存数字来解决这个问题。如果你需要用这些数字做数学运算,写下你自己的函数,或者看看你是否能找到它们的库:我建议使用前者,因为我不喜欢我见过的库。要开始学习,请参阅我的两个函数。感谢大家提供快速有用的答案,我希望我能将这三个函数都标记为正式答案。感谢链接到我的文章,但它只解释了一半的问题——打印内部舍入值。即使javascript允许您打印整个内容,它仍然是错误的——它将是最接近的可表示双精度值,正如下面其他人所解释的。我喜欢这个答案,因为它实际上告诉你如何解决这个问题。这是一个奇妙的答案,也是我一直在寻找的答案。15位有效的十进制数字“1434112520769791”而不是“714341252076979”是我不理解的。这个答案似乎有两个错误:1)轻微,最后一个数字缺少前导7
,2)主调,输出未四舍五入到15位——它也是53位尾数浮点的最接近表示形式,约占15.95位小数。..100
部分不如四舍五入稳定,例如..79135
错误进入..79100
和..79136
错误进入..79200
,甚至这个..35
//code>..36
极限也会任意漂移。(学究式模式:在某种意义上,它是四舍五入,因为它“四舍五入”到15.95位小数)