3

I am reading Java puzzlers by Joshua Bloch. In puzzle 28, I am not able to understand following paragraph-

This works because the larger a floating-point value, the larger the distance between the value and its successor. This distribution of floating-point values is a consequence of their representation with a fixed number of significant bits. Adding 1 to a floating-point value that is sufficiently large will not change the value, because it doesn't "bridge the gap" to its successor.

  1. Why do larger floating point values have larger distances between their values and successors?
  2. In case of Integer, we add one to get the next Integer, but in case of float, how do we get next float value? If I have float value in IEEE-754 format, do I add 1 to the mantissa part to get next float?
4

4 回答 4

6

想象一下基于十进制的格式,您只能设置前 5 个值(即尾数长度为 5)。对于小数字,你会很好:1.0000、12.000、125.00

但是对于更大的数字,您将不得不截断 eg1113500。下一个可表示的数字是 1113600,比它大 100。两者之间的任何值都不能以这种格式表示。如果您正在读取此范围内的值,则必须截断它 - 找到最接近的匹配表示,即使它不准确。

数字越大,问题就越严重。如果我达到 34567800000,那么下一个可表示的数字将是 34567900000,即 1000000 或 100 万的差距。这样,您可以看到表示之间的差异取决于大小。

在另一个极端,对于 0.0001 的小值,下一个可表示的值是 0.0002,因此差距仅为 0.0001。

浮点值具有相同的原理,但采用二进制编码(2 的幂而不是 10 的幂)。

于 2013-08-07T17:12:40.213 回答
5

您可以将浮点数视为以 2 为底的科学记数法。在浮点数中,尾数(又名significand)和指数的位数被限制为固定位数。多少取决于您使用的是float(24 位)还是double(53 位)。

考虑以 10 为底的科学记数法有点熟悉。想象一下,尾数被限制为一个整数,并且总是由 3 位有效数字表示。现在考虑此表示中的这两对连续数字:

  • 100 x 10 0和 101 x 10 0(100 和 101)
  • 100 x 10 1和 101 x 10 1(1000 和 1010)

请注意,第一对数字之间的距离(也称为差异)是 1,而第二对数字之间的距离是 10。在这两对数字中,尾数相差 1,这是整数之间可能存在的最小差异,但差异由指数缩放。这就是为什么更大的数字在浮点数之间有更大的步长(你的第一个问题)。

关于第二个问题,让我们看一下将 1 (100 x 10 -2 ) 加到数字 1000 (100 x 10 1 ) 上:

  • 100 x 10 1 + 100 x 10 -2 = 1001 x 10 0

但我们仅限于尾数中只有三个有效数字,因此最后一个数字被归一化(四舍五入后)为:

  • 100×10 1

这让我们回到 1000。要更改浮点值,您需要将该数字与下一个数字之间的差值相加至少一半;这个最小差异随数字的大小而变化。

二进制浮点也发生了完全相同的事情。还有更多细节(例如,规范化、保护数字、隐含的小数点、隐含位),您可以在优秀的文章What Every Computer Scientist Should Know About Floating-Point Arithmetic 中了解这些信息

于 2013-08-07T17:19:23.430 回答
4
  1. 浮点数表示为尾数和指数的组合,其中数字的值是mantissa * 2^(exponent)这样,如果我们假设尾数限制为 2 位(为了使事情更简单)并且您有一个1.1 * 2^100非常大的数字,则“下一个”值将是1.2 * 2^100. 因此,如果您正在进行混合比例计算,1.1*2^100 + 1将四舍五入,1.1*2^100因为尾数中没有足够的空间来保留准确的结果。
  2. 从 java 6 开始,您有一个实用方法Math.nextUp()Math.nextAfter()将允许您“迭代”所有可能的双精度/浮点值。在此之前,您需要向尾数添加 +1 并可能处理溢出以获得下一个/上一个值。
于 2013-08-07T17:11:55.017 回答
2

虽然它没有解释原因,但这个示例代码展示了如何计算一个浮点数和下一个可用浮点数之间的距离,并给出了一个大数字的例子。f并且g应该Integer.MAX_VALUE分开,但它们是相同的。下一个值是h,它1099511627776更大。

float f = Long.MAX_VALUE;
System.out.println("f = " + new BigDecimal(f));
System.out.println("f bits = " + Float.floatToIntBits(f));
float g = f - Integer.MAX_VALUE;
System.out.println("g = f - Integer.MAX_VALUE = " + new BigDecimal(g));
System.out.println("g bits = " + Float.floatToIntBits(g));
System.out.println("f == g? " + (f == g));
float h = Float.intBitsToFloat(Float.floatToIntBits(f) + 1);
System.out.println("h = " + new BigDecimal(h));
System.out.println("h bits = " + Float.floatToIntBits(h));
System.out.println("h - f = " + new BigDecimal(h).subtract(new BigDecimal(f)));

输出:

f = 9223372036854775808
f bits = 1593835520
g = f - Integer.MAX_VALUE = 9223372036854775808
g bits = 1593835520
f == g? true
h = 9223373136366403584
h bits = 1593835521
h - f = 1099511627776
于 2013-08-07T17:14:41.547 回答