web-dev-qa-db-ja.com

Rand()から特定の範囲の数値を取得するにはどうすればよいですか?

srand(time(null));

printf("%d", Rand());

高範囲の乱数(0-32000ish)を与えますが、どうすればいいかわかりませんが、必要なのは0-63または0-127だけです。助けがありますか?

33
akway
Rand() % (max_number + 1 - minimum_number) + minimum_number

したがって、0-65の場合:

Rand() % (65 + 1 - 0) + 0

(明らかに0をオフのままにすることができますが、完全を期すためにあります)。

これはランダム性をわずかに偏らせることに注意してください。ただし、特に繊細なことをしていない場合は心配する必要はありません。

57
Tyler McHenry

ここで確認してください

http://c-faq.com/lib/randrange.html

これらの手法のいずれについても、必要に応じて範囲をシフトするのは簡単です。 [M、N]の範囲の数値は、次のようなもので生成できます。

M + Rand() / (Rand_MAX / (N - M + 1) + 1)
16
fnurglewitz

これを使用できます:

int random(int min, int max){
   return min + Rand() / (Rand_MAX / (max - min + 1) + 1);
}

から:

comp.lang.c FAQリスト・質問13.16

Q:特定の範囲の整数をランダムに取得するにはどうすればよいですか?

A:明白な方法、

Rand() % N        /* POOR */

(0からN-1までの数字を返そうとする)は、多くの乱数ジェネレーターの下位ビットが悲惨なほど非ランダムであるため、貧弱です。 (質問 13.18 を参照してください。)より良い方法は次のようなものです

(int)((double)Rand() / ((double)Rand_MAX + 1) * N)

浮動小数点を使用したくない場合は、別の方法があります

Rand() / (Rand_MAX / N + 1)

確率1/Nで何かを行う必要がある場合は、

if(Rand() < (Rand_MAX+1u) / N)

これらの方法はすべて、Rand_MAX(<stdlib.h>でANSIが定義している)を知る必要があり、NがRand_MAXよりもはるかに小さいと想定しています。 NがRand_MAXに近く、乱数発生器の範囲がNの倍数でない場合(つまり(Rand_MAX + 1)%N!= 0の場合)、これらの方法はすべて故障します。その他。 (浮動小数点を使用しても効果はありません。問題は、RandがRand_MAX + 1個の個別の値を返すことです。これは常にNバケットに均等に分割することはできません。)これが問題である場合、できることはRand multiple特定の値を破棄する:

unsigned int x = (Rand_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;
do {
  r = Rand();
} while(r >= y);
return r / x;

これらの手法のいずれについても、必要に応じて範囲をシフトするのは簡単です。 [M、N]の範囲の数値は、次のようなもので生成できます。

M + Rand() / (Rand_MAX / (N - M + 1) + 1)

(ちなみに、Rand_MAXはconstantであり、Cライブラリの固定範囲Rand関数です。Rand_MAXを他の値に設定することはできません。また、Randが他の範囲の数値を返すように要求する方法はありません。

0から1までの浮動小数点値を返す乱数ジェネレーターから始めている場合(PMrandの最後のバージョンなど) 13.15 、または問題のdrand48 13.21 )、0からN-1の整数を取得するために必要なことは、そのジェネレータの出力にNを掛けることだけです。

(int)(drand48() * N)

追加リンク

参照:K&R2 Sec。 7.8.7 p。 168
PCS秒。 11ページ172

引用元: http://c-faq.com/lib/randrange.html

10
Vitim.us

他のポスターが主張しているように、結果のモジュロを取ると、ほぼランダムな何かが得られますが、完全にそうではありません。

この極端な例を考えてみましょう。コイントスをシミュレートし、0または1を返すとします。これを行うことができます。

isHeads = ( Rand() % 2 ) == 1;

無害に見えますよね? Rand_MAXが3のみであると仮定します。もちろん、はるかに高くなりますが、ここでのポイントは、Rand_MAXを均等に分割しないモジュラスを使用するとバイアスがかかることです。高品質の乱数が必要な場合、問題が発生します。

私の例を考えてみましょう。可能な結果は次のとおりです。

Rand()  freq. Rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0

したがって、「テール」は「ヘッド」の2倍の頻度で発生します。

アトウッド氏はこの問題について議論します このコーディングホラー記事で

6
Bob Kaufman

他の人が指摘したように、単にモジュラスを使用すると、個々の数値の確率が歪められ、より小さい数値が優先されます。

その問題に対する非常に独創的で優れた解決策がJavaの Java.util.Random クラス:

public int nextInt(int n) {
    if (n <= 0)
        throw new IllegalArgumentException("n must be positive");

    if ((n & -n) == n)  // i.e., n is a power of 2
        return (int)((n * (long)next(31)) >> 31);

    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n-1) < 0);
    return val;
}

なぜそれが機能するのかを理解するのに少し時間がかかりました。それを読者の演習として残しておきますが、数字が等しい確率になるようにするかなり簡潔なソリューションです。

そのコードの重要な部分はwhileループの条件です。これは、そうでなければ不均一な分布をもたらすような数値の範囲に収まる数値を拒否します。

5
Joey

#defineを使用しないように更新

double Rand(double min, double max)
{
    return (double)Rand()/(double)Rand_MAX * (max - min) + min;
}
3
Mark Synowiec
double scale = 1.0 / ((double) Rand_MAX + 1.0);
int min, max;
...
rval = (int)(Rand() * scale * (max - min + 1) + min);
3
John Bode

低次ビットの「ランダム性」を過度に気にしない場合は、Rand()%HI_VALだけです。

また:

(double)Rand() / (double)Rand_MAX;  // lazy way to get [0.0, 1.0)
2
genpfault

単純な方法は次のとおりです。

int myRand = Rand() % 66; // for 0-65

これは非常にわずかに不均一な分布になる可能性があります(最大値に依存します)が、かなり近いです。

なぜ完全に均一ではないのかを説明するために、この非常に単純化された例を考えてみましょう。
Rand_MAXが4で、0〜2の数字が必要だとします。取得可能な値を次の表に示します。

Rand()   |  Rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0

問題が発生しましたか?最大値がRand_MAXの偶数除数でない場合、小さな値を選択する可能性が高くなります。ただし、Rand_MAXは一般に32767であるため、ほとんどの場合、バイアスは十分小さい可能性があります。

この問題を回避するにはさまざまな方法があります。 JavaのRandomによる処理方法の説明については、 here を参照してください。

2
Michael Myers

Rand() は、0からRand_MAXまでの数値(少なくとも32767)を返します。

範囲内の数値を取得する場合は、モジュロを使用できます。

int value = Rand() % 66; // 0-65

より正確にするには、 この記事をご覧ください 。モジュロが必ずしも良いとは限らない理由(特にハイエンドでの悪い分布)について説明し、さまざまなオプションを提供します。

1
Reed Copsey

この答えは、ランダム性ではなく、算術順序に焦点を当てています。範囲内の数値を取得するには、通常、次のようにします。

// the range is between [aMin, aMax]
double f = (double)Rand() / Rand_MAX;
double result = aMin + f * (aMax - aMin);

ただし、(aMax-aMin)がオーバーフローする可能性があります。例えば。 aMax = 1、aMin = -DBL_MAX。より安全な方法は、次のように書くことです。

// the range is between [aMin, aMax]
double f = (double)Rand() / Rand_MAX;
double result = aMin - f * aMin + f * aMax;

この概念に基づいて、このような何かが問題を引き起こす可能性があります。

Rand() % (max_number + 1 - minimum_number) + minimum_number
// 1. max_number + 1 might overflow
// 2. max_number + 1 - min_number might overflow
1
QQVEI

Rand()を使用するだけで、プログラムを複数回実行するときに同じ乱数が得られます。つまり、プログラムを初めて実行すると、乱数x、y、zが生成されます。プログラムを再度実行すると、私が観測したのと同じx、y、z番号が生成されます。

毎回一意に保つことがわかった解決策は、srand()を使用することです

追加のコードは次のとおりです。

#include<stdlib.h>
#include<time.h>

time_t t;
srand((unsigned) time(&t));
int Rand_number = Rand() % (65 + 1 - 0) + 0 //i.e Random numbers in range 0-65.

範囲を設定するには、次の式を使用できます:Rand()%(max_number + 1-minimum_number)+ minimum_number

それが役に立てば幸い!

0
Jay Mehta
2 cents (ok 4 cents):

n = Rand()
x = result
l = limit

n/Rand_MAX = x/l

Refactor:

(l/1)*(n/Rand_MAX) = (x/l)*(l/1)

Gives:

x = l*n/Rand_MAX

int randn(int limit)

{

    return limit*Rand()/Rand_MAX;

}

int i;

for (i = 0; i < 100; i++) { 

    printf("%d ", randn(10)); 
    if (!(i % 16)) printf("\n"); 

}

> test
0
5 1 8 5 4 3 8 8 7 1 8 7 5 3 0 0
3 1 1 9 4 1 0 0 3 5 5 6 6 1 6 4
3 0 6 7 8 5 3 8 7 9 9 5 1 4 2 8
2 7 8 9 9 6 3 2 2 8 0 3 0 6 0 0
9 2 2 5 6 8 7 4 2 7 4 4 9 7 1 5
3 7 6 5 3 1 2 4 8 5 9 7 3 1 6 4
0 6 5
0
Scott Franco

既存の回答に詳細を追加するだけです。

Mod %演算は常に完全な除算を実行するため、除数よりも小さい剰余を生成します。

x%y = x-(y * floor((x/y)))

コメント付きのランダム範囲検索関数の例:

uint32_t Rand_range(uint32_t n, uint32_t m) {
    // size of range, inclusive
    const uint32_t length_of_range = m - n + 1;

    // add n so that we don't return a number below our range
    return (uint32_t)(Rand() % length_of_range + n);
}

上記の別の興味深いプロパティ:

x%y = x、x <yの場合

const uint32_t value = Rand_range(1, Rand_MAX); // results in Rand() % Rand_MAX + 1
// TRUE for all x = Rand_MAX, where x is the result of Rand()
assert(value == Rand_MAX);
result of Rand()
0
wulfgarpro

乱数の品質を気にする場合は、Rand()を使用しないでください

http://en.wikipedia.org/wiki/Mersenne_twister のような他のprngを使用するか、または他の高品質prngを使用します。

次に、モジュラスを使用します。

0
Spudd86