簡體   English   中英

重新審視 IEEE-754 double(64 位浮點)與 long(64 位整數)

[英]IEEE-754 double (64-bit floating point) vs. long (64-bit integer) revisited

我正在重新審視一個問題(如何測試數字轉換是否會改變值? ),就我而言,該問題已完全解決。 問題是檢測特定數值何時會溢出 JavaScript 的 IEEE-754 數字類型。 上一個問題是使用 C# 並且標記的答案完美地工作。

現在我正在做完全相同的任務,但這次是在 Java 中,它不起作用。 AFAIK,Java 使用 IEEE-754 作為其double數據類型。 所以我應該能夠來回施放它來迫使精度下降,但它會往返。 對此我感到困惑,我開始深入研究 Java,現在我真的很困惑。

在 C# 和 Java 中,long 的最小值和最大值是相同的:

long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;

AFAIK,這些值超出了 IEEE-754 中可表示的數字,因為為指數和符號保留了固定位。

// this fails in browsers that have stuck with the pure ECMAScript Number format
var str = Number(-9223372036854775808).toFixed();
if ("-9223372036854775808" !== str) { throw new Error("Overflow!"); }

這在 Java 中為 (value = -9223372036854775808L) 返回false

boolean invalidIEEE754(long value) {
    try {
        return ((long)((double)value)) != value;
    } catch (Exception ex) {
        return true;
    }
}

這在 Java 中為 (value = -9223372036854775808L) 返回false

boolean invalidIEEE754(long value) {
    // trying to get closer to the actual representation and
    // being more explicit about conversions
    long bits = Double.doubleToLongBits(Long.valueOf(value).doubleValue());
    long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
    return (value != roundtrip);
}

這對 (value = -9223372036854775808L) 返回true但不太准確:

boolean invalidIEEE754(long value) {
    return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}

為什么這樣工作? 我是否缺少編譯器優化之類的東西,例如編譯器是否檢測到我的轉換並為我“修復”它們?

編輯:按請求添加測試用例。 這三個測試都失敗了:

import static org.junit.Assert.*;
import org.junit.Test;

public class FooTests {

    @Test
    public void ieee754One() {
        assertTrue(((long)((double)Long.MIN_VALUE)) != Long.MIN_VALUE);
    }

    @Test
    public void ieee754Two() {
        long bits = Double.doubleToLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
        long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();

        assertTrue(Long.MIN_VALUE != roundtrip);
    }

    @Test
    public void ieee754Three() {
        long bits = Double.doubleToRawLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
        long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();

        assertTrue(Long.MIN_VALUE != roundtrip);
    }
}

-9223372036854775808L表示為 IEEE-754 雙精度數。 它正好是-2^63 ,它具有雙重表示-1.0 x 2^63和編碼0xc3e0000000000000

Double 能夠表示比這大得多的數字。 但是,它不能表示可表示數字范圍內的所有整數 例如,如果給數字加 1,您將得到-9223372036854775807 = -2^63 + 1 ,它不能表示為雙精度值,並且不會在往返轉換中幸存下來。

-2^63 + 1轉換為 double 會將其四舍五入到最接近的可表示的 double 值,即-2^63 轉換回 long 將保留該值。

編輯:您在哪個平台上進行 JavaScript 測試? 在當前的 Safari 中,

"-9223372036854775808" === Number(-9223372036854775808).toFixed()

評估為True

暫無
暫無

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

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