これは、シードを引数として使用して乱数を生成する私のコードです:
double randomGenerator(long seed) {
Random generator = new Random(seed);
double num = generator.nextDouble() * (0.5);
return num;
}
種を与えて100個の数字を生成しようとするたびに、それらはすべて同じです。
これを修正するにはどうすればよいですか?
同じ種を与えている場合、それは正常です。これはテストを可能にする重要な機能です。
これをチェックして、擬似ランダム生成とシードを理解します。
決定論的ランダムビットジェネレーターDRBGとも呼ばれる疑似乱数ジェネレーター(PRNG)は、乱数の特性を近似する一連の数値を生成するアルゴリズムです。シーケンスは、真にランダムなシードを含むPRNGの状態と呼ばれる比較的小さな初期値のセットによって完全に決定されるという点で、真にランダムではありません。
異なるシーケンス(アルゴリズムの調整やデバッグを行わない通常の場合)が必要な場合は、nanoTimeを使用して毎回異なるシードを取得しようとするゼロ引数コンストラクターを呼び出す必要があります。もちろん、このRandom
インスタンスはメソッドの外部に保持する必要があります。
コードはおそらく次のようになります。
private Random generator = new Random();
double randomGenerator() {
return generator.nextDouble()*0.5;
}
簡単な方法は以下を使用することです:
Random Rand = new Random(System.currentTimeMillis());
これは、Random
番号を生成する最良の方法です。
メソッドスコープで新しいRandomを作成しないでください。クラスメンバーにします。
public class Foo {
private Random random
public Foo() {
this(System.currentTimeMillis());
}
public Foo(long seed) {
this.random = new Random(seed);
}
public synchronized double getNext() {
return generator.nextDouble();
}
}
これは一例です。 Random
をこのようにラッピングすると、値が追加されるとは思いません。それを使用しているあなたのクラスに入れてください。
それがPseudo-RNGの原理です。数字は本当にランダムではありません。それらは決定論的アルゴリズムを使用して生成されますが、シードに応じて、生成される数値のシーケンスは異なります。常に同じシードを使用するため、常に同じシーケンスが取得されます。
問題は、ランダムジェネレータを再度シードすることです。シードするたびに、乱数ジェネレーターの初期状態はリセットされ、生成する最初の乱数は初期状態の後の最初の乱数になります
1つのシードを使用して複数の数値を生成する場合は、次のようなことができます。
public double[] GenerateNumbers(long seed, int amount) {
double[] randomList = new double[amount];
for (int i=0;i<amount;i++) {
Random generator = new Random(seed);
randomList[i] = Math.abs((double) (generator.nextLong() % 0.001) * 10000);
seed--;
}
return randomList;
}
同じシードを使用すると、同じリストが表示されます。
ここのいくつかの例では、新しいRandom
インスタンスを作成していますが、これは不要です。また、1つのソリューションのようにsynchronized
を使用する理由もありません。代わりに、 ThreadLocalRandom
クラスのメソッドを利用してください。
double randomGenerator() {
return ThreadLocalRandom.current().nextDouble(0.5);
}