2013-07-13 7 views
12

私はJavaで少しの捕食者 - 獲物のシミュレーションを書いた。ルールが使用される技術は非常に複雑であり、混沌としたシステムで終わる場合でも単純です:基本データ型 Javaは決定的ではありませんか?

  • 外部のシステムが含まれていない
  • なし外部のライブラリに

    • 算術演算および決定は
    • 何の並行処理はして、システムを初期化するときだから私は思っ
    • 現在の時刻や日付の役に立たない

    を発生しません同じ結果を出力するはずの同じパラメータですが、そうではありません。理由は不思議です。

    私のアプリケーションではRandomが使用されていますが、そのテストではすべての値を所定の値で初期化していますので、すべて同じ出力を同じ順序で実行する必要があります。

    私はSetを繰り返していますが、Setの順番は定義されていません。しかし、私は同じ値で同じ順序で塗りつぶされたSetがいくつかの実行で異なった振る舞いをしなければならない理由は見当たりません。それは?

    私は多くのfloatを使用しています。 1 + 1 = 1.9999999999725のデータ型は常に私には疑わしいですが、私の行動が私にとって奇妙であっても、それは常に同じ奇妙でなければなりません。ではない?

    ガベージコレクションは決定的ではありませんが、デストラクタに依存しない限り、私は安全でなければなりません。

    上記のように、実際の使用時間に応じて並行性とデータ型はありません。

    単純な例では、その動作を再現することはできません。しかし、私のコードを見て、私は予測できないものは見えません。私の前提は間違っていますか?私は何が欠けている可能性がある任意のアイデア?

    は、ここに私の仮定を検証するためのテストです:それは私のため242455.25で常に結果

    public static void main(String[] args) { 
        Random r = new Random(1); 
        Set<Float> s = new HashSet<Float>(); 
        for (int i = 0; i < 1000000; i++) { 
         s.add(r.nextFloat()); 
        } 
    
        float ret = 1; 
        int cnt = 0; 
        for (Float f : s) { 
         float multiply = 0.3f; 
         if (cnt++ % 2 == 0) { 
          multiply = 0.7f; 
         } 
         float f2 = (f * multiply); 
         ret += f2; 
        } 
    
        System.out.println(ret); 
    } 
    

  • +1

    時間関数? – Mysticial

    +1

    ランダムデータを初期化すると、シードを使用することを意味しますか? – tjameson

    +0

    これは興味深いと思います。あなたのコードを見てもらえますか? – kol

    答えて

    20

    Javaで確定的なプログラムを書くことができます。非決定論の可能性を排除する必要があります。

    実際のコードを見ることなく、非決定論の原因となる可能性があること、そしてその決定論の具体的な証拠を知るのは難しいです。

    潜在的に非決定論的な動作の原因となる可能性のあるライブラリメソッドは、使用方法によっていくつかあります。

    たとえば、Object.hashcode()(最初にインスタンスで呼び出されたとき)によって返される値は、非決定的です。そして、それはハッシングを使用するライブラリに浸透します。要素クラスがhashcode()をオーバーライドしない場合、反復処理時にHashSetまたはHashMapの要素が返される順序に確実に影響します。

    乱数ジェネレータは、決定的であってもなくてもよい。それらが擬似乱数であり、それらが固定されたシードで初期化されている場合、各シードによって生成される数列は確定的になります。

    浮動小数点演算である必要があります。算術式への入力の固定されたセットの場合、結果は常に同じでなければなりません。 (私は、浮動小数点演算の決定論は、JLSによって保証されていることを確認しないんだけど、それが実際に起こった場合には、強大な奇妙だろう。として...あなたは壊れたハードウェア上で実行されている。)


    フォローアップ ... strictfpと非確定性。

    JLS 15.4によれば:FP-厳密でない式の中

    」、余裕は、中間結果を表すために拡張指数範囲を使用する実装のために付与され、正味の効果は、おおよそfloat値セットまたはdouble値セットを排他的に使用するとオーバーフローまたはアンダーフローが発生する可能性がある場合、計算で「正解」が生成される可能性があります。

    これはまさに実装は非FP厳密式であり、どのくらい「余裕」言いません。しかし、私はその余裕が非決定論的な振る舞いを許すことにまで及ばないと考えていたでしょう。私は、特定のプラットフォーム上のJITコンパイラは、常に同じ表現のために同等のネイティブコードを生成し、そのコードは決定論的であると考えていたでしょう。 (ハードウェア自体が非決定論的な浮動小数点を持たない限り、非決定論の理由は見当たりません。)他の可能性のある非決定論的な原因は、JITのコンパイルされたコードと解釈されるコードの動作が異なる可能性があることです。しかし、率直に言って、私はそれが起こることを「ナット」と思っています。私はそれを聞いたと思います。

    したがって、非FP厳密な式の評価は理論的には非決定論的であるかもしれませんが、実際に起こっているという明白な証拠がない限り、これを割り引くべきです。

    (私は本当の非決定論ではなく、プラットフォームの違いについて話していることに注意してください。)

    +1

    浮動小数点演算の決定は 'strictfp'を使わなければ保証されませんが、これはプラットフォーム間でのみ行うべきです。 (+1) –

    +0

    'strctfp'がなければ、実装はより自由度が高く、ときどき高精度を使うことがあります。 –

    +0

    @PaulBellora - そうです。プラットフォーム間の変動は、非決定論と同じではありません。真の非決定論を持っていたら、あなたのfpハードウェアに欠陥があります...壊れていなければ。 –

    10

    私が設定しthrou反復だ、と私はセットが反復される順序がdefiniedされていないことを知っています。しかし、私は同じ値で同じ順序で塗りつぶされたセットがいくつかの実行でdiffernetを振る舞わなければならない理由を見ません。それは?

    できます。実装は、例えば、メモリ内のオブジェクトの位置を基底のハッシュテーブルのキーとして自由に使用することができます。これは、ガーベジコレクションが実行される時期によって異なる場合があります。

    +0

    @MichaelBulla - どのJVMを使用していますか? – tjameson

    +0

    @tjameson:私は特定のJVMを使用していません。この質問は、何が起こるかではなく、何が起こるかについてです。 –

    +0

    私はOPが私たちにどのようなJVMを使用しているか知ってもらうために、実装ノートを参照して実装が潜在的に発生しているかどうかを調べることができると期待していました。 – tjameson

    関連する問題