[英]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.