генерувати випадкові подвійні числа в C ++


83

Як генерувати випадкові числа між двома подвійними в c ++, ці числа повинні мати вигляд xxxxx, yyyyy.


6
"ці цифри мають виглядати як ххххх, ррррр". Як генерувати випадкові подвійні та як форматувати подвійні як рядки - це абсолютно окремі питання.
Steve Jessop

І якщо подумати про це альтернативно: генерування рівномірно розподілених подвійних значень та генерування рівномірно розподілених десяткових знаків є дещо різними, хоча і пов’язаними, завданнями.
Steve Jessop

Генерування рівномірно розподілених цілих чисел більш тісно пов'язане з проблемою десяткових знаків.
Potatoswatter

Відповіді:


116

Ось як

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

Не забувайте викликати srand () із відповідним початковим елементом кожного разу, коли запускається ваша програма.

[Редагувати] Ця відповідь застаріла, оскільки C ++ отримав власну випадкову бібліотеку, що не базується на C (див. Відповідь Алессандро Якопсона) Але, це все ще стосується C


10
Якщо ви додаєте 1 до RAND_MAX, робіть це обережно, оскільки воно може дорівнювати INT_MAX. double f = rand() / (RAND_MAX + 1.0);
Steve Jessop

8
Зауважте, що випадковість цього може бути обмежена. Діапазон xxxxx, yyyyy пропонує 10 десяткових цифр. Існує безліч систем, де RAND_MAX менше 10 ^ 10. Це означало б, що деякі цифри в цьому діапазоні єp(xxxxx,yyyyy)==0.0
MSalters

7
Вам слід уникати rand (), якщо це можливо. Іншу відповідь див. На рішення C ++ 11 або TR1.
jfritz42

Не всі використовують C ++ 0x, tr1 або C ++ 11. Чи існує посилання, яке показує, що rand () слід уникати? Це був єдиний спосіб отримати випадкові числа протягом десятиліть.
rep_movsd

1
@ChamilaWijayarathna, Вам потрібно включити cstdlib
Veridian

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;
}

Детальніше див. У статті Джона Д. Кука "Виробництво випадкових чисел за допомогою C ++ TR1" .

Див. Також "Створення генератора випадкових чисел" .


7
Можливо, ви захочете оновити це новішим документом cppreference , що є досить непоганим.
Шафік Ягмор

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

а отже суттєво нижчий.

Недоліком є ​​те, що для отримання рандомізованого цілого числа (припускаючи 15-бітний RNG) буде потрібно 4 виклики rand ().

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);
}

Примітка: Я не знаю, чи перевищує кількість бітів для long unsigned long (64 біт), ніж кількість бітів подвійної мантиси (53 біта для IEE 754) на всіх платформах чи ні. Можливо, було б «розумно» включити чек, if (sizeof(unsigned long long)*8 > num_mant_bits) ...якби це не так.


3

Цей фрагмент безпосередньо наведено в мові програмування C ++ від Stroustrup (4th Edition) , §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). Це був би марний крок обробки.
Зак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.