2016-02-13 73 views
2

考慮下面的代碼輸出的布爾是Java的浮點整數運算

A: false 
B: false 
C: true 

當我試圖通過任何小於65不起作用減去V1 + V2的總和,就好像減法永遠發生。如果我將原語切換到兩倍,問題就解決了。這是爲什麼發生?

private static final float V1 = 1076712940; 
private static final float V2 = 1070770707; 

public static void main(final String[] args) { 
    final float y = V1 + V2;//2147483647 

    System.out.println("A: ((y - 64) - 1) == (y - 65) --> " 
         + (((y - 64) - 1) == (y - 65))); /* A */ 
    System.out.println("B: (y > y - 64) --> " + (y > y - 64)); /* B */ 
    System.out.println("C: (y > y - 65) --> " + (y > y - 65)); /* C */ 
} 
+4

你認爲'float'具有多少精度?提示:嘗試'System.out.println(Float.toHexString(V1));'和'System.out.println(Float.toHexString(V2));'''你可以使用'double'作爲'y', ' V1'和'V2'(但是'double'也缺乏無限精度)。 –

回答

9

浮點在內存中由符號位,尾數和指數表示,它們本質上是二進制分數。許多十進制數不能完全表示爲二進制分數。在指數或尾數中增加位可以提高精度。

我相信在你的情況下,你已經保存的浮點數和64的值之間的差異並不是一個足夠大的變化來具有不同的浮點表示。但是,因爲double在尾數和指數中有附加位,所以它可以更精確,並且精確地表示減法。

+1

簡單地說:大量的0.00 ... 001 x 10^n的差異將變得越來越大。 –

+0

我將V1和V2切換爲Float.MAX_VALUE 結果發生了變化 A:真 B:假 C:假 您對此有何看法? – Richard

+0

您可以使用'Math.ulp(f)'刪除任何給定值的精確精確級別,以顯示該值與下一個可表示值之間的最小差異。 +1 –

1

這擴大一點在prior answer

原始程序在評論中包含一個聲明y是2147483647.它不是。由於浮點四捨五入,這是2147483648.該程序看起來在y,和可表示的數字包圍它。 BigDecimal的toString在沒有科學記數法的情況下做了精確的轉換,對於這種情況更爲明確。 BigDecimal還對有限長度小數展開的數字進行精確算術,包括所有有限浮點數和雙數。

import java.math.BigDecimal; 

public class Test { 
    private static final float V1 = 1076712940; 
    private static final float V2 = 1070770707; 

    public static void main(String[] args) { 
    final float y = V1 + V2;// 2147483647 
    BigDecimal yBD = new BigDecimal(y); 
    System.out.println("y = " + yBD); 
    BigDecimal down = new BigDecimal(Math.nextDown(y)); 
    System.out.println("nextDown(y) = " + down + " diff = " + yBD.subtract(down)); 
    BigDecimal up = new BigDecimal(Math.nextUp(y)); 
    System.out.println("nextUp(y) = " + up + " diff = " + up.subtract(yBD)); 
    System.out.println(Float.MAX_VALUE + Float.MAX_VALUE); 
    } 

} 

輸出:

y = 2147483648 
nextDown(y) = 2147483520 diff = 128 
nextUp(y) = 2147483904 diff = 256 
Infinity 

2147483648是二的冪,所以它下面的間隙只有128,但上述的間隙是256減去任何小於64具有精確的結果更接近2147483648比任何其他可表示的數字。減去64會得出兩個數字中間的精確結果,並且可以向2147483648舍入。減去65得到的結果更接近2147483520.

在評論中,您問:「我將V1V2Float.MAX_VALUE結果變了A:真B:假C:假你對此有何看法?

我的第一個想法,從我的程序的最後輸出得到證實,是「這使得y無限。」。從無窮大增加或減少有限數字不會改變其值。無限等於自身。

一般來說,如果直接查看所涉及的數字,可以更容易地看到發生了什麼,而不僅僅是查看測試結果和涉及它們的比較。