2009-04-09 4 views
7

PRNGの値をより小さな範囲に制限する最良の方法は何ですか?モジュラスを使用し、古い最大値が新しい最大数で均等に割り切れない場合は、0から(old_max - new_max - 1)に偏ってください。私は最善の方法は、このようなもの(これは浮動小数点、整数でない数学です)pseduo乱数をより小さな範囲に制限する適切な方法は何ですか?

random_num = PRNG()/max_orginal_range * max_smaller_range 

だろうと仮定しますが、私の腸の中で何かが私はその方法問うます(多分浮動小数点の実装と表現の違いを?)。

乱数生成器は、ハードウェアとソフトウェアのプラットフォーム間で一貫した結果を生成し、制約も同様に必要です。

私は上記の擬似コードを疑うことは正しかったです(私が考えていた理由ではありません)。 MichaelGGのanswerは私と別の方法で問題を考えました。私は小さな数字を使ってそれをモデル化し、すべての結果をテストすることができます。したがって、0から31の間の乱数を生成するPRNGがあるとし、小さい範囲を0から9にしたいとしましょう。モジュラスを使用する場合、0,1,2,3の方向にバイアスします。擬似コードを使用する場合あなたは0,2,5,7に偏っています。私は、あるセットを他のセットにマッピングする良い方法があるとは思いません。私がこれまでに考え出したベストは、old_max/new_maxより大きい乱数を再生成することですが、それには深刻な問題もあります(期間を短縮したり、正しい数値になるまで新しい数値を生成する時間など) 。

私はこの問題に素朴に接しているかもしれないと思います。文学について深刻な研究を始める時が来るかもしれません(誰かがこれに前に取り組んでいなければなりません)。

答えて

2

これは特に有用な答えではないかもしれませんが、私はいくつかの方法を考え、数百万回試して結果セットを確認するのが最善の方法だと思います。

疑問がある場合は、自分で試してみてください。 (C#のような)多くの言語がその機能に

int maximumvalue = 20; 
Random rand = new Random(); 

rand.Next(maximumvalue); 

可能な限り制限が組み込まれています、あなたはあなたではなく任意のコードよりも、それらを使用する必要があること

EDIT

に留意する必要があるだろう自分自身を書く。車輪を再燃させないでください。

+0

また、バイアスを導入せずに結果を制約するかなり巧妙な方法を使用するjava.util.Random.nextInt(int)を見てみることもできます。なぜそれが動作するのか理解するために1日ぐらいかかりました:) – Joey

+0

そのソースは入手できます(申し訳ありませんが、私はJavaコーダーではありません、APIの場所については何も知らない) – DevinB

+0

ランダムチェックは良いアイデアですが、管理可能なものに数値を減らすと、すべての結果(上記参照)をテストでき、擬似コードは実際に偏っています。今、私は理解できそうもない記事を掘り起こす必要があります。 –

0

PRNG()が均等に分布する乱数を生成している場合、上記は良好に見えます。実際(もしあなたが平均等を拡大したいならば)上記はすべての目的のためにうまくいくはずです。私はあなたが元のPRNG()に関連するエラーが何であるか、そしてそれ以上の操作がそれに実質的に加わるかどうか尋ねる必要があると思います。

0

お持ちの場合はアクセス

疑問がある場合は、適切なサイズのサンプルセットを生成、およびExcelまたは同様に結果を見て(/ std.devなど、あなたが期待するものをチェックするためにあなたの平均) PRNG機能(たとえば、ランダム())は、その範囲内の番号0 < = X < 1を生成するよに、あなただけで行うことはできません。

random_num = (int) (random() * max_range); 

はMAX_RANGEするあなたの範囲は0で番号を与えることを?ここで

+0

問題のPRNGは0と2^32の間の数値を生成しますが、それでもシステム間で問題を引き起こす浮動小数点の不正確さを心配しています(1/10は正確に表現できないため、 .9など.10 ... 01) –

0

が制限されたときにCLRのランダムクラスが(リフレクターあたりとして)どのように動作するかです:

long num = maxValue - minValue; 
if (num <= 0x7fffffffL) { 
    return (((int) (this.Sample() * num)) + minValue); 
} 
return (((int) ((long) (this.GetSampleForLargeRange() * num))) + minValue); 

あなたは正のintを与えられている場合であっても、それは二重にそれを取得することは難しいことではありません。ランダムなintに(1/maxint)を乗算するだけです。 32ビットintからdoubleへの移動は、適切な精度を提供する必要があります。 (私は実際にこのようなPRNGをテストしていないので、フロートで何かが欠けている可能性があります)

+0

ええと、もし私がその権利を読んでいれば、PRNGはfloat(if)またはdouble(if if outside)を生成しています。 PRNGは整数を生成しないので、これはおそらくreal_random /(double)MAX_RANDOMです。だから唯一の違いは私の擬似コードはゼロベースと仮定し、これは任意のベースを可能にします。 –

+0

Randomクラスを調べると、内部的に( "InternalSample")intを生成し、次に1/Int32.MaxValue(doubleとして)を掛けます。 GetSampleForLargeの範囲は、完全なint32の範囲でのみ許可します。 – MichaelGG

+0

したがって、InternalSampleはreal_randomであり、逆数を掛けることは除算と同じです(効率に違いがなければなりません)。これは、2^32が新しい範囲で均等に割り切れないときに結果をバイアスしていることを意味します。バイアスの周りに道がないように、それは間違いなく鳴っています。 –

0

擬似乱数ジェネレータは、基本的に1と0のランダムな系列を生成します。ベース2の無限大数。あなたが少しずつ消費するたびに、その数を2で割ってモジュラスを維持しています。あなたは1ビットを無駄にすることなくこれを永久に行うことができます。

[0、N]の範囲の数値が必要な場合は、同じものが必要ですが、ベース2の代わりにベースNが必要です。基本的にベースを変換するのは簡単です。必要なビット数を消費し、残りのビットを自分のprngに戻して、次に番号が必要なときに使用します。

+2

あなたは何を得ているのか、まだ偏っているのか分かりません。 0 - 3を生成するPRNGを仮定します。0 - 2に減らしたいと考えています.4つの数値が必要です。すべてのケースをモデル化するのは簡単です。結果を加算すると、0 - 2に等しくなるはずです。パターン11を破棄するか、baisesを1にする必要があります –

関連する問題