替代措辞:什么时候将Double.MIN_VALUE添加到Java中的double 而不是会产生不同的Double值? (见Jon Skeet在下面的评论)
关于Java中最小Double值的这个SO question有一些答案在我看来是等价的。 Jon Skeet的answer毫无疑问是有效的,但他的解释并没有让我确信它与Richard's answer有什么不同。
Jon的回答使用以下内容:
double d = // your existing value;
long bits = Double.doubleToLongBits(d);
bits++;
d = Double.longBitsToDouble();
理查兹回答提到Double.MIN_VALUE
持有最小的常数 double类型的正非零值, 2-1074。它等于十六进制 浮点字面量 0x0.0000000000001P-1022也等于 到
Double.longBitsToDouble(0x1L)
。
我的问题是,Double.logBitsToDouble(0x1L)
与Jon的bits++;
有什么不同?
Jon的评论侧重于基本的浮点问题。
添加之间存在差异 Double.MIN_VALUE为double值, 并递增位模式 代表双重。他们是 完全不同的操作,由于 浮点数的方式 存储。如果你试图添加一个非常 很少数到一个很大的数字, 差异可能很小 最接近的结果是相同的 原本的。在当前添加1 然而,位模式将始终如此 改变相应的浮动 点值,尽可能小 在该比例下可见的值。
我没有看到Jon添加Double.MIN_VALUE增加长“bit ++”的方法有什么不同。什么时候会产生不同的结果?
我编写了以下代码来测试差异。也许有人可以提供更多/更好的样本双数或使用循环来找到存在差异的数字。
double d = 3.14159269123456789; // sample double
long bits = Double.doubleToLongBits(d);
long bitsBefore = bits;
bits++;
long bitsAfter = bits;
long bitsDiff = bitsAfter - bitsBefore;
long bitsMinValue = Double.doubleToLongBits(Double.MIN_VALUE);
long bitsSmallValue = Double.doubleToLongBits(Double.longBitsToDouble(0x1L));
if (bitsMinValue == bitsSmallValue)
{
System.out.println("Double.doubleToLongBits(0x1L) is same as Double.doubleToLongBits(Double.MIN_VALUE)");
}
if (bitsDiff == bitsMinValue)
{
System.out.println("bits++ increments the same amount as Double.MIN_VALUE");
}
if (bitsDiff == bitsMinValue)
{
d = d + Double.MIN_VALUE;
System.out.println("Using Double.MIN_VALUE");
}
else
{
d = Double.longBitsToDouble(bits);
System.out.println("Using doubleToLongBits/bits++");
}
System.out.println("bits before: " + bitsBefore);
System.out.println("bits after: " + bitsAfter);
System.out.println("bits diff: " + bitsDiff);
System.out.println("bits Min value: " + bitsMinValue);
System.out.println("bits Small value: " + bitsSmallValue);
输出:
Double.doubleToLongBits(Double.longBitsToDouble(0x1L)) is same as Double.doubleToLongBits(Double.MIN_VALUE)
bits++ increments the same amount as Double.MIN_VALUE
Using doubleToLongBits/bits++
bits before: 4614256656636814345
bits after: 4614256656636814346
bits diff: 1
bits Min value: 1
bits Small value: 1
答案 0 :(得分:7)
好的,让我们用这种方式想象它,坚持使用十进制数字。假设您有一个浮点小数点类型,它允许您表示5个十进制数字,以及指数为0到3之间的数字,将结果乘以1,10,100或1000。
因此,最小的非零值仅为1(即尾数= 00001,指数= 0)。最大值是99999000(尾数= 99999,指数= 3)。
现在,当您添加1到50000000时会发生什么?您不能代表50000001 ... 500000000之后的下一个可表示的数字是50001000.所以如果您尝试将它们加在一起,结果将是最接近“真实”结果的值 - 仍然是500000000。这是比如将Double.MIN_VALUE
添加到较大的double
。
我的版本(转换为位,递增然后转换回来)就像取50000000,分成尾数和指数(m = 50000,e = 3)然后将其递增到最小量,到(m = 50001,e = 3)然后重新组装到50001000。
你看到他们有什么不同吗?
现在这是一个具体的例子:
public class Test{
public static void main(String[] args) {
double before = 100000000000000d;
double after = before + Double.MIN_VALUE;
System.out.println(before == after);
long bits = Double.doubleToLongBits(before);
bits++;
double afterBits = Double.longBitsToDouble(bits);
System.out.println(before == afterBits);
System.out.println(afterBits - before);
}
}
这会尝试大量的两种方法。输出是:
true
false
0.015625
通过输出,这意味着:
Double.MIN_VALUE
没有任何影响afterBits
和before
之间的差异为0.015625, 大于Double.MIN_VALUE
。难怪简单的添加没有效果!答案 1 :(得分:3)
正如乔恩所说的那样:
“如果你尝试添加一点点 号码到一个非常大的数字, 差异可能很小 最接近的结果与 原“。
例如:
// True:
(Double.MAX_VALUE + Double.MIN_VALUE) == Double.MAX_VALUE
// False:
Double.longBitsToDouble(Double.doubleToLongBits(Double.MAX_VALUE) + 1) == Double.MAX_VALUE)
MIN_VALUE
是可表示最小的正双,但这并不意味着将它添加到任意双精度会产生不等的双重。
相反,将1加到基础位会导致新的位模式,从而导致不等的加倍。