ランダム(Java 7)の181783497276652981および8682522807148012とは何ですか?


112

なぜ、181783497276652981そして8682522807148012選ばれたの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()シードパラメータなしで呼び出すと、現在の「シード一意化子」が取得され、とXORされSystem.nanoTime()ます。次に181783497276652981、次にnew Random()呼び出されるときに格納される別のシード一意化子を作成するために使用します。

リテラル181783497276652981L8682522807148012Lは定数には配置されませんが、他の場所には表示されません。

最初のコメントは私に簡単なリードを与えます。その記事をオンラインで検索すると、実際の記事が表示されます。 8682522807148012紙には表示されませんが、181783497276652981表示されない-別の番号の列として1181783497276652981である、1817834972766529811前に追加。

この論文で1181783497276652981は、これは線形合同生成器に良い「メリット」をもたらす数であると主張しています。この数値は単にJavaに誤ってコピーされたのでしょうか?181783497276652981許容できるメリットがありますか?

そして、なぜ8682522807148012選ばれたのですか?

どちらかの番号をオンラインで検索しても説明はありません。このページだけ1がの前にドロップされていることに気づきます181783497276652981

これらの2つの数値と同様に機能する他の数値を選択できましたか?なぜか、なぜそうでないのか?


乗算は確実にオーバーフローを引き起こしますが、言及された定数(最初のものが大きいものでも)は大きすぎて収まらないことを指摘しておきます。
nanofarad 2013

6
86825228071480122010年に行われた改訂でわかるように、クラスの以前のバージョンのレガシーです。181783497276652981L確かにタイプミスのようで、バグレポートを提出することができます。
assylias 2013

6
それはタイプミス、つまりバグ、または明らかにされていない動機のある機能のいずれかです。著者に尋ねる必要があります。ここで得られるものは、多かれ少なかれ無知な意見です。バグだと思われる場合は、バグレポートを送信してください。
ローン侯爵2013

1
特に異なる答えが与えられた場合、これは各定数に対して2つの別々の質問になる可能性があります。
Mark Hurd 2013

1
このような基本的なクラスに組み込まれているグローバルなスケーラビリティのボトルネックを見て悲しいです。seedUniquifier64コアボックスでは非常に競合する可能性があります。スレッドローカルの方がスケーラブルだったでしょう。
usr

回答:


57
  1. この数値は単にJavaに誤ってコピーされたのでしょうか?

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

  2. 181783497276652981には許容できるメリットがありますか?

    これは、本書に記載されている評価アルゴリズムを使用して決定できます。しかし、「元の」数のメリットはおそらくより高いです。

  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ドキュメント:

このコンストラクターは、乱数ジェネレーターのシードを、このコンストラクターの他の呼び出しとは異なる可能性が非常に高い値に設定します。

「スレッド間」および「無関係」によって拡張できます

種子シーケンス品質

しかし、シーディングシーケンスのランダム性は、基になるRNGと同じくらい良好です。このJava実装でシードシーケンスに使用されるRNGは、c = 0およびm = 2 ^ 64の乗法線形合同法ジェネレーター(MLCG)を使用します。(係数2 ^ 64は64ビット長整数のオーバーフローにより暗黙的に与えられます)ゼロcと2のべき乗の係数のため、「品質」(サイクル長、ビット相関など)は制限されます。論文が述べているように、全体のサイクル長に加えて、すべてのビットには独自のサイクル長があり、重要度の低いビットに対して指数関数的に減少します。したがって、下位ビットの繰り返しパターンは小さくなります。(seedUniquifier()の結果は、実際のRNGで48ビットに切り捨てられる前にビット反転する必要があります)

しかし、それは速いです!そして、不必要な比較と設定ループを避けるために、ループ本体は高速でなければなりません。これはおそらく、この特定のMLCGの使用法を説明します。加算なし、xoringなし、乗算1つだけです。

そして、言及された論文は、1181783497276652981のように、c = 0とm = 2 ^ 64に適した「乗数」のリストを提示しています。

全体として:JRE開発者向けの努力のA;)しかし、タイプミスがあります。(しかし、誰かがそれを評価しない限り、知っている人は、欠落している先行1がシードRNGを実際に改善する可能性があります。)

しかし、一部の乗数は明らかに悪いです。「1」は一定のシーケンスにつながります。「2」は、単一ビットの移動シーケンスにつながります(どういうわけか相関があります)...

RNGのシーケンス間の相関関係は、実際には複数のランダムシーケンスがインスタンス化されて並列化される(モンテカルロ)シミュレーションに関連しています。したがって、「独立した」シミュレーションを実行するには、適切なシード戦略が必要です。したがって、C ++ 11標準では、無相関のシードを生成するためのシードシーケンスの概念が導入されています。


3
少なくとも奇妙なことですが、最上位のものではなく最下位のものをドロップした場合、すべての乗算は最終的に(62ステップ後に)seedUniquifierゼロになるまでビットを失います。
ハロルド2013

9

乱数ジェネレータに使用される方程式は次のとおりであると考える場合:

LCGEquation

X(n + 1)は次の数値、aは乗数、X(n)は現在の数値、cは増分、mは係数です。

さらに詳しく調べるとRandom、a、c、mはクラスのヘッダーで定義されています。

private static final long multiplier = 0x5DEECE66DL;   //= 25214903917 -- 'a'
private static final long addend = 0xBL;               //= 11          -- 'c'
private static final long mask = (1L << 48) - 1;       //= 2 ^ 48 - 1  -- 'm'

そして、protected int next(int bits)これが方程式が実装されている方法である方法を見て

nextseed = (oldseed * multiplier + addend) & mask;
//X(n+1) =  (X(n)   *      a     +    c  ) mod m

これは、メソッドseedUniquifier()が実際にX(n)を取得していること、または最初のケースで初期化X(0)が実際に8682522807148012 * 181783497276652981であることを意味し、この値はさらにの値によって変更されますSystem.nanoTime()。このアルゴリズムは上記の方程式と一致していますが、次のX(0)= 8682522807148012、a = 181783497276652981、m = 2 ^ 64およびc = 0を使用します。ただし、mod mが長いオーバーフローによって実行されるため、上記の方程式は

eq2

論文を見ると a =の値は1181783497276652981m = 2 ^ 64、c = 0の場合です。したがって、これはタイプミスのようであり、8682522807148012X(0)の値はレガシーコードからランダムに選択されたように見えますのためにRandomここに見られるように。しかし、これらの選択された数値のメリットは依然として有効である可能性がありますが、トーマスBが述べたように、おそらく論文の数値ほど「良い」とは言えません。

編集-以下の元の考えは明確にされているので無視できますが、参照用に残します

これは私に結論を導きます:

  1. 論文への参照は、値自体ではなく、a、c、およびmの異なる値のために値を取得するために使用される方法に関するものです

  2. それ以外の点では値が先頭の1以外は同じであり、コメントが誤って配置されていることは単なる偶然です(ただし、これを信じるのはまだ困難です)。

または

論文のテーブルについて深刻な誤解があり、開発者がランダムに値を選択したところです。特に、最初にテーブル値を使用することのポイントが何であるかが乗算されるまで、特に何らかの方法でシード値を所有している場合、これらの値は考慮されません

だからあなたの質問に答えるために

これらの2つの数値と同様に機能する他の数値を選択できましたか?なぜか、なぜそうでないのか?

はい、ランダムなインスタンスを作成するときにシード値を指定した場合、実際には他の値を使用して、任意の数を使用できた可能性があります。この値は、ジェネレーターのパフォーマンスに影響を与えません。これは、クラス内でハードコーディングされているa、c、およびmの値によって決定されます。


1
それほどではない-2つのアルゴリズムがあります。(i)1は、コンストラクターが呼び出されるたびに新しいランダムシードを作成します。そのアルゴは単純なX_n + 1 = X_n * aを使用します。長いオーバーフローのため、これはX_n + 1 = X_n * a mod mと同等です。a = 181783497276652981で、m = 2 ^ 64です。(ii)与えられたシードから始まり、一連の乱数を生成する別のアルゴ。その2番目のアルゴはあなたが言及したものであり、ドキュメントは「これは、コンピュータプログラミングの芸術におけるKnuthによって記述された線形合同の疑似乱数ジェネレータです」と説明しています。
アッシリア2013

1
@assylias私はあなたの意見を理解し、ソースコードにとても夢中になりRandom、元の質問を完全に追い抜いた引用論文をすぐに編集してくれてありがとう。
Java Devil

3

あなたが提供したリンクに従って、彼らは(欠けている1を追加した後:)ロングは2 ^ 128の数を持つことができないため、2 ^ 64からの最高の歩留まりを選択しました

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.