为什么这是真的?
这是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
包括三个部分:
- 符号位(1位)
- 指数(8位)
- 有效数字(24位,但只存储23位,因为有效数字的MSB始终为1)
您可以将浮点视为计算机进行科学记数法的方式,而不是二进制。
精度等于log(2 ^ number of significand bits)
。 这意味着float
可以保持log(2 ^ 24) = 7.225
有效数字。
该数字2,000,000,050有9位有效数字。 上面的计算告诉我们,24位有效数字不能保存那么多有效数字。 之所以2,000,000,000是因为只有1个有效数字,所以它适用于有效数字。
要解决这个问题,你可以使用double
因为它有一个52位有效数字,这足以代表每个可能的32位数字。
简单地说 – 当浮点值为20亿时,50是舍入误差。
您可能会发现这个技巧可以找到有趣的下一个可表示的值。
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
如果您考虑如下程序(C ++),它可能有助于您了解情况。 它显示了四舍五入到相同浮点值的连续整数组:
#include #include 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.因此,对于其他值。 这是上述有限存储空间的实际结果。