当我将1.265乘以10000时,使用Javascript时会得到126499.99999999999。
为什么会这样?
答案 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)
答案 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