2

何をする必要があるかを決定するために乱数を多用し、PRNGの出力に基づいて多くの実行パスを持つプログラムがあります。デバッグしようとして頭を悩ませた後、すべての PRNG 呼び出しが、インスタンス化時にハードコードされた番号にシードされた同じ Random インスタンスを参照するようにすることにしました。そうすれば、プログラムを実行するたびに同じバグが表示されるはずです。残念ながら、実行するたびに異なるバグが発生します (動作はほとんど同じように見えますが)。

コードを何度も検索して、Math.random() の呼び出しを逃したものがないことを確認しました。

何か案は?

編集:生成される数値は同じであることを確認しましたが、動作はまだ非決定論的です。このプログラムはマルチスレッドではありません。まだ完全に困惑しています。

したがって、PRNG は期待どおりに動作していますが、まだ非決定論があります。プログラムに非決定性がうっかり持ち込まれてしまう可能性のある方法にはどのようなものがありますか?

4

3 に答える 3

3

わかりました、非決定論の原因を突き止めたと思います。ある時点で HashSet を繰り返し処理していました。HashSet は同じものによって同じ順序で取り込まれますが、HashSet に追加されるクラスのハッシュ メソッドを指定していないため、各インスタンスのメモリ位置に応じて何らかのハッシュにデフォルト設定されます。

HashSet の各インスタンスを LinkedHashSet に変更すると、現在は 30 回までの実行で一貫した結果が得られているようですが、以前は同じ動作が連続して数回しか発生しませんでした。

于 2012-05-21T22:52:39.980 に答える
2

OK、これはブードゥー教のようです。Randomオブジェクトをラップし、呼び出しをスタックトレースでログに記録するカスタム PRNG を作成してみてください。

public class CustomRNG {

    private static Logger logger = Logger.getLogger(CustomRNG.class.getName());
    private static Random random = new Random(1234);

    public int nextInt() {

       int val = random.nextInt();
       log(val);

       return val;
    }

    private void log(int value) {
        logger.log(Level.INFO, "value: " + value, new Throwable());
    }
}

これにより、値とスタックトレースを含む nextInt へのすべての呼び出しがログに記録されます (必要に応じて呼び出しカウントを追加します)。アプリを数回実行してみて、どの時点 (スタック トレース) で分岐するかを確認してください。

于 2012-05-21T13:37:55.073 に答える
0

継続的な非決定論の考えられる原因 (可能性の降順):

  • すべての PRNG 呼び出しを同じランダム インスタンスに置き換えていません。おそらく最初にこれを確認する必要があります:-) 優れた IDE は、Random クラスへのすべての参照を追跡するのに役立ちます。
  • 同時実行によるタイミング効果があります (たとえば、どのスレッドが最初に PRNG を呼び出すかが重要です)。
  • システムへの何らかの形式の外部入力があります (たとえば、ユーザー入力? システム タイマーに基づいて実行されたアクション?)
  • 使用している一部のライブラリには、プログラムの動作に影響を与える非決定論的要素があります (たとえば、一部の並べ替えアルゴリズムでは乱数が使用され、返される結果の順序に影響を与える可能性があります)。
  • ある種の環境制約にぶつかっています (たとえば、OutOfMemoryError または IOException エラーが時々発生しますが、さまざまな方法でキャッチされて回復されたり、GC がいくつかのソフト/弱い参照をクリアすることを決定したりします)。
  • 宇宙線 / ハードウェア エラーによるメモリの破損
于 2012-05-21T13:08:23.853 に答える