Случайное вещественное число в [0..1[ с использованием Mersenne Twister

Я пытаюсь создать модель зомби-апокалипсиса на С++, используя простые структуры, и когда я рандомизирую население, мне нужно, чтобы некоторые поля структуры имели значение в интервале [0..1[. Поскольку меня интересует более статистически корректный анализ, я решил использовать движок mt19937 для генерации своих «данных». Играя с этим PRNG, я не смог найти способ сгенерировать число в указанном диапазоне. Вот код, который я придумал:

int
main ( int argc, char** argv )
{

    mt19937_64 newr ( time ( NULL ) );
    std::cout << newr.max ( ) << endl;
    std::cout << newr.min ( );
    double rn;
    for(;;){
        rn = newr()/newr.max ();
        std::cout << rn << std::endl;
    }
}

Но единственные результаты, которые я получаю для цикла, - это нули (0). Небольшой отпечаток вывода не работает:

18446744073709551615
0
0
0
0
0
0
0
0
0
0
0

Любые идеи?


person Pedro    schedule 30.12.2014    source источник
comment
Используйте 1_.   -  person Jonathan Potter    schedule 31.12.2014


Ответы (2)


Это происходит потому, что возвращаемое значение newr() и newr.max() является целым числом, а значение, возвращаемое newr(), меньше, чем newr.mar(). Результатом деления является нулевое целое число, которое затем преобразуется в double. Чтобы исправить это, используйте

rn = static_cast<double>(newr()) / newr.max();
person Captain Obvlious    schedule 30.12.2014
comment
Большое спасибо, как только смогу, я отмечу это как правильный ответ. Я должен был подумать об этом раньше, лол. - person Pedro; 31.12.2014
comment
Лучше бы сделали static_cast<double>(foo), наверное. - person Alex Reynolds; 31.12.2014
comment
@AlexReynolds Просто чтобы быть идолом, конечно; p - person Captain Obvlious; 31.12.2014
comment
Я думаю, что более новые версии clang++ будут задыхаться от приведения в стиле (double)foo. Подход static_cast может быть более перспективным. YMMV. - person Alex Reynolds; 31.12.2014
comment
@AlexReynolds: зачем им давиться действительным кодом C++? - person Rufflewind; 31.12.2014
comment
Кроме того, в чем разница между использованием static_cast‹double› и просто (double). Разве GCC (компилятор, который я использую) не компилирует оба одинаково? - person Pedro; 31.12.2014
comment
Извините, возможно, дроссель слишком сильный. Такой тип приведения может вызвать предупреждение о компиляции «предупреждение: использование приведения в старом стиле». Предупреждения обычно полезно исправлять. Педро, следующий вопрос и ответ SO кратко объясняет приведение в стиле С++, включая static_cast<>: stackoverflow.com/a/5249436/19410 - person Alex Reynolds; 31.12.2014
comment
В следующем ответе SO более подробно рассказывается о приведениях в старом стиле (C) и о том, почему рекомендуется привыкнуть избегать их в коде C++: stackoverflow.com/a/332086/19410 - person Alex Reynolds; 31.12.2014
comment
@Pedro, это не даст равномерного распределения, в частности, 1.0 встречается крайне редко, чем любая другая комбинация битов. По какой причине вы не используете для этого обертки стандартной библиотеки? - person Mark Ransom; 31.12.2014
comment
@MarkRansom AFIC mt19937 должен давать гораздо более равномерное распределение по сравнению со стандартным «rand()». Я думаю, что у меня есть некоторые недостатки в изучении C/C++, что такое оболочки? - person Pedro; 31.12.2014
comment
@Pedro Педро Я говорю о классах в заголовке <random>, они предназначены для использования с mt19937. В частности, std::uniform_real_distribution. Проблема не в распределении двигателей, а в том, как они сопоставляются с диапазоном. uniform_real_distribution обходит проблему, полностью исключая конец диапазона. - person Mark Ransom; 31.12.2014
comment
@MarkRansom Когда я читал документацию по этим классам, я немного запутался и попытался упростить ее. Это всего лишь личный проект. Мой следующий шаг — заставить GSL работать на моем компьютере с Windows, а затем я просто воспользуюсь обычным дистрибутивом GSL. Но спасибо за объяснение! - person Pedro; 31.12.2014

Вы делите int на int и таким образом округляете целое число.

Способ использования случайного движка - один из различных дистрибутивов, в вашем случае std::uniform_real_distribution:

std::mt19937_64 engine ( time ( NULL ) );
std::uniform_real_distribution<double> dist(0., 1.);
for(;;){
    const double rn = dist(engine);
    std::cout << rn << std::endl;
}
person Jarod42    schedule 31.12.2014