簡體   English   中英

長值如何適合 Java 中的浮點數據類型而不會損失精度

[英]How does long value fit in float data type in Java without loss of precision

長值如何適合 Java 中的浮點數據類型而不會損失精度。 因為如果精度損失那么下面的代碼片段應該產生

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println(lMax == f);

Output 
true

問題是,為了比較longfloatlong值被轉換為float ,並且發生了與賦值相同的精度損失......

如果您想“檢測”精度損失,請嘗試使用BigDecimal s,如下所示:

System.out.println(new BigDecimal(lMax).compareTo(new Bigdecimal(f)));

我知道構造函數BigDecimal(double)會將floatdouble精度,但沒有精度丟失...

編輯

對於大多數人來說, long似乎比float更“精確”。 但是float的范圍是+/-10^38 ,這比long的大得多......

測試

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

f = --lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

輸出:

true
-1
true
true
9223372036854775807, 9223372036854775807
true
-1
false
true
9223372036854775807, 9223372036854775806

Java 語言規范中的二進制數字提升規則是理解問題中代碼片段行為的關鍵。 特別是“否則,如果任一操作數的類型為 float,則另一個將轉換為 float”。

lMax == f比較中, lMax 完全轉換為 float ,正如float f = lMax賦值所做的float f = lMax 如果取相同的輸入值,對其進行兩次相同的轉換,然后比較結果,無論轉換是否改變了值,它們都將相等。

如果您想很好地演示精度損失,請在以毫秒為單位獲取系統時間並從 long 轉換為 float 時嘗試這個小腳本:

class Scratch {
    public static void main(String[] args) throws InterruptedException {

        float currentF;
        long currentL;
        float lastNewF = 0;
        long lastL = System.currentTimeMillis();
        long diff;

        while (true) {
            currentL = System.currentTimeMillis();
            currentF = (float) currentL;
            if (currentF != lastNewF) {
                // we finally got a new "different" float value
                lastNewF = currentF;
                diff = currentL - lastL;
                lastL = currentL;
                System.out.println(diff + " milliseconds since we got a new time as float");
            }
            Thread.sleep(250);
        }
    }
}

您可以從輸出中看到有時會丟失多達 2 分鍾的精度:

0 milliseconds since we got a new time as float
46964 milliseconds since we got a new time as float
131054 milliseconds since we got a new time as float
131093 milliseconds since we got a new time as float
131077 milliseconds since we got a new time as float

lMax的值=9223372036854775807; // 在您的 JVM 中可能會有所不同。

f 的值 = 9.223372E18

現在,當您比較lMax == f ,首先將 f 轉換為 long,然后進行比較。 轉換成long后,f值與lMax相同。

甚至同樣適用於以下代碼。

long lMax = Long.MAX_VALUE; // value is 9223372036854775807
float f =lMax;
float f2 = 9223372036854775807.5f;
System.out.println(lMax == f);
System.out.println(lMax == f2);

輸出

true
true

與 long 相比,這里 f2 正在丟失十進制值。 f2 的 long 值與 lMax 相同。

lMax 是一個長數。 當你將它分配給一個浮點數時,它會失去精度。

浮動 f = lMax;

當您將 long 與 float 進行比較時,在內部將 long 轉換為 float 或將 float 轉換為 long。 你的代碼

lMax == f

將類似於

((Float)f).longValue() == lMax

這是 9.223372E18 == 9.223372E18 真

((Long)lMax).floatValue() == f

這是 9223372036854775807 == 9223372036854775807 true

無論哪種方式,答案都是正確的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM