1.265 * 10000 = 126499.99999999999?

时间:2009-06-08 08:17:53

标签: javascript floating-point floating-accuracy

当我将1.265乘以10000时,使用Javascript时会得到126499.99999999999。

为什么会这样?

11 个答案:

答案 0 :(得分:24)

答案 1 :(得分:11)

您应该知道计算机中的所有信息都是二进制的,并且不同基础中的分数的扩展会有所不同。

例如,基数10中的1/3 = .33333333333333333333333333,而基数3中的1/3等于.1,基数2等于.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基数10 + 2 * 4 ^ -2 = 49.375。

现在浮点精度的问题来自有效数字中有限的位数。浮点数有三个部分,一个符号位,指数和尾数,很可能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。

因此我们最终的IEEE 754单(32位)表示为1.625:

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并使用单个浮点而不是双倍,概念保持不变。您使用丢失准确性,因为浮点表示在尾数中只有很多位,用于表示任何给定的数字。

希望这有帮助。

答案 2 :(得分:5)

这是浮点表示错误的结果。并非所有具有有限十进制表示的数字都具有有限的二进制浮点表示。

答案 3 :(得分:4)

阅读this article。从本质上讲,计算机和浮点数不能很好地结合在一起!

答案 4 :(得分:4)

另一方面,126500 IS等于126499.99999999 .... :)

就像1 is equal to 0.99999999....

一样

因为1 = 3 * 1/3 = 3 * 0.333333 ... = 0.99999999 ....

答案 5 :(得分:2)

纯粹是由于floating point表示不准确。

您可以尝试使用Math.round

var x = Math.round(1.265 * 10000);

答案 6 :(得分:1)

您可能需要阅读this

答案 7 :(得分:1)

这些小错误通常是由语言使用的浮点精度引起的。有关浮点精度问题的更多信息,请参阅this wikipedia page

答案 8 :(得分:1)

这是一种克服你的问题的方法,虽然可能不是很漂亮:

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)

答案 9 :(得分:1)

如果您需要解决方案,请停止使用浮点数或双打并开始使用BigDecimal。 检查BigDecimal实现stz-ida.de/html/oss/js_bigdecimal.html.en

答案 10 :(得分:0)

甚至在MS JScript引擎上添加: WScript.Echo(1083.6-1023.6)给出59.9999999