2010-09-07 38 views
1

替代措辞:何时将Double.MIN_VALUE添加到Java中的双精度型而不是会导致不同的Double值? (请参见下面乔恩斯基特的评论)这两种方法是否对应Java中最小的Double值?

SO question关于Java的最小Double值有一定的答案,这在我看来是等价的。 Jon Skeetanswer毫无疑问的作品,但他的解释并没有说服我,它是如何从Richard'sanswer不同。

乔恩的答案使用以下:

double d = // your existing value; 
long bits = Double.doubleToLongBits(d); 
bits++; 
d = Double.longBitsToDouble(); 

理查兹回答中提到的JavaDoc为Double.MIN_VALUE

的常量保持最小 正非零double类型, 2-1074的值。它等于十六进制 浮点文字 0x0.0000000000001P-1022和也等于 到Double.longBitsToDouble(0x1L)

我的问题是,Double.logBitsToDouble(0x1L)与Jon的bits++;有什么不同?

Jon的评论主要关注基本浮点问题。

有添加 Double.MIN_VALUE为双精度值, 和递增代表一个双位模式 之间的差。他们是 完全不同的操作,由于 存储浮点数 的方式。如果您尝试非常 小号码添加到一个非常大的数字, 的差异可能是如此之小 是最接近的结果是一样的 原。将1加到当前 位模式,但是,将总是 改变对应浮动 点值,通过最小可能 值,它是在该比例中可见。

我没有看到Jon的方法增加长“bit ++”,添加Double.MIN_VALUE的方法没有任何区别。他们何时会产生不同的结果?

我写了下面的代码来测试差异。也许有人可以提供更多/更好的样本双数或使用循环来找到有差异的数字。

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); 

OUTPUT:

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 

回答

7

好吧,让我们用这种方式想象一下,坚持十进制数字。假设你有一个浮点小数点类型,它允许你表示5个十进制数字,并且一个0到3之间的数字作为指数,以1,10,100或者1000倍数结果。

因此,零值仅为1(即尾数= 00001,指数= 0)。最大值是99999000(尾数= 99999,指数= 3)。

现在,当您添加1到50000000时会发生什么?在500000000是50001000之后,您不能表示50000001 ...下一个可表示的数字。因此,如果您尝试将它们加在一起,结果只会是与“真”结果最接近的值 - 仍然是500000000。如将Double.MIN_VALUE添加到较大的double。分割成尾数和指数(m = 50000,e = 3),然后将其增加到最小值(m = 50001,e = 3),我的版本(转换为位,递增然后转换回) 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没有任何效果
  • 递增位没有有效果
  • 的区别在afterBitsbefore之间为0.015625,这是很多大于Double.MIN_VALUE。难怪简单的加法没有效果!
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会导致一个新的位模式,因此确实会导致不等的double。

相关问题