私が懸念している限り、完全に解決された質問(数値変換が値を変更するかどうかをテストする方法は? )を再検討しています。問題は、特定の数値が JavaScript の IEEE-754 Number 型をオーバーフローする時期を検出することでした。前の質問は C# を使用しており、マークされた回答は完全に機能しました。
今、私はまったく同じタスクを実行していますが、今回は Java で動作しません。私の知る限り、Javaはそのdouble
データ型にIEEE-754を使用します。したがって、精度を失わせるために前後にキャストできるはずですが、往復します。これに戸惑い、私はJavaを深く掘り下げ始めましたが、今では本当に混乱しています。
C# と Java の両方で、long の最小値と最大値は同じです。
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
私の知る限り、これらの値は、指数と符号用に予約されている固定ビットのため、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!"); }
これはfalse
、Java で (値 = -9223372036854775808L) を返します。
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
これはfalse
、Java で (値 = -9223372036854775808L) を返します。
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);
}
これはtrue
(value = -9223372036854775808L) を返しますが、精度は低くなります。
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
なぜこれがこのように機能するのですか?コンパイラーの最適化のようなものを見逃していますか? 例えば、コンパイラーは私の変換を検出し、それらを「修正」していますか?
編集:リクエストによるテストケースの追加。これら 3 つのテストはすべて失敗します。
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);
}
}