0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

乱数まとめ

0
Last updated at Posted at 2026-03-28

javaの乱数についてメモ。

java.util.Randomクラス

おそらくもっともサンプルで出てくる初期(jdk1.0)から存在するクラス。
Math.random()はこのRandom.nextDouble()を呼んでいる。
線形合同式のため、過去の一覧から次の乱数が予測できるらしい。

スレッドセーフなのは、AtomicLongを使っている。
この式はクヌース先生のThe Art of Computer Programmingから引用って、1968年出版ですか。

    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
            oldseed = seed.get();
            nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }

自作系Xorshiftクラス

Wikipedia Xorshiftにある。
線形合同式よりは新しい2003年頃。
シードは1以外

xorshift32
        double nextDouble() {
            nextLong();
            return (double) ((long) state & 0xffffffffL) * (1.0 / (double) (0xffffffffL));
        }

        int nextLong() {
            state ^= state << 13;
            state ^= state >>> 17;
            state ^= state << 5;
            return state;
        }

xorshift64
		double nextDouble() {
			nextLong();
			return (double) (state & Long.MAX_VALUE) * (1.0 / (double) (Long.MAX_VALUE));
		}

		long nextLong() {
			state ^= state << 13;
			state ^= state >>> 7;
			state ^= state << 17;
			return state;
		}

java.util.concurrent.ThreadLocalRandomクラス

jdk1.7で追加。
スレッドローカルを使っているから、Randomクラスをスレッドローカルで管理しているのかと思えば、まったく違う式だった。
Unsafe U = Unsafe.getUnsafe();って、もうjavaじゃない部分。
単にGOLDEN_GAMMAを足しているだけだが、スレッドIDも含まれている。
したがって、同じシードでも、スレッドIDが異なれば、異なる乱数パターンとなるが、毎回再現したくてシードを同じにしているのに、スレッドIDが異なったら再現できないのは使いにくいのではないか。
ThreadLocalRandomクラスにsetSeedは公開されているが、実際に呼び出すとUnsupportedOperationExceptionとなる。

    final long nextSeed() {
        Thread t; long r; // read and update per-thread seed
        U.putLong(t = Thread.currentThread(), SEED,
                  r = U.getLong(t, SEED) + (t.threadId() << 1) + GOLDEN_GAMMA);
        return r;
    }

java.util.SplittableRandomクラス

jdk1.8で追加。
独立した並列計算に使用可能だが、スレッドセーフではないと、ややこしい。
乱数ジェネレータの独立性と一様性をテストするDieHarderスイートに合格します。と書いてあるので、乱数としてはマシな感じ。(RandomはDieHarderテストの一部に通っていないとどこかに書いてあった)
ThreadLocalRandomクラスと同じ値GOLDEN_GAMMAを加えた後に、Xorshiftのアイデアも入っているような雰囲気。
setSeedは存在しないが、コンストラクタでseedは指定できる。

    private long nextSeed() {
        return seed += gamma;
    }

    private static long mix64(long z) {
        z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
        z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
        return z ^ (z >>> 31);
    }

    private static int mix32(long z) {
        z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
        return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
    }

java.security.SecureRandomクラス

jdk1.2(1.4)から存在する。
暗号用の乱数。
中身はプロバイダーがプラグイン化されているので、おそらくネイティブコールされている。

SecureRandom数値生成アルゴリズムは、jdk1.8からjdk24でも変わっていない。

ただしWindowsで実行すると以下のものしか使えない。

  • DRBG:NIST SP 800-90Ar1で定義されているDRBGメカニズムを使用するアルゴリズム。
  • SHA1PRNG:Sunプロバイダが提供する擬似乱数生成(PRNG)アルゴリズム。 このアルゴリズムは、PRNGの基盤としてSHA-1を使用します。 各操作につき値が1増加する64ビット・カウンタを使って鎖状につながった真にランダムなシード値から、SHA-1ハッシュを計算します。 160ビットのSHA-1出力のうち、64ビットだけが使用されます。
  • Windows-PRNG:基盤となるWindows OSから乱数を取得します。

その他リストにあるのは以下のもの。

  • NativePRNG:基盤となるネイティブOSから乱数を取得します。 乱数生成のブロック性については何も表明されません。
  • NativePRNGBlocking: 基盤となるネイティブOSから乱数を取得し、必要に応じてブロック化します。 たとえば、UNIX系システムの/dev/randomなど。
  • NativePRNGNonBlocking:基盤となるネイティブOSから乱数を取得しますが、アプリケーションの速度低下を避けるためブロック化しません。 たとえば、UNIX系システムの/dev/urandomなど。
  • PKCS11:基礎となるインストール済および構成済のPKCS #11ライブラリから乱数を取得します。

java.util.random.RandomGeneratorクラス

jdk17で追加。
ThreadLocalRandomは特別な使い方だが、それ以外はRandomGeneratorFactory.ofで共通に使える。
ただしseedの設定はできない。

使用可能な乱数ジェネレータ・アルゴリズム

LXMグループ内のアルゴリズムは互いに似ています。 各アルゴリズムのパラメータは、アルゴリズム名にあります。 "L"の後の数字はLCGサブ・ジェネレータの状態ビットの数を示し、"X"の後の数字はXBGサブ・ジェネレータの状態ビットの数を示します。 "ミックス"は、アルゴリズムで8操作ビット混合関数が使用されていることを示します。"StarStar"は、3操作ビット・スクラムブラの使用を示します。

  • L32X64MixRandom:$2^{64}-2^{32}$
  • L64X128MixRandom:$2^{128}-2^{64}$
  • L64X128StarStarRandom:$2^{128}-2^{64}$
  • L64X256MixRandom:$2^{256}-2^{64}$
  • L64X1024MixRandom:$2^{1024}-2^{64}$
  • L128X128MixRandom:$2^{128}-2^{128}$
  • L128X256MixRandom:$2^{256}-2^{128}$
  • L128X1024MixRandom:$2^{1024}-2^{128}$
  • Xoroshiro128PlusPlus:$2^{128}-1$1
  • Xoshiro256PlusPlus:$2^{256}-1$2
  • Random:$2^{48}$
  • SplittableRandom:$2^{64}$
  • SecureRandom:Hash_DRBG,SHA-256,128,reseed_only3

Apache Commons RNG

cppのmtに相当するMersenneTwister64なるものが、入っている。
ファクトリーから使うには、以下の外部jarファイルが必要となる。

  • commons-rng-client-api-1.6.jar
  • commons-rng-core-1.6.jar
  • commons-rng-simple-1.6.jar

RandomSourceにはいっぱいあるが、有りすぎるのでこれだけ実行してみる。

		UniformRandomProvider mt = RandomSource.MT_64.create(1);
		//MersenneTwister64 mt = new MersenneTwister64(new long[] { 1L });
		for (int i = 0; i < max; i++) {
			double v = mt.nextDouble();
		}

実行時間の比較

すべてnextDouble相当を呼び出し。
数値の単位はミリ秒。

RandomGeneratorFactory,ThreadLocalRandom,Xorshift32,Xorshift64

name 100万 1000万 1億
Random 19 166 1565
Xorshift32 5 17 137
Xorshift64 5 20 161
ThreadLocalRandom 6 15 89
SplittableRandom 8 63 78
L32X64MixRandom 16 81 836
L64X128MixRandom 8 67 511
L64X128StarStarRandom 8 65 621
L64X256MixRandom 8 72 705
L64X1024MixRandom 9 80 794
L128X128MixRandom 11 103 808
L128X256MixRandom 11 86 998
L128X1024MixRandom 13 91 1102
Xoroshiro128PlusPlus 6 58 597
Xoshiro256PlusPlus 7 63 642
SecureRandom 1688 15238 158511

Randomが一番ショボいのに、とにかく遅い。あんな単純な式なのに、AtomicLongが足を引っ張っているような。
AIチャットは、L64X128MixRandomやXoroshiro128PlusPlusが、実行速度やメモリ使用量のバランスがよいとのこと。

ただし、自由にseedが設定できそうなのは、Random,Xorshift32,Xorshift64,SplittableRandom,SecureRandomくらい。

SecureRandom

name 100万 1000万
DRBG 1521 15264
SHA1PRNG 205 1531
Windows-PRNG 365 3458

こちらの用途から100万回も呼ぶようなものではないような。
RandomGeneratorFactoryで終わらないと思ったら、SecureRandomだった。

Apache Commons RNG

name 100万 1000万 1億
RandomSource.MT_64 46 71 236
new MersenneTwister64 37 52 227

初期化に多少時間がかかる。
100万、1000万と連続して実行すると、35-22-204のように、1000万件の方が速くなる。

ソース置き場

  1. 変な羅列と思ったら、Xor-Rotate-Shift-Rotateらしい

  2. こちらはXor-Shift-Rotateらしい

  3. toString()の説明。暗号目的ならば、RandomGeneratorクラスではなく、従来通りSecureRandomクラスを使う

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?