5

「NA」値が NaN 値と区別される R と対話する Java コードを作成しています。NA は、値が「統計的に欠落している」ことを示します。つまり、値を収集できなかったか、利用できないことを意味します。

class DoubleVector {
     public static final double NA = Double.longBitsToDouble(0x7ff0000000001954L);

     public static boolean isNA(double input) {
         return Double.doubleToRawLongBits(input) == Double.doubleToRawLongBits(NA);
     }

     /// ... 
}

次の単体テストは、NaN と NA の関係を示しており、私の Windows ラップトップでは正常に動作しますが、ubuntu ワークステーションでは「isNA(NA) #2」が失敗することがあります。

@Test
public void test() {

    assertFalse("isNA(NaN) #1", DoubleVector.isNA(DoubleVector.NaN));
    assertTrue("isNaN(NaN)", Double.isNaN(DoubleVector.NaN));
    assertTrue("isNaN(NA)", Double.isNaN(DoubleVector.NA));
    assertTrue("isNA(NA) #2", DoubleVector.isNA(DoubleVector.NA));
    assertFalse("isNA(NaN)", DoubleVector.isNA(DoubleVector.NaN));
}

デバッグから、DoubleVector.NA が正規の NaN 値 7ff8000000000000L に変更されているように見えますが、stdout に出力するとデバッガとは異なる値が返されるため、見分けるのは困難です。

また、テストは、他の多くの以前のテストの後に実行された場合にのみ失敗します。このテストを単独で実行すると、常にパスします。

これは JVM のバグですか? 最適化の副作用?

テストは常に次のように渡されます。

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)

テストは時々失敗します:

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)
4

1 に答える 1

6

Java VM の動作が正確に指定されていない数少ない領域の 1 つです。

JVM 仕様によると、double範囲には「NaN 値」しかありません。NaNdouble の算術演算では、2 つの異なる値を区別できませんでした。

のドキュメントにlongBitsToDouble()は次の注記があります。

このメソッドはdouble、長い引数とまったく同じビット パターンを持つ NaN を返すことができない場合があることに注意してください。IEEE 754 では、2 種類の NaN (静止 NaN とシグナリング NaN) が区別されます。2 種類の NaN の違いは、通常、Java ではわかりません。シグナリング NaN の算術演算は、それらを異なるが、多くの場合類似したビット パターンを持つクワイエット NaN に変換します。ただし、一部のプロセッサでは、シグナリング NaN をコピーするだけでもその変換が実行されます。特に、シグナリング NaN をコピーして呼び出し元のメソッドに返すと、この変換が実行される場合があります。そのlongBitsToDoubleため、シグナリング NaN ビット パターンで double を返すことができない場合があります。したがって、一部の長い値でdoubleToRawLongBits(longBitsToDouble(start))は、等しくない場合がありますstart. さらに、どの特定のビット パターンがシグナリング NaN を表すかは、プラットフォームに依存します。ただし、クワイエットまたはシグナリングのすべての NaN ビット パターンは、上記の NaN 範囲内にある必要があります。

したがって、double値を処理すると常に特定 NaNの値がそのまま維持されると仮定することは危険です。

最もクリーンな解決策は、データを保存し、特別な値を確認したlongに変換することです。ただし、これはパフォーマンスにかなりの影響を与えます。double

影響を受けた場所にフラグを追加すると、逃げることができます。これは決して動作することを保証strictfpするものではありませんが、(おそらく) JVM が浮動小数点値を処理する方法を変更し、役立つ必要なヒントになる可能性があります。ただし、まだ移植性はありません。

于 2011-06-16T12:52:06.817 に答える