Как мне генерировать случайные числа с плавающей точкой в C ++?
Я думал, что смогу взять целое число рандов и разделить его на что-нибудь, будет ли этого достаточно?
c++
random
floating-point
Hasen
источник
источник
random
заголовке, добавленном в C ++ 11, подкрепляется стандартным документом N3924: не рекомендуется rand () в C ++ 14 . Я включаюrand()
в свой ответ, в основном, исторические соображения, но также существует понимание того, что устаревшие приложения существуют.<random>
заголовкомОтветы:
rand()
может использоваться для генерации псевдослучайных чисел в C ++. В сочетании сRAND_MAX
небольшой математикой вы можете генерировать случайные числа в любом произвольном интервале по вашему выбору. Этого достаточно для учебных целей и игрушечных программ. Если вам нужны действительно случайные числа с нормальным распределением, вам нужно использовать более продвинутый метод.Будет сгенерировано число от 0,0 до 1,0 включительно.
Это будет генерировать число от 0,0 до некоторой произвольной
float
,X
:Это сгенерирует число от некоторого произвольного
LO
до некоторого произвольногоHI
:Обратите внимание, что
rand()
функции часто будет недостаточно, если вам нужны действительно случайные числа.Перед тем, как позвонить
rand()
, вы должны сначала «запустить» генератор случайных чисел, позвонивsrand()
. Это должно быть сделано один раз во время выполнения вашей программы - не один раз при каждом вызовеrand()
. Это часто делается так:Для того, чтобы позвонить
rand
илиsrand
необходимо#include <cstdlib>
.Для того, чтобы позвонить
time
, необходимо#include <ctime>
.источник
rand()
. Этот вопрос и мой ответ были специально сосредоточены на изучении основ и не касались высокой степени точности. Вы должны научиться ходить, прежде чем научиться бегать.C ++ 11 дает вам много новых опций
random
. Канонической статьей на эту тему будет N3551, Генерация случайных чисел в C ++ 11Чтобы понять, почему использование
rand()
может быть проблематичным, смотрите презентацию rand () «Считается вредным » Стефана Т. Лававея, данную во время мероприятия GoingNative 2013 . Слайды в комментариях, но здесь есть прямая ссылка .Я также расскажу
boost
и об использовании,rand
так как устаревший код все еще может требовать его поддержки.Приведенный ниже пример извлечен из сайта cppreference и использует механизм std :: mersenne_twister_engine и std ::iform_real_distribution, который генерирует числа в
[0,10)
интервале, с другими закомментированными движками и дистрибутивами ( смотрите вживую ):вывод будет похож на следующее:
Вывод будет варьироваться в зависимости от того, какое распределение вы выберете, поэтому, если мы решили использовать std :: normal_distribution со значением
2
для mean и stddev, например,dist(2, 2)
вместо этого вывод будет аналогичен этому ( смотрите его вживую ):Ниже приведена модифицированная версия некоторого кода, представленного в
N3551
( смотрите его вживую ):Результаты будут выглядеть примерно так:
Увеличение
Конечно, Boost.Random также всегда доступен , здесь я использую boost :: random ::iform_real_distribution :
Rand ()
Если вы должны использовать его,
rand()
мы можем перейти к разделу часто задаваемых вопросов C для получения инструкций о том, как генерировать случайные числа с плавающей запятой? , который в основном дает пример, подобный этому для генерации на интервале[0,1)
:и генерировать случайное число в диапазоне от
[M,N)
:источник
randMToN
пожалуйста? либо обратите внимание, что это[M,N]
или добавить обратно+ 1.
из вышеrandZeroToOne
. -> Думайте о том, чтобы называть это так:randMToN(0.0, 1.0);
(N-M)
. Хороший способ справиться с этой ошибкой можно найти здесь: stackoverflow.com/questions/33058848/…Взгляните на Boost.Random . Вы могли бы сделать что-то вроде этого:
Поиграйте, вы могли бы лучше передать один и тот же объект mt19937, вместо того, чтобы каждый раз создавать новый, но, надеюсь, вы поняли идею.
источник
max
но можно использовать с открытым концомmin
, вы можете полностью изменить интервал легко:return min + max - gen();
.В современном
c++
вы можете использовать<random>
заголовок, который идет сc++11
.Чтобы получить случайные
float
, вы можете использоватьstd::uniform_real_distribution<>
.Вы можете использовать функцию для генерации чисел, и если вы не хотите, чтобы числа были одинаковыми все время, установите движок и распределение равными
static
.Пример:
Идеально помещать
float
в контейнер, напримерstd::vector
:Пример вывода:
источник
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
технически неверен, 1.0 никогда не будет сгенерирован, см. en.cppreference.com/w/cpp/numeric/random/…To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Назовите код с двумя
float
значениями, код работает в любом диапазоне.источник
fmaf()
(илиfma()
перегрузки с плавающей точкой в C ++) в C99 или C ++ 11, который может сохранить большую точность. Как и вfmaf((float)rand() / RAND_MAX, b - a, a)
.Если вы используете C ++, а не C, то помните, что в техническом отчете 1 (TR1) и в черновике C ++ 0x они добавили средства для генератора случайных чисел в заголовочном файле, я считаю, что он идентичен Boost. Случайная библиотека и определенно более гибкая и «современная», чем функция библиотеки C, rand.
Этот синтаксис дает возможность выбрать генератор (например, mersenne twister mt19937), а затем выбрать распределение (нормальное, бернулли, биномиальное и т. Д.).
Синтаксис выглядит следующим образом (бесстыдно позаимствовано с этого сайта ):
источник
В некоторых системах (Windows с VC приходит на ум, в настоящее время),
RAND_MAX
это смехотворно мало, т.е. е. только 15 бит. При делении наRAND_MAX
вас генерируется только мантисса из 15 бит вместо 23 возможных бит. Это может или не может быть проблемой для вас, но вы пропустите некоторые значения в этом случае.О, просто заметил, что уже есть комментарий к этой проблеме. В любом случае, вот код, который может решить эту проблему для вас:
Не проверено, но может работать :-)
источник
drand48(3)
это стандартный способ POSIX. GLibC также предоставляет реентерабельную версиюdrand48_r(3)
.Функция была объявлена устаревшей в SVID 3, но не было предоставлено адекватной альтернативы, поэтому IEEE Std 1003.1-2013 все еще включает ее и не имеет никаких замечаний о том, что она появится где-нибудь в ближайшее время.
В Windows стандартным способом является CryptGenRandom () .
источник
Пока что я не был удовлетворен ни одним из ответов, поэтому я написал новую функцию случайного числа. Это делает побитовые предположения о типе данных с плавающей точкой. Для этого все еще нужна функция rand () с как минимум 15 случайными битами.
источник
По моему мнению, приведенный выше ответ дает некоторое «случайное» смещение, но ни один из них не является действительно случайным смещением (то есть они пропускают часть представления с плавающей точкой). Прежде чем я углублюсь в свою реализацию, давайте сначала посмотрим на стандартный формат ANSI / IEEE для float:
| знак (1 бит) | е (8 бит) | f (23 бита) |
число, представленное этим словом, (-1 * знак) * 2 ^ e * 1.f
обратите внимание, что число 'e' является смещенным (с смещением 127) числом, таким образом, в диапазоне от -127 до 126. Самая простая (и фактически самая случайная) функция - просто записать данные случайного int в число с плавающей точкой, таким образом
обратите внимание, что если вы сделаете
float f = (float)rand();
это, он преобразует целое число в число с плавающей точкой (таким образом, 10 станет 10,0).Так что теперь, если вы хотите ограничить максимальное значение, вы можете сделать что-то вроде (не уверен, что это работает)
но если вы посмотрите на структуру числа с плавающей точкой, то увидите, что максимальное значение числа с плавающей точкой составляет (приблизительно) 2 ^ 127, что намного больше, чем максимальное значение целого числа (2 ^ 32), что исключает значительную часть числа, которые могут быть представлены поплавком. Это моя последняя реализация:
использование этой функции
randf(0, 8, 0)
вернет случайное число от 0,0 до 255,0источник
int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
и мантисса:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
замена соответствующих строк выше. Обратите внимание, что ошибка мантиссы является основной: дляRAND_MAX
меньших1 << 23
вы бы случайным образом рандомизировали младшие значащие биты и получали 0 для самых значимых битов все время!Если вы знаете, что ваш формат с плавающей запятой - это IEEE 754 (почти все современные процессоры, включая Intel и ARM), то вы можете построить случайное число с плавающей запятой из случайного целого числа, используя побитовые методы. Это следует учитывать только в том случае, если у вас нет доступа к C ++ 11
random
или к тому,Boost.Random
что гораздо лучше.Это даст лучшее распределение, чем разделение с использованием.
источник
return (float)random23 / (1 << 23)
. (Да, я только что проверил это , изменив вашу функциюrandom32
в качестве параметра и запустив ее для всех значений от нуля до(1 << 23)-1
. И да, ваш метод действительно дает точно такие же результаты, что и деление на1 << 23
.)Для C ++ он может генерировать реальные числа с плавающей точкой в диапазоне, указанном
dist
переменнойисточник
rand () возвращает int между 0 и RAND_MAX. Чтобы получить случайное число в диапазоне от 0,0 до 1,0, сначала приведите значение int, возвращаемое rand (), к float, а затем разделите на RAND_MAX.
источник
Я не мог опубликовать два ответа, так что вот второе решение. log2 случайные числа, массивный уклон в сторону 0,0f, но это действительно случайное смещение от 1,0f до 0,0f.
источник