С++ генерирует случайные числа
Мой вывод 20 случайных 1, а не между 10 и 1, может ли кто-нибудь объяснить, почему это происходит?
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
srand((unsigned)time(0));
int random_integer;
int lowest=1, highest=10;
int range=(highest-lowest)+1;
for(int index=0; index<20; index++){
random_integer = lowest+int(range*rand()/(RAND_MAX + 1.0));
cout << random_integer << endl;
}
}
Выход: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Ответы
Ответ 1
Потому что на вашей платформе RAND_MAX == INT_MAX
.
Выражение range*rand()
никогда не может принимать значение больше, чем INT_MAX
. Если математическое выражение больше, чем INT_MAX
, то переполнение целых чисел уменьшает его до числа между INT_MIN
и INT_MAX
. Деление на RAND_MAX
всегда будет равно нулю.
Попробуйте следующее выражение:
random_integer = lowest+int(range*(rand()/(RAND_MAX + 1.0)))
Ответ 2
Намного проще использовать библиотеку <random>
правильно, чем rand
(предполагая, что вы достаточно знакомы с С++, что синтаксис не бросает вас).
#include <random>
#include <iostream>
int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist(1, 10);
for(int i = 0; i < 20; ++i)
std::cout << dist(eng) << " ";
}
Ответ 3
random_integer = (rand() % 10) + 1
Это должно дать вам псевдослучайное число от 1 до 10.
Ответ 4
Несколько поздний ответ, но он должен предоставить некоторые дополнительные
информация , если важно качество генерации. (Не все
приложения нуждаются в этом: небольшое смещение часто не является проблемой.)
Во-первых, конечно, проблема в исходном коде состоит в том, что
range * rand()
имеет приоритет над следующим подразделением и выполняется
используя целочисленную арифметику. В зависимости от RAND_MAX
это может легко
приводят к переполнению, с реализацией определенных результатов; на все
которые я знаю, если это приводит к переполнению (потому что
RAND_MAX > INT_MAX / range
, фактические результаты почти наверняка
быть меньше, чем RAND_MAX + 1.0
, а деление приведет к
значение меньше 1.0
. Существует несколько способов избежать этого:
Простейшим и надежным является просто rand() % range + lowest
.
Заметим, что это предполагает, что rand()
имеет разумное качество. Многие
прежних реализаций не было, и я видел, по крайней мере, один, где
rand() % 6 + 1
, чтобы имитировать бросок кубика чередующимся нечетным и четным.
только правильное решение состоит в том, чтобы лучше реализовать
rand()
; это привело к тому, что люди пытались найти альтернативные решения, такие как
(range * (rand() / (RAND_MAX + 1.0))) + lowest
. Это маскирует
проблема, но он не изменит плохой генератор в хороший.
Вторая проблема, , если важно качество генерации, является
что при генерации случайных целых чисел вы дискретизируете: если вы
например, для имитации броска кубика, у вас есть шесть возможных
значения, которые вы хотите выполнить с равной вероятностью. Случайный
генератор будет генерировать RAND_MAX + 1
разные значения, равные
вероятность. Если RAND_MAX + 1
не кратно 6, то нет
возможный способ распределения значений, равных
значения. Представьте простой случай, когда RAND_MAX + 1
равно 10. Используя
%
выше, значения 1 & times; 4 в два раза больше, чем
значения 5 и 6. Если вы используете более сложную формулу 1 + int(6 *
(rand() / (RAND_MAX + 1.0)))
(в случае, когда RAND_MAX + 1 == 10
,
оказывается, что 3 и 6 только наполовину вероятнее других.
Математически нет возможности распространять 10 разных
значения в 6 слотов с одинаковым количеством элементов в каждом слоте.
Конечно, RAND_MAX
всегда будет значительно больше 10, и
введенная предвзятость будет значительно меньше; если диапазон
значительно меньше RAND_MAX
, это может быть приемлемым. Если это
не, однако, обычная процедура выглядит примерно так:
int limit = (RAND_MAX + 1LL) - (RAND_MAX + 1LL) % range;
// 1LL will prevent overflow on most machines.
int result = rand();
while ( result >= limit ) {
result = rand();
}
return result % range + lowest;
(Существует несколько способов определения значений для выброса.
оказывается, тот, который я использую, но я помню, как Энди Кениг использовал что-то
совершенно разные, но это привело к тому, что одни и те же значения были
выкинутый в конце.)
Обратите внимание, что большую часть времени вы не будете вводить цикл; наихудший случай
когда range
есть (RAND_MAX + 1) / 2 + 1
, и в этом случае вы все равно
в среднем за один раз через цикл.
Обратите внимание, что эти комментарии применяются только тогда, когда вам необходимо фиксированное количество
дискретные результаты. Для (другого) общего случая генерации случайного
число с плавающей запятой в диапазоне [0,1)
, rand() / (RAND_MAX +
1.0)
примерно так же хорошо, как вы собираетесь получить.
Ответ 5
Я предлагаю заменить rand()/(RAND_MAX + 1.0)
на range*double(rand())/(RAND_MAX + 1.0))
. Поскольку мое решение, похоже, дает головные боли...
возможные комбинации аргументов:
-
range*rand()
является целым числом и переполняется.
-
double(range*rand())
переполняется, прежде чем преобразовать его в double.
-
range*double(rand())
не переполняется и дает ожидаемые результаты.
У моего первоначального сообщения было две фигурные скобки, но они ничего не меняли (результаты одинаковы).
Ответ 6
Visual studio 2008 вообще не имеет проблем с этой программой и с радостью генерирует swathe случайных чисел.
То, что я буду осторожен, это /(RAND_MAX +1.0), так как это, скорее всего, сменит целые проблемы и в конечном итоге с большим количеством жира.
Сбрасывать до двойного значения перед делением, а затем отбрасывать обратно в int
Ответ 7
(rand() % highest) + lowest + 1
Ответ 8
Вы генерируете случайное число (т.е. (range*rand()/(RAND_MAX + 1.0))
), значение которого находится между -1 и 1 (]-1,1[
), а затем отбрасывает его на целое число. Целочисленное значение такого числа всегда равно 0, поэтому вы заканчиваете с lower + 0
EDIT: добавила формулу, чтобы сделать мой ответ более ясным
Ответ 9
Вероятно, "10 * rand()" меньше, чем "RAND_MAX + 1.0", поэтому значение вашего вычисления равно 0.
Ответ 10
Это одна из самых простых логик, полученная из блога. в этой логике вы можете ограничить случайные числа с помощью данного заданного оператора модуля (%) внутри цикла for, просто скопируйте и вставьте из этого блога, но в любом случае проверьте это:
// random numbers generation in C++ using builtin functions
#include <iostream>
using namespace std;
#include <iomanip>
using std::setw;
#include <cstdlib> // contains function prototype for rand
int main()
{
// loop 20 times
for ( int counter = 1; counter <= 20; counter++ ) {
// pick random number from 1 to 6 and output it
cout << setw( 10 ) << ( 1 + rand() % 6 );
// if counter divisible by 5, begin new line of output
if ( counter % 5 == 0 )
cout << endl;
}
return 0; // indicates successful termination
} // end main
- Подробнее на: http://www.programmingtunes.com/generation-of-random-numbers-c/#sthash.BTZoT5ot.dpuf
Ответ 11
Как использовать условие, чтобы проверить, совпадает ли последний номер с текущим? Если условие выполнено, сгенерируйте другое случайное число. Это решение работает, но потребуется больше времени.