1. ホーム
  2. java

[解決済み] Random (Java 7)の 181783497276652981 と 8682522807148012 は何ですか?

2022-10-14 14:33:49

質問

なぜ 1817834972766529818682522807148012 で選ばれた Random.java ?

以下は、Java SE JDK 1.7の関連するソースコードです。

/**
 * Creates a new random number generator. This constructor sets
 * the seed of the random number generator to a value very likely
 * to be distinct from any other invocation of this constructor.
 */
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

private static final AtomicLong seedUniquifier
    = new AtomicLong(8682522807148012L);

というわけで new Random() を呼び出すと、現在のquot;seed uniquifier"を受け取り、それをXORして System.nanoTime() . そして 181783497276652981 を使って別のシードユニークファイアを作成し、 次回のために保存します。 new Random() が呼び出されたときのために保存されます。

リテラルは 181783497276652981L8682522807148012L は定数には置かれませんが、他の場所には現れません。

最初はコメントから簡単に手がかりが得られます。 その記事をオンラインで検索すると 実際の記事 . 8682522807148012 は論文には出てきませんが 181783497276652981 は別の数字の部分文字列として登場します。 1181783497276652981 であり、これは 181783497276652981 を持つ 1 が付加されています。

この論文では、次のように主張しています。 1181783497276652981 は線形合同生成器のための良いquot;merit"をもたらす数であると主張しています。 この数は単に Java に間違ってコピーされたのでしょうか? また 181783497276652981 は許容できる長さを持つのでしょうか?

また、なぜ 8682522807148012 が選ばれたのか?

どちらの番号もネットで検索しても説明はなく、ただただ このページ を削除したことにも気づきました。 1 の前にある 181783497276652981 .

この2つの数字と同じように機能する他の数字を選ぶことはできたでしょうか? その理由またはそうでない理由を教えてください。

どのように解決するのですか?

  1. この数字は単にJavaに間違ってコピーされただけなのでしょうか?

    はい、タイプミスのようです。

  2. 181783497276652981は受け入れられるメリットがあるのでしょうか?

    これは論文で紹介されている評価アルゴリズムを使って判断することができます。しかし、quot;original"の数値のメリットはおそらくもっと高いでしょう。

  3. そして、なぜ8682522807148012が選ばれたのでしょうか?

    ランダムなようです。コードが書かれたときのSystem.nanoTime()の結果かもしれません。

  4. この2つの数字と同じように機能する他の数字を選ぶことはできたのでしょうか?

    すべての数字が同じように良いとは限りません。だから、ダメなのです。

シード戦略

JRE の異なるバージョンと実装の間には、デフォルトのシードスキーマに違いがあります。

public Random() { this(System.currentTimeMillis()); }

public Random() { this(++seedUniquifier + System.nanoTime()); }

public Random() { this(seedUniquifier() ^ System.nanoTime()); }

最初のものは、複数のRNGを連続して作成した場合、受け入れられません。もしそれらの作成時間が同じミリ秒の範囲に収まるなら、完全に同一のシーケンスを与えることになります。(同じシード => 同じシーケンス)

2つ目は、スレッドセーフではありません。複数のスレッドが同時に初期化した場合、同一のRNGを得ることができます。さらに、後続の初期化の種は相関する傾向があります。システムの実際のタイマー分解能に依存しますが、シード配列は線形に増加します (n、n+1、n+2、...)。で述べたように ランダム シードはどの程度異なる必要がありますか? および参照された論文 疑似乱数生成器の初期化におけるよくある不具合 という論文では、相関のあるシードは、複数の RNG の実際の配列の間に相関を発生させることができると述べています。

3 番目のアプローチでは、スレッドやその後の初期化においても、ランダムに分散された、したがって相関のないシードを作成します。 そのため、現在の java docs:

このコンストラクタは乱数生成器の種を このコンストラクタの他のどの呼び出しとも異なる可能性が非常に高い値です。 を設定します。

は "across threads" と "uncorrelated" によって拡張される可能性があります。

シード配列の品質

しかし、シードシーケンスのランダム性は、基礎となるRNGと同じくらい良いものでしかありません。 このJava実装でシードシーケンスに使用されているRNGは、c=0、m=2^64の乗法線形合同生成器(MLCG)を使用しています。(係数2^64は64ビット長整数のオーバーフローによって暗黙に与えられます) cが0であることと、2乗剰余であることから、品質(周期長、ビット相関など)が制限される。論文にあるように、全体のサイクル長以外に、各ビットは独自のサイクル長を持ち、それは下位のビットほど指数関数的に減少する。したがって、下位ビットは繰り返しパターンが小さくなる。(実際のRNGでは48ビットに切り詰められる前に,seedUniquifier()の結果はビット反転されるはずです)

しかし、これは高速です。不必要な比較ループや設定ループを避けるために、ループ本体は高速であるべきなのです。足し算、割り算をせず、掛け算だけという、この特殊なMLCGの使い方は、おそらくこのためでしょう。

そして、言及された論文は、1181783497276652981として、c=0およびm=2^64のための良い"multipliers"のリストを提示する。

すべてにおいて。JRE-developersの努力の賜物です。) しかし、typo があります。 (しかし、誰かが評価しない限り、先頭の 1 が欠けていることが実際にシード RNG を向上させる可能性もあります)。

しかし、いくつかの倍率は確実に悪くなっています。 "1" は一定のシーケンスを導きます。 "2"は1ビット動くシーケンスになります(何らかの相関があります)。 ...

RNG の配列間相関は、複数のランダム配列がインスタンス化され、さらに並列化される (モンテカルロ) シミュレーションに実際に関連しています。したがって、良いシーディング戦略は、独立したシミュレーションを実行するために必要です。そのため、C++11 標準では、"seeding" という概念を導入しています。 シードシーケンス という概念を導入し、相関のないシードを生成できるようにしました。