当我将 1.265 乘以 10000 时,我在使用 Javascript 时得到 126499.99999999999。
为什么会这样?
当我将 1.265 乘以 10000 时,我在使用 Javascript 时得到 126499.99999999999。
为什么会这样?
浮点数在所有情况下都不能正确处理小数。查看
您应该知道,计算机中的所有信息都是二进制的,并且分数在不同基数中的扩展是不同的。
例如,以 10 为底的 1/3 = .33333333333333333333,而以 3 为底的 1/3 等于 0.1,以 2 为底的等于 0.0101010101010101。
如果您不完全了解不同的基础如何工作,这里有一个例子:
基数为 4 的数字 301.12。将等于 3 * 4^2 + 0 * 4^1 + 1 * 4^0 + 1 * 4^-1 + 2 *4^-2= 3 * 4^2 +1+ 1 * 4^-1 + 2 * 4^-2=49.375,以 10 为底。
现在浮点精度的问题来自有效数字中的有限位数。浮点数有 3 个部分,符号位、指数和尾数,最有可能 javascript 使用 32 或 64 位 IEEE 754 浮点标准。对于更简单的计算,我们将使用 32 位,因此浮点数为 1.265
0 的符号位(0 表示正数,1 表示负数) 0 的指数(偏移量为 127,即指数+偏移量,因此在无符号二进制中为 127) 01111111(最后我们有 1.265 的有效位,即 ieee 浮点数标准使用隐藏的 1 表示,因此我们的 1.265 的二进制表示为 1.01000011110101110000101,忽略 1:) 01000011110101110000101。
所以我们最终的 1.625 的 IEEE 754 单一(32 位)表示是:
Sign Bit(+) Exponent (0) Mantissa (1.625)
0 01111111 01000011110101110000101
现在 1000 将是:
符号位 (+) 指数 (9) 尾数 (1000) 0 10001000 11110100000000000000000
现在我们必须将这两个数字相乘。浮点乘法包括将隐藏的 1 重新添加到两个尾数,将两个尾数相乘,从两个指数中减去偏移量,然后将两个指数加在一起。在此之后,尾数必须再次归一化。
首先1.01000011110101110000101*1.11110100000000000000000=10.0111100001111111111111111000100000000000000000(这个乘法很痛苦)
现在显然我们有一个 9 的指数 + 一个 0 的指数,所以我们保留 10001000 作为我们的指数,并且我们的符号位仍然存在,所以剩下的就是归一化。
我们需要我们的尾数为 1.000000 的形式,所以我们必须将它向右移动一次,这也意味着我们必须增加我们的指数,使我们达到 10001001,因为我们的尾数已标准化为 1.00111100001111111111111111000100000000000000000。它必须被截断为 23 位,所以我们剩下 1.00111100001111111111111(不包括 1,因为它将隐藏在我们的最终表示中)所以我们留下的最终答案是
Sign Bit (+) Exponent(10) Mantissa
0 10001001 00111100001111111111111
最后,如果我们将这个答案转换回十进制,我们得到 (+) 2^10 * (1+ 2^-3 + 2^-4 +2^-5+2^-6+2^-11+2^-12 +2^-13+2^-14+2^-15+2^-16+2^-17+2^-18+2^-19+2^-20+2^-21+2^-22 +2^-23)=1264.99987792
虽然我确实简化了将 1000 乘以 1.265 而不是 10000 并使用单浮点而不是双精度的问题,但概念保持不变。您使用 loss accuracy 因为浮点表示在尾数中只有这么多位来表示任何给定的数字。
希望这可以帮助。
这是浮点表示错误的结果。并非所有具有有限十进制表示的数字都具有有限二进制浮点表示。
阅读这篇文章。本质上,计算机和浮点数并不能完美地结合在一起!
另一方面,126500 等于 126499.99999999 .... :)
因为 1 = 3 * 1/3 = 3 * 0.333333... = 0.99999999....
这些小错误通常是由语言使用的浮点精度引起的。有关浮点精度问题的更多信息,请参阅此维基百科页面。
如果您需要解决方案,请停止使用浮点数或双精度数并开始使用 BigDecimal。检查 BigDecimal 实现stz-ida.de/html/oss/js_bigdecimal.html.en
这是克服您的问题的一种方法,尽管可以说不是很漂亮:
var correct = parseFloat((1.265*10000).toFixed(3));
// Here's a breakdown of the line of code:
var result = (1.265*10000);
var rounded = result.toFixed(3); // Gives a string representation with three decimals
var correct = parseFloat(rounded); // Convert string into a float
// (doesn't show decimals)
甚至在 MS JScript 引擎上添加:WScript.Echo(1083.6-1023.6) 给出 59.9999999