12

私が懸念している限り、完全に解決された質問(数値変換が値を変更するかどうかをテストする方法は? )を再検討しています。問題は、特定の数値が 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);
    }
}
4

1 に答える 1

6

-9223372036854775808L IEEE-754倍精度数として表すことができますそれは正確-2^63に、二重の表現-1.0 x 2^63とエンコーディングを持っています0xc3e0000000000000

Doubleは、これよりはるかに大きい数値を表すことができます。ただし、表現可能な数値の範囲内のすべての整数を表現することはできません。たとえば、数値に1を加算すると、が得られますが-9223372036854775807 = -2^63 + 1、これは倍精度値として表すことができず、ラウンドトリップ変換後も存続しません

doubleに変換-2^63 + 1すると、最も近い表現可能なdouble値に丸められ-2^63ます。longに戻すと、その値が保持されます。

編集: JavaScriptでテストしたプラットフォームは何ですか?現在のSafariでは、

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

として評価されTrueます。

于 2010-12-03T20:01:16.870 に答える