Java浮点澄清

时间:2013-08-07 17:05:15

标签: java floating-point

我正在阅读Joshua Bloch的 Java益智游戏。在谜题28中,我无法理解以下段落 -

  

这是有效的,因为浮点值越大,越大   价值与其继承人之间的距离。这种分布   浮点值是它们用a表示的结果   固定的有效位数。将1添加到浮点值   足够大不会改变价值,因为它   并没有“弥合差距”给它的继任者。

  1. 为什么较大的浮点值的值与后继值之间的距离较大?
  2. 如果是Integer,我们会添加一个来获取下一个Integer,但如果是float,我们如何获得下一个float值?如果我有IEEE-754格式的浮点值,我是否在尾数部分添加1以获得下一个浮点数?

4 个答案:

答案 0 :(得分:6)

想象一下基于小数的格式,你只允许设置前5个值(即你的尾数是长度5)。对于小数字你会没事的: 1.0000, 12.000, 125.00

但是对于较大的数字,你可能会开始截断例如.113535。下一个可表示的数字是1113600,即100更大。中间的任何值都不能以此格式表示。如果您正在读取此范围内的值,则必须截断它 - 找到匹配的最近表示,即使它不准确。

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

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

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

答案 1 :(得分:5)

您可以将浮点视为基础2科学记数法。在浮点数中,您被限制为尾数(a.k.a。有效数字)和指数的固定位数。多少取决于您使用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 x 10 1

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

二进制浮点正在发生同样的事情。有更多细节(例如,规范化,保护数字,隐含小数点,隐含位),您可以在优秀的文章What Every Computer Scientist Should Know About Floating-Point Arithmetic

中阅读

答案 2 :(得分:4)

  1. 浮点数表示为尾数的组合 和exponent,其中数字的值是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(),它允许你“迭代”所有可能的double / float值。在此之前,您需要在尾数中添加+1,并可能需要处理溢出以获取下一个/上一个值。

答案 3 :(得分:2)

虽然它没有解释原因,但此示例代码显示了如何计算浮点数与下一个可用浮点数之间的距离,并给出了一个大数字的示例。 fg应该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