7

問題は、0 から 999 までのランダムな整数を生成する必要があることです (数学的な推測を調査するため)。すべての値が出現する確率が同じである必要があります。

私は を試しrand()ましたが、RAND_MAX(私のコンパイラでは) 32767 であるrand() % 1000ため、最初の 1–767 が発生する可能性が大幅に高くなることを意味します (rand()そもそも、すべての可能性が同じ確率であると仮定しています)。

私はWindowsを使用して/dev/randomいるので、オプションではありません。

4

6 に答える 6

24

uniform_int_distributionC++11を使用すると、次のようなことができます。

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 999);

    for (int n=0; n<1000; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}
于 2013-04-22T17:59:56.903 に答える
10

あなたの弾性率の観察は正しく、数学的な精査に耐えられないいくつかの理由の1つです。rand()ここのメモから

生成されるランダム シーケンスの品質については保証されません。過去に、いくつかの rand() の実装は、生成されるシーケンスのランダム性、分布、および周期に深刻な欠点がありました (1 つのよく知られた例では、下位ビットが呼び出し間で 1 と 0 の間で単純に交互になりました)。rand() は、暗号化などの深刻な乱数生成のニーズにはお勧めできません。

C++11 では、目的に適している可能性が高い、より厳密な標準を保持するいくつかの新しい乱数ジェネレーターが導入されています。

数バイト以上のオーバーヘッドを犠牲にできる場合 (できると仮定しても安全です)、私はお勧めします。std::mersenne_twister_engine

于 2013-04-22T18:00:08.580 に答える
3

これを行う最も簡単な方法は、 interval 内の数字を捨てて、残りの数字に[32000, 32767]のみ適用することだと思います。% 1000これにより、より均一な分布が得られるはずです。

または、boost のランダム/均一分布コンポーネント (または、利用可能な場合は C++11 から) を使用することもできますrand

于 2013-04-22T17:59:43.887 に答える
1

問題は、 rand() がドメイン上で均一に分散された変数を提供すること[0,RAND_MAX]でありRAND_MAX、最も可能性が高いのは 32767 です。単純な乗算によって、このドメインをより大きなドメインにマップすることはできません。

u=(double)rand();
d=(double)RAND_MAX;
double div= u/d;
double res=div*interval_range;

これは、RAND_MAX が の偶数倍である場合にのみ正しいためですinterval_range。ただし、その場合、より大きなドメインにすべての値があるわけではありません。ただし、新しい目的のドメインがRAND_MAXあなたの場合よりも小さい場合は、によって生成された一様分布をrand()目的のドメインに切り詰めることができます (本質的にrand()、目的のドメインよりも大きい値を拒否することを意味します)。切り捨てられた一様分布はまだ一様であるため、新しいドメインに新しい一様分布変数があります (これはより正確には条件付き分布になります)。統計例:

ここに画像の説明を入力

したがって、切り捨てられた一様分布には別の「瞬間」、それを説明するパラメーター (平均、std_dev、分散など) がありますが、再び一様になります。

コード例:

int main{ 
    int o=RAND_MAX;
    std::map<int,int> m1;
    int min=0,max=999;

    for (int i=0; i<1000*9994240; ++i){//9994240=305*32768  32768=RAND_MAX+1
        int r=rand();
        if(r<=max){
            m1[r]++;
        }
    }
    for (auto & i : m1)
        std::cout << i.first << " : " << i.second << '\n';
}

結果:0:42637 1:42716 2:42590 3:42993 4:42936 5:42965 6:42941 7:42705 8:42944 9:42707 10:42860 11:43012 12:42793 // ... 995:42861 996 : 42911 997 : 42865 998 : 42877 999 : 43159


この方法で、任意のドメインで目的の結果を得ることができます。

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1000);

    for (int n=0; n<1000; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}

ただし、この場合は実際にブーストを使用する必要があります。

#include <iostream>
#include "boost/random.hpp"
#include "boost/generator_iterator.hpp"
using namespace std;

int main() {
      typedef boost::mt19937 RNGType;
      RNGType rng;
      boost::uniform_int<> zero_to_n( 0, 999 );
      boost::variate_generator< RNGType, boost::uniform_int<> >
                    dice(rng, zero_to_n);
          int n  = dice();

}
于 2013-04-22T18:04:22.477 に答える
0
  1. を使用して乱数を取得しrand()ます。

  2. で割りRAND_MAXます。0 から 1 の間の浮動小数点数を取得します。

  3. この数に 1000 を掛けます。

于 2013-04-22T18:00:24.967 に答える
0

コンピュータには「本当にランダム」というものはありません。また、1 から 767 (厳密には、この場合は 0 から 767) の可能性が他のどの数字よりも有意に高いとは考えていません。ただし、「より良い」乱数が必要な場合、C++ 11 はより高度な乱数ジェネレーターである Mersenne Twister の使用をサポートしています。

詳細はこちら: http://www.cplusplus.com/reference/random/mt19937/

于 2013-04-22T18:00:53.003 に答える