15

だから、私はランダムなベクトルを作成しようとしています (拡張可能な配列ではなく、ジオメトリを考えてください)。ランダムなベクトル関数を呼び出すたびに、y と z は異なりますが、同じ x 値を取得します。

int main () {
    srand ( (unsigned)time(NULL));
    Vector<double> a;
    a.randvec();
    cout << a << endl;
    return 0;
}

関数を使用して

//random Vector
template <class T>
void Vector<T>::randvec()
{
    const int min=-10, max=10;
    int randx, randy, randz;

    const int bucket_size = RAND_MAX/(max-min);

    do randx = (rand()/bucket_size)+min;
    while (randx <= min && randx >= max);
    x = randx;

    do randy = (rand()/bucket_size)+min;
    while (randy <= min && randy >= max);
    y = randy;

    do randz = (rand()/bucket_size)+min;
    while (randz <= min && randz >= max);
    z = randz;
}

何らかの理由で、randx は一貫して 8 を返しますが、他の数値は (疑似) ランダム性に完全に従っているようです。ただし、たとえば randy を定義する呼び出しを randx の前に置くと、randy は常に 8 を返します。

最初の乱数が常に 8 になるのはなぜですか? シードが間違っていますか?

4

7 に答える 7

9

問題は、乱数ジェネレーターに非常に近い値がシードされていることです。プログラムを実行するたびに、time() の戻り値がわずかに変化するだけです。おそらく 1 秒か、まったく変化しません! 次に、かなり貧弱な標準の乱数ジェネレーターが、これらの同様のシード値を使用して、明らかに同一の初期乱数を生成します。基本的に、time() よりも優れた初期シード ジェネレーターと、rand() よりも優れた乱数ジェネレーターが必要です。

使用される実際のループ アルゴリズムは、Accelerated C++ から持ち上げられたと思います。これは、mod 演算子を使用するよりも、必要な範囲で数値をより適切に分散させることを目的としています。しかし、常に (事実上) 同じシードが与えられることを補うことはできません。

于 2010-06-13T16:00:58.640 に答える
5

に問題は見られません。srand()また、非常によく似たコードを実行しようとしたときに、最初の で同じ番号を繰り返し取得することはありませんでしたrand()。ただし、別の問題が発生する可能性があることに気付きました。

do randx = (rand()/bucket_size)+min;
while (randx <= min && randx >= max);

この行は、意図したとおりに動作しない可能性があります。である限りmin < max(常にそうあるべきです)、 がrandxより小さいか等しいかmin、より大きいか等しいの両方になることは不可能ですmax。さらに、ループする必要はまったくありません。代わりに、次を使用して最小値と最大値の間の値を取得できます。

randx = rand() % (max - min) + min;
于 2010-06-13T15:34:08.977 に答える
4

私はまったく同じ問題を抱えていました。srand() 呼び出しを移動して、プログラムで一度だけ呼び出されるように修正しました (以前は、関数呼び出しの先頭にシードしていました)。技術的なことはよくわかりませんが、問題は解決しました。

于 2012-02-22T14:32:57.570 に答える
3

また、その奇妙な変数を取り除きbucket_size、次の方法を使用して から までの数値ab包括的に生成することもできます。

srand ((unsigned)time(NULL));

const int a = -1;
const int b = 1;

int x = rand() % ((b - a) + 1) + a;
int y = rand() % ((b - a) + 1) + a;
int z = rand() % ((b - a) + 1) + a;
于 2010-06-13T15:33:25.307 に答える
2

rand簡単なクイックフィックスは、シード後に数回呼び出すことです。

int main ()
{
    srand ( (unsigned)time(NULL));
    rand(); rand(); rand();

    Vector<double> a;
    a.randvec();
    cout << a << endl;
    return 0;
}

説明をわかりやすくするために、テストプログラムを4回連続して実行してrand()を最初に呼び出すと、次の出力が得られました。

27592
27595
27598
27602

それらがどれほど似ているかに気づきましたか?たとえば、rand()100で割ると、同じ数が3回続けて得られます。次に、4回の連続実行でのrand()の2番目の結果を見てみましょう。

11520
22268
248
10997

これはずっと良く見えますね?反対票の理由は本当にわかりません。

于 2010-06-13T15:26:14.107 に答える
1

実装では、整数除算により、乱数の最小の 4 ~ 5 ビットが無視されます。RNG はシステム時間でシードされるため、最初に得られる値は (平均して) 20 秒ごとにしか変化しません。

これはうまくいくはずです:

randx = (min) + (int) ((max - min) * rand() / (RAND_MAX + 1.0));

どこ

rand() / (RAND_MAX + 1.0)

[0, 1) のランダムな double 値であり、残りはそれをシフトするだけです。

于 2010-06-13T16:17:49.007 に答える