генерировать случайные двойные числа в c ++


83

Как сгенерировать случайные числа между двумя двойниками в C ++, эти числа должны выглядеть как xxxxx, yyyyy.


6
«эти числа должны выглядеть как xxxxx, yyyyy». Как создавать случайные двойники и как форматировать двойники как строки - это совершенно разные вопросы.
Стив Джессоп,

И подумайте об этом иначе : генерация равномерно распределенных чисел двойной точности и генерация равномерно распределенных десятичных чисел - несколько разные, хотя и связанные, задачи.
Стив Джессоп,

Генерация равномерно распределенных целых чисел более тесно связана с проблемой десятичных дробей.
Potatoswatter

Ответы:


116

Вот как

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

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

[Edit] Этот ответ устарел, поскольку в C ++ есть собственная случайная библиотека, не основанная на C (см. Ответ Алессандро Якопсона). Но это все еще относится к C


10
Если вы добавляете 1 к RAND_MAX, делайте это осторожно, так как он может быть равен INT_MAX. double f = rand() / (RAND_MAX + 1.0);
Стив Джессоп,

8
Обратите внимание, что случайность этого может быть ограничена. Диапазон xxxxx, yyyyy предполагает 10 десятичных цифр. Существует множество систем, в которых RAND_MAX меньше 10 ^ 10. Это будет означать, что некоторые числа в этом диапазоне имеютp(xxxxx,yyyyy)==0.0
MSalters

7
По возможности следует избегать rand (). См. Другой ответ для решения C ++ 11 или TR1.
jfritz42 04

Не все используют C ++ 0x, tr1 или C ++ 11. Следует ли избегать ссылок на rand ()? Это был единственный способ получить случайные числа на протяжении десятилетий.
rep_movsd 05

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 , что очень хорошо.
Shafik Yaghmour

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-битного ГСЧ).

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

Если количество битов для мантиссы или ГСЧ неизвестно, соответствующие значения должны быть получены в функции.

#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 бит), чем количество битов двойной мантиссы (53 бит для IEE 754) на всех платформах или нет. Вероятно, было бы "разумно" включить проверку, как if (sizeof(unsigned long long)*8 > num_mant_bits) ...будто это не так.


3

Этот фрагмент взят прямо из языка программирования 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). Это был бы бесполезный этап обработки.
Zak
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.