Мне нужно сгенерировать случайные числа в пределах указанного интервала [макс; мин].
Кроме того, случайные числа должны быть равномерно распределены по интервалу, а не находиться в определенной точке.
В настоящее время я генерирую как:
for(int i=0; i<6; i++)
{
DWORD random = rand()%(max-min+1) + min;
}
Согласно моим тестам, случайные числа генерируются только около одной точки.
Example
min = 3604607;
max = 7654607;
Генерируются случайные числа:
3631594
3609293
3630000
3628441
3636376
3621404
Из ответов ниже: ОК, RAND_MAX - 32767. Я использую платформу C ++ Windows. Есть ли другой метод генерации случайных чисел с равномерным распределением?
rand()
единообразен. Какую библиотеку вы используете?cstdlib.h
неrand()
является единообразным: cplusplus.com/reference/cstdlib/randОтветы:
Почему
rand
плохая идеяБольшинство ответов, которые вы здесь получили, используют
rand
функцию и оператор модуля. Этот метод может не генерировать числа равномерно (это зависит от диапазона и значенияRAND_MAX
), и поэтому не рекомендуется.C ++ 11 и генерация в диапазоне
В C ++ 11 появилось множество других возможностей. Один из которых соответствует вашим требованиям, для генерации случайного числа в диапазоне, довольно хорошо:
std::uniform_int_distribution
. Вот пример:const int range_from = 0; const int range_to = 10; std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<int> distr(range_from, range_to); std::cout << distr(generator) << '\n';
А вот работающий пример.
Функция шаблона может помочь некоторым:
template<typename T> T random(T range_from, T range_to) { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<T> distr(range_from, range_to); return distr(generator); }
Другие генераторы случайных чисел
В
<random>
Заголовок предлагает бесчисленное множество других генераторов случайных чисел с различными видами распределений , включая Бернулли, Пуассона и нормальное.Как перетасовать контейнер?
Стандарт предусматривает
std::shuffle
, что можно использовать следующим образом:std::vector<int> vec = {4, 8, 15, 16, 23, 42}; std::random_device random_dev; std::mt19937 generator(random_dev()); std::shuffle(vec.begin(), vec.end(), generator);
Алгоритм будет переупорядочивать элементы случайным образом с линейной сложностью.
Boost.Random
Другой альтернативой, если у вас нет доступа к компилятору C ++ 11 +, является использование Boost.Random . Его интерфейс очень похож на интерфейс C ++ 11.
источник
mt19937
тип?1 9 6 2 8 7 1 4 7 7
. Вы как рандомизируете это каждый раз, когда мы запускаем программу?[править] Предупреждение: не используйте
rand()
для статистики, моделирования, криптографии или чего-либо серьезного.Достаточно хорошо, чтобы числа выглядели случайными для обычного человека, спешащего, не более того.
См. Ответ @ Jefffrey для получения лучших вариантов или этот ответ для криптозащищенных случайных чисел.
Как правило, старшие биты показывают лучшее распределение, чем младшие, поэтому рекомендуемый способ генерации случайных чисел диапазона для простых целей:
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Примечание : убедитесь, что RAND_MAX + 1 не переполняется (спасибо Деми)!
Деление генерирует случайное число в интервале [0, 1); «растянуть» это до необходимого диапазона. Только когда max-min + 1 приближается к RAND_MAX, вам понадобится функция BigRand (), как написано Марком Рэнсомом.
Это также позволяет избежать некоторых проблем с нарезкой из-за модуля, что может еще больше ухудшить ваши числа.
Качество встроенного генератора случайных чисел не гарантирует качества, необходимого для статистического моделирования. Это нормально, что числа «выглядят случайными» для человека, но для серьезного приложения вам следует взять что-то получше - или, по крайней мере, проверить его свойства (равномерное распределение обычно хорошо, но значения имеют тенденцию коррелировать, а последовательность детерминирована. ). У Кнута есть отличный (хотя и трудный для чтения) трактат о генераторах случайных чисел, и я недавно обнаружил, что LFSR превосходен и чертовски прост в реализации, учитывая, что его свойства вам подходят.
источник
( rand() / ((double)RAND_MAX+1)) * (max-min+1) + min
просто переместите преобразование на удвоение и избегайте проблемы.Я хотел бы дополнить отличные ответы Angry Shoe и peterchen кратким обзором состояния дел в 2015 году:
Некоторые хорошие варианты
randutils
randutils
Библиотека (презентация) является интересной новинкой, предлагая простой интерфейс и (объявившего) надежные случайные возможности. У него есть недостатки, заключающиеся в том, что он добавляет зависимости от вашего проекта, и, будучи новым, он не был тщательно протестирован. В любом случае, поскольку он бесплатный (лицензия MIT) и предназначен только для заголовков, я думаю, что стоит попробовать.Минимальный образец: бросок кубика
#include <iostream> #include "randutils.hpp" int main() { randutils::mt19937_rng rng; std::cout << rng.uniform(1,6) << "\n"; }
Даже если библиотека не интересует, на веб-сайте ( http://www.pcg-random.org/ ) можно найти много интересных статей на тему генерации случайных чисел в целом и библиотеки C ++ в частности.
Boost.Random
Boost.Random
(документация) является библиотекой , которая вдохновилаC++11
«S<random>
, с которым разделяет большую часть интерфейса. Хотя теоретически также являясь внешней зависимостью,Boost
к настоящему времени имеет статус «квазистандартной» библиотеки, и ееRandom
модуль можно рассматривать как классический выбор для генерации случайных чисел хорошего качества. Он имеет два преимущества по сравнению сC++11
решением:random_device
методы использования системы , специфичные для предложения посевные хорошего качестваЕдинственный небольшой недостаток заключается в том, что модуль предлагает
random_device
не только заголовок, его нужно компилировать и связыватьboost_random
.Минимальный образец: бросок кубика
#include <iostream> #include <boost/random.hpp> #include <boost/nondet_random.hpp> int main() { boost::random::random_device rand_dev; boost::random::mt19937 generator(rand_dev()); boost::random::uniform_int_distribution<> distr(1, 6); std::cout << distr(generator) << '\n'; }
Хотя минимальный образец работает хорошо, в реальных программах следует добавить пару улучшений:
mt19937
thread_local
mt19937
с более чем одним целым числом: Mersenne Twister имеет большое состояние и может использовать больше энтропии во время инициализацииНекоторые не очень хорошие варианты
Библиотека C ++ 11
Будучи наиболее идиоматическим решением,
<random>
библиотека не предлагает многого в обмен на сложность своего интерфейса даже для базовых нужд. Недостаток заключается вstd::random_device
том, что стандарт не требует минимального качества для своего вывода (при условии, что онentropy()
возвращает0
), и с 2015 года MinGW (не самый используемый компилятор, но вряд ли эзотерический выбор) всегда будет печатать4
на минимальном образце.Минимальный образец: бросок кубика
#include <iostream> #include <random> int main() { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<int> distr(1, 6); std::cout << distr(generator) << '\n'; }
Если реализация не гнилая, это решение должно быть эквивалентно решению Boost, и применимы те же предложения.
Решение Годо
Минимальный образец: бросок кубика
#include <iostream> #include <random> int main() { std::cout << std::randint(1,6); }
Это простое, эффективное и аккуратное решение. Единственный дефект, для компиляции потребуется время - около двух лет, при условии, что C ++ 17 будет выпущен вовремя и экспериментальная
randint
функция будет утверждена в новом стандарте. Возможно, к тому времени улучшатся и гарантии качества посева.Хуже-это-лучшее решение
Минимальный образец: бросок кубика
#include <cstdlib> #include <ctime> #include <iostream> int main() { std::srand(std::time(nullptr)); std::cout << (std::rand() % 6 + 1); }
Старое решение C считается вредным, и по уважительным причинам (см. Другие ответы здесь или этот подробный анализ ). Тем не менее, у него есть свои преимущества: он простой, портативный, быстрый и честный, в том смысле, что известно, что получаемые случайные числа вряд ли являются приличными, и поэтому у человека нет соблазна использовать их для серьезных целей.
Решение бухгалтерского тролля
Минимальный образец: бросок кубика
#include <iostream> int main() { std::cout << 9; // http://dilbert.com/strip/2001-10-25 }
Хотя 9 - несколько необычный результат для обычного броска кубика, нужно восхищаться превосходным сочетанием хороших качеств в этом решении, которое оказалось самым быстрым, простым, самым удобным для кеширования и самым портативным. Заменяя 9 на 4, можно получить идеальный генератор для любого типа подземелий и гибели драконов, при этом избегая при этом обозначенных символами значений 1, 2 и 3. Единственный небольшой недостаток заключается в том, что из-за дурного настроения бухгалтерских троллей Дилберта, эта программа фактически порождает неопределенное поведение.
источник
randutils
Библиотека называется PCG Теперь.Если
RAND_MAX
32767, вы можете легко удвоить количество бит.int BigRand() { assert(INT_MAX/(RAND_MAX+1) > RAND_MAX); return rand() * (RAND_MAX+1) + rand(); }
источник
rand
вызов возвращается,0x1234
а второй0x5678
- вы получаете0x12345678
. Это единственный номер, который начинается с которого вы можете получить0x1234
, потому что следующий номер всегда будет0x5678
. Вы получаете 32-битные результаты, но у вас есть только 32768 возможных чисел.Если можете, используйте Boost . Мне повезло с их случайной библиотекой .
uniform_int
должен делать то, что хочешь.источник
uniform_int
времени. Получить непредвзятый вывод довольно легко, здесь было несколько вопросов, демонстрирующих метод.Если вас беспокоит случайность, а не скорость, вам следует использовать безопасный метод генерации случайных чисел. Есть несколько способов сделать это ... Самый простой - использовать генератор случайных чисел OpenSSL .
Вы также можете написать свой собственный, используя алгоритм шифрования (например, AES ). Выбирая начальное число и IV, а затем непрерывно повторно шифруя выходные данные функции шифрования. Использовать OpenSSL проще, но менее мужественно.
источник
Вы должны искать
RAND_MAX
свой конкретный компилятор / среду. Я думаю, вы увидите эти результаты, еслиrand()
произведете случайное 16-битное число. (похоже, вы предполагаете, что это будет 32-битное число).Я не могу обещать, что это ответ, но, пожалуйста, опубликуйте свою ценность
RAND_MAX
и немного более подробно о вашей среде.источник
Проверить что
RAND_MAX
находится в вашей системе - я предполагаю, что это всего лишь 16 бит, и ваш диапазон слишком велик для этого.Кроме того, см. Это обсуждение: Генерация случайных целых чисел в желаемом диапазоне и примечания по использованию (или нет) функции C rand () .
источник
Это не код, но эта логика может вам помочь.
static double rnd(void) { return (1.0 / (RAND_MAX + 1.0) * ((double)(rand())) ); } static void InitBetterRnd(unsigned int seed) { register int i; srand( seed ); for( i = 0; i < POOLSIZE; i++){ pool[i] = rnd(); } } // This function returns a number between 0 and 1 static double rnd0_1(void) { static int i = POOLSIZE-1; double r; i = (int)(POOLSIZE*pool[i]); r = pool[i]; pool[i] = rnd(); return (r); }
источник
Если вы хотите, чтобы числа были равномерно распределены по диапазону, вам следует разбить диапазон на несколько равных частей, которые представляют необходимое количество очков. Затем получите случайное число с минимальным / максимальным значением для каждого раздела.
В качестве еще одного примечания вам, вероятно, не следует использовать,
rand()
поскольку он не очень хорошо генерирует случайные числа. Я не знаю, на какой платформе вы работаете, но, вероятно, есть функция получше, которую вы можете назватьrandom()
.источник
Это должно обеспечить равномерное распределение по диапазону
[low, high)
без использования числа с плавающей запятой, если общий диапазон меньше RAND_MAX.uint32_t rand_range_low(uint32_t low, uint32_t high) { uint32_t val; // only for 0 < range <= RAND_MAX assert(low < high); assert(high - low <= RAND_MAX); uint32_t range = high-low; uint32_t scale = RAND_MAX/range; do { val = rand(); } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range return val/scale + low; }
а для значений больше RAND_MAX вам нужно что-то вроде
uint32_t rand_range(uint32_t low, uint32_t high) { assert(high>low); uint32_t val; uint32_t range = high-low; if (range < RAND_MAX) return rand_range_low(low, high); uint32_t scale = range/RAND_MAX; do { val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval } while (val >= range); return val + low; }
Примерно так работает std :: uniform_int_distribution.
источник
По своей природе небольшая выборка случайных чисел не должна быть равномерно распределена. В конце концов, они случайны. Я согласен с тем, что если генератор случайных чисел генерирует числа, которые последовательно кажутся сгруппированными, то, вероятно, с ним что-то не так.
Но имейте в виду, что случайность не обязательно одинакова.
Изменить: я добавил «небольшой образец», чтобы уточнить.
источник
Решение, данное man 3 rand для числа от 1 до 10 включительно:
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
В вашем случае это будет:
j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));
Конечно, это не идеальная случайность или однородность, как указывают некоторые другие сообщения, но этого достаточно для большинства случаев.
источник
@Решение
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Предупреждение : не забывайте, что из-за растяжения и возможных ошибок точности (даже если RAND_MAX было достаточно большим), вы сможете генерировать только равномерно распределенные «ячейки», а не все числа в [min, max].
@ Решение: Бигранд
Предупреждение : обратите внимание, что это удваивает биты, но по-прежнему не сможет сгенерировать все числа в вашем диапазоне в целом, т.е. не обязательно верно, что BigRand () будет генерировать все числа между в своем диапазоне.
Информация : ваш подход (по модулю) "хорош", пока диапазон rand () превышает ваш диапазон интервалов, а rand () является "равномерным". Ошибка не более чем для первых максимальных - минимальных чисел составляет 1 / (RAND_MAX +1).
Также я предлагаю переключиться на новый случайный пакет e и в C ++ 11, который предлагает лучшие и более разнообразные реализации, чем rand ().
источник
Это решение, которое я придумал:
#include "<stdlib.h>" int32_t RandomRange(int32_t min, int32_t max) { return (rand() * (max - min + 1) / (RAND_MAX + 1)) + min; }
Это бакет-решение, концептуально похожее на решения, которые используются
rand() / RAND_MAX
для получения диапазона с плавающей запятой от 0 до 1, а затем округления его в бакет. Однако он использует чисто целочисленную математику и использует преимущества целочисленного деления для округления значения до ближайшего сегмента.Делается несколько предположений. Во-первых, предполагается, что
RAND_MAX * (max - min + 1)
он всегда умещается вint32_t
. ЕслиRAND_MAX
используется 32767 и используются 32-битные вычисления int, максимальный диапазон, который вы можете иметь, равен 32767. Если ваша реализация имеет гораздо больший RAND_MAX, вы можете преодолеть это, используяint64_t
для вычисления большее целое число (например, ). Во-вторых, еслиint64_t
используется, ноRAND_MAX
по-прежнему 32767, в диапазонах больше, чемRAND_MAX
вы начнете получать «дыры» в возможных выходных числах. Это, вероятно, самая большая проблема любого решения, связанного с масштабированиемrand()
.Тем не менее, тестирование на большом количестве итераций показывает, что этот метод очень единообразен для небольших диапазонов. Однако возможно (и вероятно), что математически это имеет небольшую погрешность и, возможно, вызывает проблемы при приближении диапазона
RAND_MAX
. Проверьте это на себе и решите, соответствует ли он вашим потребностям.источник
Конечно, следующий код выдаст вам не случайные числа, а псевдослучайное число. Используйте следующий код
#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )
Например:
int myRand = QUICK_RAND(10, 20);
Вы должны позвонить
srand(time(0)); // Initialize random number generator.
иначе числа не будут случайными.
источник
Я только что нашел это в Интернете. Это должно работать:
DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));
источник