Java.util.Random.nextDouble()は私にとって遅いので、本当に速いものが必要です。
私はいくつかのグーグル検索をしました、そして私は整数ベースの高速ランダムジェネレーターだけを見つけました。区間<0、1)の実数について何かありますか?
高速なものが必要でJava8にアクセスできる場合は、Java.utils
SplitableRandom をお勧めします。それはより速く(〜2倍の速さ)、より良い統計分布を持っています。
さらに高速またはより優れたアルゴリズムが必要な場合は、次の特殊なXorShiftバリアントのいずれかをお勧めします。
これらのアルゴリズムとその品質に関する情報は、 this big PRNG compare 。
私は独立したパフォーマンス比較を行いました。詳細な結果とコードはここにあります: github.com/tobijdc/PRNG-Performance
[〜#〜] tldr [〜#〜]
Java.util.Random
は使用せず、Java.util.SplittableRandom
を使用してください。より速くまたはより良いものが必要な場合PRNG XorShiftバリアントを使用してください。
次の方法で、整数ベースのRNGを変更して、[0,1)の間隔でdoubleを出力することができます。
double randDouble = randInt()/(Rand_INT_MAX + 1.0)
ただし、randInt()が32ビット整数を生成する場合、doubleには53の仮数ビットがあるため、doubleのすべてのビットが満たされるわけではありません。明らかに、2つのランダムな整数を生成して、すべての仮数ビットを埋めることができます。または、Ramdom.nextDouble()実装のソースコードを確認することもできます。ほぼ確実に整数RNGを使用し、出力をdoubleに変換するだけです。
パフォーマンスに関しては、最もパフォーマンスの高い乱数ジェネレーターは線形合同ジェネレーターです。これらのうち、NumericalRecipesジェネレーターの使用をお勧めします。ウィキペディアからLCGの詳細を確認できます: http://en.wikipedia.org/wiki/Linear_congruential_generator
ただし、優れたランダム性が必要で、パフォーマンスがそれほど重要でない場合は、メルセンヌツイスターが最良の選択だと思います。ウィキペディアのページもあります: http://en.wikipedia.org/wiki/Mersenne_Twister
PCGと呼ばれる最近の乱数ジェネレーターがあります。これは http://www.pcg-random.org/ で説明されています。これは本質的に、LCG出力のランダム性を向上させるLCGの後処理ステップです。 PCGはLCGの後処理ステップにすぎないため、LCGよりも低速であることに注意してください。したがって、パフォーマンスが非常に重要で、ランダム性の品質がそれほど重要でない場合は、PCGの代わりにLCGを使用する必要があります。
私が言及したジェネレーターはどれも暗号的に安全ではないことに注意してください。暗号化アプリケーションの値を使用する必要がある場合は、暗号化的に安全なアルゴリズムを使用する必要があります。ただし、暗号化にdoubleが使用されるとは思いません。
これらのソリューションはすべて、基本的な事実(数週間前までは気づいていなかった)を見逃していることに注意してください。乗算を使用して64ビットからdoubleに渡すと、時間の大きな損失になります。 DSIユーティリティ( http://dsiutils.di.unimi.it/ )でのxorshift128 +およびxorshift1024 +の実装は、直接ビット操作を使用しており、その結果は印象的です。
NextDouble()のベンチマークをご覧ください。
http://dsiutils.di.unimi.it/docs/it/unimi/dsi/util/package-summary.html#package.description
と報告された品質
私見あなたはただjuhistの答えを受け入れる-これが理由です。
nextDoubleはnext()を2回呼び出すため、低速です。ドキュメントに記載されています。
したがって、最良のオプションは次のとおりです。
これは、JavaのRandom、LCG(Java.util.Randomと同じくらい悪い)、およびMarsagliaのユニバーサルジェネレーター(doubleを生成するバージョン)を使用した非常に長いベンチマークです。
import Java.util.*;
public class d01 {
private static long sec(double x)
{
return (long) (x * (1000L*1000*1000));
}
// ns/op: nanoseconds to generate a double
// loop until it takes a second.
public static double ns_op(Random r)
{
long nanos = -1;
int n;
for(n = 1; n < 0x12345678; n *= 2) {
long t0 = System.nanoTime();
for(int i = 0; i < n; i++)
r.nextDouble();
nanos = System.nanoTime() - t0;
if(nanos >= sec(1))
break;
if(nanos < sec(0.1))
n *= 4;
}
return nanos / (double)n;
}
public static void bench(Random r)
{
System.out.println(ns_op(r) + " " + r.toString());
}
public static void main(String[] args)
{
for(int i = 0; i < 3; i++) {
bench(new Random());
bench(new LCG64(new Random().nextLong()));
bench(new UNI_double(new Random().nextLong()));
}
}
}
// straight from wikipedia
class LCG64 extends Java.util.Random {
private long x;
public LCG64(long seed) {
this.x = seed;
}
@Override
public long nextLong() {
x = x * 6364136223846793005L + 1442695040888963407L;
return x;
}
@Override
public double nextDouble(){
return (nextLong() >>> 11) * (1.0/9007199254740992.0);
}
@Override
protected int next(int nbits)
{
throw new RuntimeException("TODO");
}
}
class UNI_double extends Java.util.Random {
// Marsaglia's UNIversal random generator extended to double precision
// G. Marsaglia, W.W. Tsang / Statistics & Probability Letters 66 (2004) 183 – 187
private final double[] U = new double[98];
static final double r=9007199254740881.0/9007199254740992.;
static final double d=362436069876.0/9007199254740992.0;
private double c=0.;
private int i=97,j=33;
@Override
public double nextDouble(){
double x;
x=U[i]- U[j];
if(x<0.0)
x=x+1.0;
U[i]=x;
if(--i==0) i=97;
if(--j==0) j=97;
c=c-d;
if(c<0.0)
c=c+r;
x=x-c;
if(x<0.)
return x+1.;
return x;
}
//A two-seed function for filling the static array U[98] one bit at a time
private
void fillU(int seed1, int seed2){
double s,t;
int x,y,i,j;
x=seed1;
y=seed2;
for (i=1; i<98; i++){
s= 0.0;
t=0.5;
for (j=1; j<54; j++){
x=(6969*x) % 65543;
// typo in the paper:
//y=(8888*x) % 65579;
//used forthe demo in the last page of the paper.
y=(8888*y) % 65579;
if(((x^y)& 32)>0)
s=s+t;
t=.5*t;
}
if(x == 0)
throw new IllegalArgumentException("x");
if(y == 0)
throw new IllegalArgumentException("y");
U[i]=s;
}
}
// Marsaglia's test code is useless because of a typo in fillU():
// x=(6969*x)%65543;
// y=(8888*x)% 65579;
public UNI_double(long seed)
{
Random r = new Random(seed);
for(;;) {
try {
fillU(r.nextInt(), r.nextInt());
break;
} catch(Exception e) {
// loop again
}
}
}
@Override
protected int next(int nbits)
{
throw new RuntimeException("TODO");
}
}
プログラムを初期化してそれを繰り返すときに、ランダムなdoubleの配列を作成できます。これははるかに高速ですが、ランダムな値が再び現れます。