C ++でランダムな二重数を生成する


83

C ++で2つのdoubleの間に乱数を生成する方法、これらの数値はxxxxx、yyyyyのようになります。


6
「これらの番号はxxxxx、yyyyyのようになります」。ランダムなdoubleを生成する方法と、doubleを文字列としてフォーマットする方法は、完全に別の問題です。
Steve Jessop 2010

代わりに考えてみてください。均等に分散されたdoubleの生成と、均等に分散されたdecimalの生成は、関連はありますが、タスクが多少異なります。
Steve Jessop 2010

均等に分散された整数の生成は、小数の問題とより密接に関連しています。
ポテトスワッター2010

回答:


116

方法は次のとおりです

double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX;
    return fMin + f * (fMax - fMin);
}

プログラムを開始するたびに、適切なシードを使用してsrand()を呼び出すことを忘れないでください。

[編集] C ++がネイティブの非Cベースのランダムライブラリを取得したため、この回答は廃止されました(Alessandro Jacopsonsの回答を参照)。ただし、これはCにも当てはまります。


10
RAND_MAXに1を追加する場合は、INT_MAXと等しい可能性があるため、慎重に行ってください。double f = rand() / (RAND_MAX + 1.0);
Steve Jessop 2010

8
これのランダム性は制限される可能性があることに注意してください。xxxxx、yyyyyの範囲は、10進数の10桁を示します。RAND_MAXが10 ^ 10よりも小さいシステムはたくさんあります。これは、その範囲内のいくつかの数値がp(xxxxx,yyyyy)==0.0
MSalters 2010

7
可能であれば、rand()は避けてください。C ++ 11またはTR1ソリューションについては、他の回答を参照してください。
jfritz42 2014

誰もがC ++ 0x、tr1、またはC ++ 11を使用しているわけではありません。rand()を回避する必要があることを示す参照はありますか?何十年もの間、乱数を取得する唯一の方法でした。
rep_movsd 2014

1
@ ChamilaWijayarathna、cstdlibを含める必要があります
Veridian 2015年

103

このソリューションには、C ++ 11(またはTR1)が必要です。

#include <random>

int main()
{
   double lower_bound = 0;
   double upper_bound = 10000;
   std::uniform_real_distribution<double> unif(lower_bound,upper_bound);
   std::default_random_engine re;
   double a_random_double = unif(re);

   return 0;
}

詳細については、John D.Cookの「C ++ TR1を使用した乱数生成」を参照してください。

Stroustrupの「乱数生成」も参照してください。


7
これを最新のcppreferenceドキュメントで更新することをお勧めします。これはかなり良いことです。
Shafik Yaghmour 2013

10

これは、パフォーマンスが高く、スレッドセーフで、多くの用途に十分な柔軟性を備えている必要があります。

#include <random>
#include <iostream>

template<typename Numeric, typename Generator = std::mt19937>
Numeric random(Numeric from, Numeric to)
{
    thread_local static Generator gen(std::random_device{}());

    using dist_type = typename std::conditional
    <
        std::is_integral<Numeric>::value
        , std::uniform_int_distribution<Numeric>
        , std::uniform_real_distribution<Numeric>
    >::type;

    thread_local static dist_type dist;

    return dist(gen, typename dist_type::param_type{from, to});
}

int main(int, char*[])
{
    for(auto i = 0U; i < 20; ++i)
        std::cout << random<double>(0.0, 0.3) << '\n';
}

7

ここで精度が問題になる場合は、重要なビットをランダム化することで、より細かい目盛りで乱数を作成できます。0.0から1000.0の間にダブルが必要だとしましょう。

MSVC(12 / Win32)では、たとえばRAND_MAXは32767です。

一般的なrand()/RAND_MAXスキームを使用する場合、ギャップは次のように大きくなります

1.0 / 32767.0 * ( 1000.0 - 0.0) = 0.0305 ...

IEE 754二重変数(53の有効ビット)と53ビットのランダム化の場合、0〜1000の問題で可能な最小のランダム化ギャップは次のようになります。

2^-53 * (1000.0 - 0.0) = 1.110e-13

したがって、大幅に低くなります。

欠点は、乱数化された整数を取得するために4つのrand()呼び出しが必要になることです(15ビットのRNGを想定)。

double random_range (double const range_min, double const range_max)
{
  static unsigned long long const mant_mask53(9007199254740991);
  static double const i_to_d53(1.0/9007199254740992.0);
  unsigned long long const r( (unsigned long long(rand()) | (unsigned long long(rand()) << 15) | (unsigned long long(rand()) << 30) | (unsigned long long(rand()) << 45)) & mant_mask53 );
  return range_min + i_to_d53*double(r)*(range_max-range_min);
}

仮数またはRNGのビット数が不明な場合は、関数内でそれぞれの値を取得する必要があります。

#include <limits>
using namespace std;
double random_range_p (double const range_min, double const range_max)
{
  static unsigned long long const num_mant_bits(numeric_limits<double>::digits), ll_one(1), 
    mant_limit(ll_one << num_mant_bits);
  static double const i_to_d(1.0/double(mant_limit));
  static size_t num_rand_calls, rng_bits;
  if (num_rand_calls == 0 || rng_bits == 0)
  {
    size_t const rand_max(RAND_MAX), one(1);
    while (rand_max > (one << rng_bits))
    {
      ++rng_bits;
    }
    num_rand_calls = size_t(ceil(double(num_mant_bits)/double(rng_bits)));
  }
  unsigned long long r(0);
  for (size_t i=0; i<num_rand_calls; ++i)
  {
    r |= (unsigned long long(rand()) << (i*rng_bits));
  }
  r = r & (mant_limit-ll_one);
  return range_min + i_to_d*double(r)*(range_max-range_min);
}

注:unsigned long long(64ビット)のビット数が、すべてのプラットフォームの二重仮数ビット(IEE 754の場合は53ビット)の数よりも多いかどうかはわかりません。if (sizeof(unsigned long long)*8 > num_mant_bits) ...そうでない場合のようにチェックを含めるのはおそらく「賢い」でしょう。


3

このスニペットは、StroustrupのC ++プログラミング言語(第4版)、§40.7から直接引用したものです。C ++ 11が必要です。

#include <functional>
#include <random>

class Rand_double
{
public:
    Rand_double(double low, double high)
    :r(std::bind(std::uniform_real_distribution<>(low,high),std::default_random_engine())){}

    double operator()(){ return r(); }

private:
    std::function<double()> r;
};

#include <iostream>    
int main() {
    // create the random number generator:
    Rand_double rd{0,0.5};

    // print 10 random number between 0 and 0.5
    for (int i=0;i<10;++i){
        std::cout << rd() << ' ';
    }
    return 0;
}

0

このようなもの:

#include <iostream>
#include <time.h>

using namespace std;

int main()
{
    const long max_rand = 1000000L;
    double x1 = 12.33, x2 = 34.123, x;

    srandom(time(NULL));

    x = x1 + ( x2 - x1) * (random() % max_rand) / max_rand;

    cout << x1 << " <= " << x << " <= " << x2 << endl;

    return 0;
}

2
"(random()%max_rand)" = "random()"(つまり、3%7 = 3)。これは無駄な処理ステップになります。
ザック2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.