rand()から数字を縮小するにはどうすればよいですか?
-
11-10-2019 - |
質問
次のコードは、毎秒乱数を出力します。
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の範囲にあるのでしょうか?
解決
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;
他のヒント
これまでに投稿されたすべての例は、実際にはひどく分散された結果を提供します。頻繁にコードを実行し、統計を作成して、値がどのように歪んでいるかを確認します。
リアルを生成するためのより良い方法 ユニフォーム 任意の範囲の乱数分布[0、 n]は次のとおりです(それを仮定します rand
実際、均一な分布に従いますが、これは明らかではありません):
unsigned result;
do {
result = rand();
} while (result > N);
もちろん、その方法は遅いですが します 適切な分布を生成します。これを行うためのわずかに賢い方法は、の最大の倍数を見つけることです n それはより小さいです RAND_MAX
そしてそれを上限として使用します。その後、安全に取ることができます result % (N + 1)
.
説明のために どうして ナイーブモジュラスメソッドは悪いものであり、上記が優れている理由、 ジュリエンヌの優れた記事を参照してください 使用 rand
.
int rawRand = rand() % 101;
(詳細については)を参照してください:
他の人たちはまた、これがあなたに可能な限り最高の分布を与えないだろうと指摘しています。そのようなことがあなたのコードで重要である場合、あなたはしなければなりません:
int rawRand = (rand() * 1.0 / RAND_MAX) * 100;
編集
3年後、私は編集しています。他の人が述べたように、 rand()
多くの問題があります。明らかに、今後のより良い選択肢がある場合、その使用をお勧めできません。詳細と推奨事項については、こちらをご覧ください。
できるよ
cout << rawRand % 100 << endl; // Outputs between 0 and 99
cout << rawRand % 101 << endl; // outputs between 0 and 100
ダウン投票する人々のために。これが最初に投稿されてから1分後に注意してください私はコメントを残しました:
から http://www.cplusplus.com/reference/clibrary/cstdlib/rand 「ただし、このモジュロ操作は、スパンで真に均一に分布した乱数を生成しないことに注意してください(ほとんどの場合、より低い数はわずかに可能性が高いためです)が、通常は短いスパンの適切な近似です。」
64ビットのINTを使用して出力として100の数値を使用すると、数値0-16は1.00000000000000000455%の数字で表されます(相対的な精度から1%x約10の同一に分布しています-18)、数字17-99は0.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999はい、完全に分布していませんが、小さなスパンの非常に良い近似です。
また、OPはどこで同じ分布の数値を求めますか?私たちが知っているすべてのために、これらは小さな逸脱が重要ではない目的で使用されています(例えば、暗号化以外のもの - そして、彼らが暗号化のために数字を使用している場合、この質問は彼らが自分の暗号を書くにはあまりにも素朴です)。
編集 - 乱数の均一な分布に本当に関心のある人のために、次のコードが機能します。これは、64ビットのランダムINTと同様に必ずしも最適ではないことに注意してください。 rand()
10^18コールごとに1回。
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;
見る man 3 rand
- 分割してスケーリングする必要があります RAND_MAX
範囲[0、1]を取得し、その後、ターゲット範囲に100を掛けることができます。
最小値(包括的)までの範囲の場合、使用してください。 int result = rand() % (max - min + 1) + min;
どのくらい答えが欲しいですか。
最も簡単なのは、101で割った場合、残りを使用して変換することです。
int value = rawRand % 101;
セミプリストはダブルスを使用して再販売します。
double dbl = 100 * ((double)rawRand / RAND_MAX);
int ivalue = (int)(dbl + 0.5); // round up for above 0.5
そして、純粋主義者は、ランドが乱数を生成しないと言うでしょう。
あなたの情報については、乱数の品質は、一連の数値を取得し、そのシーケンスのソースがランダムであるという数学的確率を計算することにより測定されます。残りを使用した単純なハックは、ランダム性を発生させた場合、非常に貧弱な選択です。
一部の人々は、次のコードを例として投稿しました。
int rawRand = (rand() / RAND_MAX) * 100;
これは、RAND()とRAND_MAXの両方が整数であるため、問題を解決する無効な方法です。 C ++では、これにより積分分割が生じ、結果が小数点を切り捨てます。 rand_max> = rand()として、その操作の結果は1または0のいずれかです。つまり、rawRandは0または100しかできません。これを行う正しい方法は次のとおりです。
int rawRand = (rand() / static_cast<double>(RAND_MAX)) * 100;
オペランドがダブルであるため、フローティングポイント除算が使用されるため、0〜1の間の適切な値を返します。
RawRand%101は[0-100]を包括的に与えます。