2010-09-07 62 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。

相關問題