繁体   English   中英

Java浮点澄清

[英]Java floating point clarification

我正在阅读约书亚布洛赫的Java益智游戏 在谜题28中,我无法理解以下段落 -

这是有效的,因为浮点值越大,值与其后继值之间的距离越大。 这种浮点值的分布是它们用固定数量的有效位表示的结果。 将1添加到足够大的浮点值将不会更改该值,因为它不会“缩小”与其后继的间隙。

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

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

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

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

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

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

您可以将浮点视为基础2科学记数法。 在浮点数中,您被限制为尾数(也就是有效数字 )和指数的固定位数。 多少取决于您使用的是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.要更改浮点值,您需要添加该数字与下一个数字之间差异的至少一半; 这个最小差异随着数字的大小而变化。

二进制浮点正在发生同样的事情。 有更多细节(例如,归一化,保护数字,隐含小数点,隐含位),您可以在优秀的文章中了解每个计算机科学家应该知道的关于浮点运算的内容

  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() ,它允许你“迭代”所有可能的double / float值。 在此之前,您需要在尾数中添加+1,并且可能需要处理溢出以获取next / prev值。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM