这是IEEE 754标准的问题。我不完全理解它背后的机制。
public class Gray {
public static void main(String[] args){
System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
}
}
这是IEEE 754标准的问题。我不完全理解它背后的机制。
public class Gray {
public static void main(String[] args){
System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
}
}
由于 float
只能保留约7到8个有效数字。也就是说,它没有足够的比特位来精确表示数字2000000050,所以它被四舍五入为2000000000。
具体而言,float
由三部分组成:
你可以把浮点数看作是计算机使用二进制进行科学计数法的方式。
精度等于log(2 ^ 尾数位数)
。这意味着float
可以保留log(2 ^ 24) = 7.225
个有效数字。
数字2000000050有9个有效数字。上述计算告诉我们,24位尾数无法保留那么多有效数字。之所以数字2000000000可行,是因为它只有1个有效数字,所以适合放在尾数中。
要解决这个问题,可以使用double
,因为它具有52位尾数,足以表示每个可能的32位数字。
float f = 2000000000;
int binaryValue = Float.floatToRawIntBits(f);
int nextBinaryValue = binaryValue+1;
float nextFloat = Float.intBitsToFloat(nextBinaryValue);
System.out.printf("The next float value after %.0f is %.0f%n", f, nextFloat);
double d = 2000000000;
long binaryValue2 = Double.doubleToRawLongBits(d);
long nextBinaryValue2 = binaryValue2+1;
double nextDouble = Double.longBitsToDouble(nextBinaryValue2);
System.out.printf("The next double value after %.7f is %.7f%n", d, nextDouble);
The next float value after 2000000000 is 2000000128
The next double value after 2000000000.0000000 is 2000000000.0000002
简单地说,当一个浮点数的值为二十亿时,50就是一个四舍五入误差。
200000000.0
和Real((float) 200000000)
之间以及200000050.0
和Real((float) 200000050)
之间的差异。 - Stephen C如果你考虑下面这个程序(C++),可能有助于理解这种情况。它显示了一组连续整数,其舍入为相同的浮点值:
#include <iostream>
#include <iomanip>
int main()
{
float prev = 0;
int count = 0;
double from;
for (double to = 2000000000 - 150; count < 10; to += 1.0)
{
float now = to;
if (now != prev)
{
if (count)
std::cout << std::setprecision(20) << from << ".." << to - 1 << " ==> " << prev << '\n';
prev = now;
from = to;
++count;
}
}
}
输出:
1999999850..1999999935 ==> 1999999872
1999999936..2000000064 ==> 2000000000
2000000065..2000000191 ==> 2000000128
2000000192..2000000320 ==> 2000000256
2000000321..2000000447 ==> 2000000384
2000000448..2000000576 ==> 2000000512
2000000577..2000000703 ==> 2000000640
2000000704..2000000832 ==> 2000000768
2000000833..2000000959 ==> 2000000896
这意味着浮点数只能精确表示从1999999850到1999999935之间的所有整数,错误地记录它们的值为1999999872。对于其他值也是如此。这是上述有限存储空间的实际后果。
std::cout << something
这样的东西实际上是不合理的。 - JeremyP