web-dev-qa-db-ja.com

Rand()から数値を縮小するにはどうすればよいですか?

次のコードは、毎秒乱数を出力します。

int main ()
{
    srand(time(NULL)); // Seeds number generator with execution time.

    while (true)
    {
        int rawRand = Rand();

        std::cout << rawRand << std::endl;

        sleep(1);
    }
}

これらの数値を常に0〜100の範囲に収まるように、サイズを小さくするにはどうすればよいですか?

35
Maxpm

C++を使用していて、適切な配布が心配な場合は、次を使用できます。 TR1 C++ 11 <random>

#include <random>

std::random_device rseed;
std::mt19937 rgen(rseed()); // mersenne_twister
std::uniform_int_distribution<int> idist(0,100); // [0,100]

std::cout << idist(rgen) << std::endl;
78
Blastfurnace

これまでに投稿されたすべての例は、実際にはひどく分散した結果をもたらします。コードを頻繁に実行し、統計を作成して、値がどのように歪むかを確認します。

任意の範囲で実際の一様乱数分布を生成するためのより良い方法[0、[〜#〜] n [〜#〜]]は次のとおりです(Randが実際には一様分布に従うと仮定しますが、これは明らかではありません)。

_unsigned result;
do {
    result = Rand();
} while (result > N);
_

もちろん、その方法は遅いですが、良い分布を生成します。これを行う少し賢い方法は、_Rand_MAX_よりも小さい[〜#〜] n [〜#〜]の最大の倍数を見つけて、それを次のように使用することです。上限。その後、安全にresult % (N + 1)を取ることができます。

説明なぜナイーブモジュラス法が悪いのか、そしてなぜ上記が優れているのか、Randを使用)に関するJulienneの優れた記事を参照してください。

30
Konrad Rudolph
_int rawRand = Rand() % 101;
_

(詳細については)を参照してください:

ランド-C++リファレンス

他の人たちはまた、これは可能な限り最良の乱数分布を与えるものではないと指摘しました。そのようなことがコードで重要な場合は、次のようにする必要があります。

_int rawRand = (Rand() * 1.0 / Rand_MAX) * 100;
_

[〜#〜]編集[〜#〜]

3年後、私は編集を行っています。他の人が述べたように、Rand()には多くの問題があります。明らかに、今後より良い代替案がある場合は、その使用を推奨できません。詳細と推奨事項については、こちらをご覧ください。

Rand()は有害と見なされます| GoingNative 201

26
Justin Niessner

できるよ

_cout << rawRand % 100 << endl; // Outputs between 0 and 99

cout << rawRand % 101 << endl; // outputs between 0 and 100
_

投票する人々のために;これが最初に投稿されてから1分後にコメントを残したことに注意してください。

From http://www.cplusplus.com/reference/clibrary/cstdlib/Rand "ただし、このモジュロ演算では、スパン内に真に均一に分散された乱数が生成されないことに注意してください(ほとんどの場合、数値の可能性はわずかに高くなります)が、一般的に短いスパンの場合は適切な近似値です。」

64ビットintを使用し、出力として100個の数値を使用すると、0〜16の数値は数値の1.00000000000000000455%で表されます(1%を約10で同じ分布にした場合の相対精度)-18)、17〜99の数字は0.99999999999999999913の数字の%で表されます。はい、完全に分散されているわけではありませんが、小さなスパンには非常に適しています。

また、OPはどこで同じように配布された番号を要求するのでしょうか?これらは、わずかな偏差が問題にならない目的で使用されていることを私たちは知っています(たとえば、暗号化以外のもの-そして、暗号化に数字を使用している場合、この質問は、彼らが独自の暗号化を書くにはあまりにも素朴です)。

[〜#〜] edit [〜#〜]-乱数の均一な分布に本当に関心がある人のために、次のコードが機能します。これは64ビットのランダムintの場合のように必ずしも最適ではないことに注意してください。これには、10 ^ 18回の呼び出しごとに1回Rand()を2回呼び出す必要があります。

_unsigned N = 100; // want numbers 0-99
unsigned long randTruncation = (Rand_MAX / N) * N; 
// include every number the N times by ensuring rawRand is between 0 and randTruncation - 1 or regenerate.
unsigned long rawRand = Rand();

while (rawRand >= randTruncation) {
    rawRand = Rand();  
// with 64-bit int and range of 0-99 will need to generate two random numbers
// about 1 in every (2^63)/16 ~ 10^18 times (1 million million times)

// with 32-bit int and range of 0-99 will need to generate two random numbers 
// once every 46 million times.

}
cout << rawRand % N << stdl::endl;
_
7
dr jimbob

man 3 Randを参照してください。範囲[0、1]を取得するには、Rand_MAXで除算してスケーリングする必要があります。その後、ターゲット範囲に対して100を掛けることができます。

4

最小から最大(両端を含む)の範囲には、次を使用します:int result = Rand() % (max - min + 1) + min;

0
Jake Petroules