1

Javaには、-2^63から2^63までの乱数を生成するランダムジェネレータがありますが、これはjava.util.Randomではありません。

(0,1)でランダムなdoubleを生成する必要があります。これは、これまでに行ったことです。

return (seed/(double)(9223372036854775807L))/2+0.5;//seed is a random long

これは正しいですか?数値的な問題(アンダーフロー?)はありますか?

より良い/より速いでしょうか?

ありがとうございました。

4

5 に答える 5

1

私はただ一つの部門を見たいと思います。

0.5+(seed/1.84467440737096E+19);

とは言うものの、64個のランダムな整数ビットがあり、それを53ビットの倍精度に絞り込もうとするため、浮動小数点精度の問題に直面することになります。浮動小数点値専用のジェネレーターを作成したほうがいいかもしれませんが、動機がわからないため、はっきりとは言えません。

于 2012-05-07T20:03:28.423 に答える
1

私はMath.scalbを最も効率的に使用し、丸めや表現エラーによるおかしな動作がないことを確認します

double d = Math.scalb(seed >>> 1, -63);

ダブルでは53ビットしか使用できないため、一部は破棄されます。

実行した場合

long seed = Long.MAX_VALUE;
System.out.println(Math.scalb(seed >>> 1, -63));

プリント

0.5

シードが0の場合、0.0になります

シードが-1の場合、1.0になります

于 2012-05-07T20:07:33.883 に答える
1

おそらく最速の方法は、longの最初の3ビットをに設定し、0それらのビットを使用してdoubleを作成することです。

double rand = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);

これは、符号を正に強制し、指数を0未満にすることで機能します。これにより、仮数が少なくとも1回右にシフトされます。long内のすべてのintが完全にランダムであると仮定すると、均等な分布が得られます。これは、Randomを使用してランダムなlongを生成し、次にこのメソッドを使用してそれらを0から1までのdoubleに変換する完全なJavaプログラムです。

import java.util.Random;

class Main{
    public static void main(String[] args){
        Random rand = new Random();
        long seed = rand.nextLong();
        double x = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
        System.out.println(x);
    }
}

これは、10回の実行の出力です。

1.1211565592484309E-247
8.84224349357039E-242
6.956043405745214E-271
3.747746366809532E-232
9.302628573486166E-158
1.1440116527034282E-166
1.2574577719255876E-198
5.104999671234867E-269
3.360619724894072E-213
1.5654452507283312E-220

編集

これにより、0から1までのすべての可能なdoubleが均一に分散されます。小さいdoubleが多数あるため、1に近い数値が表示されることはほとんどありません。これは、既存の指数のビットに基づいて新しい指数を生成することで修正できます。しかし、それを行うにはループが必要なので、これを考慮した後、おそらく最速の方法ではありません。

long exponent = 0;
for(int i = 52; (seed >>> i & 1) > 0; i++) exponent++;
double x = Double.longBitsToDouble(seed & 0x000FFFFFFFFFFFFFL | ((1022 - exponent) << 52));

0.4773960377161338
0.929045618651037
0.7183096209363845
0.33962049395497845
0.45568660174922454
0.11670190555677815
0.09371618427480996
0.8192870898479095
0.9365016017283178
0.11311614413193898

于 2012-05-07T20:11:25.460 に答える
0

ではない正確に。より簡単な方法は、次のことを行うことだと思います。 new Random(seed).nextDouble()

于 2012-05-07T20:03:23.590 に答える
0

0から1までのランダムなdoubleが必要であると誤解しない限り、Javaに組み込まれているMath.randomはまさにそれを行います。したがって、現在行っているすべての変換を回避できます。

于 2012-05-07T20:05:14.697 に答える