14 ответов:
rand()может использоваться для генерации псевдослучайных чисел в C++. В сочетании сRAND_MAXи немного математики, вы можете генерировать случайные числа в любом произвольном интервале вы выбираете. Этого достаточно для учебных целей и игрушечных программ. Если вам нужно истинно случайные числа с нормальным распределением, вам нужно использовать более продвинутый способ.
это будет генерировать число от 0.0 до 1.0 включительно.
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);этот будет генерировать число от 0.0 до некоторой произвольной
float,X:float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));это будет генерировать число из некоторого произвольного
LOдля произвольногоHI:float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
отметим, что
C++11 дает вам много новых опций с
random. Каноническая статья на эту тему будет N3551, генерация случайных чисел в C++11чтобы понять, почему с помощью
rand()может быть проблематично увидеть rand () считается вредным презентация материала Стефан Т. Лававей данные в ходе GoingNative 2013 событие. Слайды находятся в комментариях, но вот прямой ссылка.я тоже покрываю
boostа также с помощьюrandтак как устаревший код все еще может потребовать его поддержки.приведенный ниже пример перегоняется с сайта cppreference и использует std:: mersenne_twister_engine двигатель и std:: uniform_real_distribution который генерирует числа в
[0,10)интервал, с другими движками и распределениями закомментированы (посмотреть его живи):#include <iostream> #include <iomanip> #include <string> #include <map> #include <random> int main() { std::random_device rd; // // Engines // std::mt19937 e2(rd()); //std::knuth_b e2(rd()); //std::default_random_engine e2(rd()) ; // // Distribtuions // std::uniform_real_distribution<> dist(0, 10); //std::normal_distribution<> dist(2, 2); //std::student_t_distribution<> dist(5); //std::poisson_distribution<> dist(2); //std::extreme_value_distribution<> dist(0,2); std::map<int, int> hist; for (int n = 0; n < 10000; ++n) { ++hist[std::floor(dist(e2))]; } for (auto p : hist) { std::cout << std::fixed << std::setprecision(1) << std::setw(2) << p.first << ' ' << std::string(p.second/200, '*') << '\n'; } }вывод будет похож на следующее:
0 **** 1 **** 2 **** 3 **** 4 ***** 5 **** 6 ***** 7 **** 8 ***** 9 ****выход будет меняться в зависимости от того, какой дистрибутив вы выберете, так что если мы решили пойти с std:: normal_distribution стоимостью
2как значит и stddev напримерdist(2, 2)вместо этого вывод будет похож на этот (посмотреть его в прямом эфире):-6 -5 -4 -3 -2 ** -1 **** 0 ******* 1 ********* 2 ********* 3 ******* 4 **** 5 ** 6 7 8 9в ниже приведена модифицированная версия некоторых кодов, представленных в
N3551(посмотреть его в прямом эфире):#include <algorithm> #include <array> #include <iostream> #include <random> std::default_random_engine & global_urng( ) { static std::default_random_engine u{}; return u ; } void randomize( ) { static std::random_device rd{}; global_urng().seed( rd() ); } int main( ) { // Manufacture a deck of cards: using card = int; std::array<card,52> deck{}; std::iota(deck.begin(), deck.end(), 0); randomize( ) ; std::shuffle(deck.begin(), deck.end(), global_urng()); // Display each card in the shuffled deck: auto suit = []( card c ) { return "SHDC"[c / 13]; }; auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; }; for( card c : deck ) std::cout << ' ' << rank(c) << suit(c); std::cout << std::endl; }результаты будут выглядеть примерно так:
5Ч 5S КАК 9С 4Д 6Ч Й 6Д Х 2С СМО 9Ч 8Ч 7Ч 2Д 3Д КЦ ТД КС 3С ТС 7Д 4С ДЧ КК КТ ДЖЕЙ ДИ АЙ ЙК АС КД 9Д 2Ч 4Ч 5С 8С 9С И. Н 5Д 4С 7С ОБЪЯВЛЕНИЕ 3С 8С 2С Ц 8Д 3Ч 6С И JS-7С 6С
Boost
конечно импульс.Случайный всегда вариант также, здесь я использую boost:: random:: uniform_real_distribution:
#include <iostream> #include <iomanip> #include <string> #include <map> #include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_real_distribution.hpp> int main() { boost::random::mt19937 gen; boost::random::uniform_real_distribution<> dist(0, 10); std::map<int, int> hist; for (int n = 0; n < 10000; ++n) { ++hist[std::floor(dist(gen))]; } for (auto p : hist) { std::cout << std::fixed << std::setprecision(1) << std::setw(2) << p.first << ' ' << std::string(p.second/200, '*') << '\n'; } }rand ()
если вы должны использовать
rand()тогда мы можем пойти в C FAQ для руководства о как я могу генерировать случайные числа с плавающей запятой? , что в основном дает пример, подобный этому для генерации на интервале[0,1):#include <stdlib.h> double randZeroToOne() { return rand() / (RAND_MAX + 1.); }и генерировать случайное число в диапазоне от
[M,N):double randMToN(double M, double N) { return M + (rand() / ( RAND_MAX / (N-M) ) ) ; }
посмотри импульс.Случайный. Вы могли бы сделать что-то вроде этого:
float gen_random_float(float min, float max) { boost::mt19937 rng; boost::uniform_real<float> u(min, max); boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u); return gen(); }поиграйте, вы можете сделать лучше, передавая один и тот же объект mt19937 вместо того, чтобы каждый раз создавать новый, но, надеюсь, вы получите эту идею.
вызовите код с двумя
floatзначения, код работает в любом диапазоне.float rand_FloatRange(float a, float b) { return ((b - a) * ((float)rand() / RAND_MAX)) + a; }
Если вы используете C++, а не C, то помните, что в техническом отчете 1 (TR1) и в проекте C++0x они добавили средства для генератора случайных чисел в заголовочном файле, я считаю, что он идентичен Boost.Случайная библиотека и, безусловно, более гибкая и "современная", чем функция библиотеки C, rand.
этот синтаксис предлагает возможность выбора генератора (например,мерсенн твистер mt19937), а затем выбрать распределение (нормальное, Бернулли, биномиальное и т. д.).
синтаксис выглядит следующим образом (бесстыдно заимствовано из этот сайт):
#include <iostream> #include <random> ... std::tr1::mt19937 eng; // a core engine class std::tr1::normal_distribution<float> dist; for (int i = 0; i < 10; ++i) std::cout << dist(eng) << std::endl;
современной
c++можно использовать<random>заголовок, который пришел сc++11.
Чтобы получить случайныйfloat's Вы можете использоватьstd::uniform_real_distribution<>.вы можете использовать функцию для генерации чисел, и если вы не хочу, чтобы цифры были одинаковыми все время, установите двигатель и распределение, чтобы быть
static.
Пример:float get_random() { static std::default_random_engine e; static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1 return dis(e); }идеально подходит для размещения
float's в контейнере, напримерstd::vector:int main() { std::vector<float> nums; for (int i{}; i != 5; ++i) // Generate 5 random floats nums.emplace_back(get_random()); for (const auto& i : nums) std::cout << i << " "; }пример:
0.0518757 0.969106 0.0985112 0.0895674 0.895542
В некоторых системах (Windows с VC приходит на ум, в настоящее время),
RAND_MAXсмехотворно мал, т. е. всего 15 бит. При делении наRAND_MAXвы только генерируете мантиссу из 15 бит вместо 23 возможных бит. Это может быть или не быть проблемой для вас, но вы упускаете некоторые значения в этом случае.О, просто заметил, что уже был комментарий для этой проблемы. В любом случае, вот код, который может решить эту проблему для вас:
float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);неопробованных, но может сработать :-)
drand48(3)является стандартным способом POSIX. Библиотека также предоставляет реентерабельная версия,drand48_r(3).функция была объявлена устаревшей в SVID 3, но адекватной альтернативы не было предоставлено так IEEE Std 1003.1-2013 по-прежнему включает в себя и не замечает, что это надолго.
в Windows, стандартный способ CryptGenRandom().
Я не был удовлетворен ни одним из ответов до сих пор, поэтому я написал новую случайную функцию float. Он делает побитовые предположения о типе данных float. Ему по-прежнему нужна функция rand() с не менее чем 15 случайными битами.
//Returns a random number in the range [0.0f, 1.0f). Every //bit of the mantissa is randomized. float rnd(void){ //Generate a random number in the range [0.5f, 1.0f). unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand())); unsigned short coinFlips; //If the coin is tails, return the number, otherwise //divide the random number by two by decrementing the //exponent and keep going. The exponent starts at 63. //Each loop represents 15 random bits, a.k.a. 'coin flips'. #define RND_INNER_LOOP() \ if( coinFlips & 1 ) break; \ coinFlips >>= 1; \ ret -= 0x800000 for(;;){ coinFlips = rand(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); //At this point, the exponent is 60, 45, 30, 15, or 0. //If the exponent is 0, then the number equals 0.0f. if( ! (ret & 0x3F800000) ) return 0.0f; RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP(); } return *((float *)(&ret)); }
на мой взгляд, приведенный выше ответ дает некоторый "случайный" поплавок, но ни один из них не является действительно случайным поплавком (т. е. они пропускают часть представления float). Прежде чем я поспешу в свою реализацию, давайте сначала посмотрим на стандартный формат ANSI / IEEE для поплавков:
/ знак (1-бит) / e (8-бит) / f (23-бит)/
число, представленное этим словом (-1 * знак) * 2^e * 1.f
обратите внимание, что число ' e ' является смещенным (с смещением 127) числом таким образом, в диапазоне от -127 до 126. Самая простая (и на самом деле самая случайная) функция-просто записать данные случайного int в float, таким образом
int tmp = rand(); float f = (float)*((float*)&tmp);обратите внимание, что если вы делаете
float f = (float)rand();он преобразует целое число в float (таким образом, 10 станет 10.0).
Так что теперь, если вы хотите ограничить максимальное значение, вы можете сделать что-то вроде (не уверен, что это работает)int tmp = rand(); float f = *((float*)&tmp); tmp = (unsigned int)f // note float to int conversion! tmp %= max_number; f -= tmp;но если вы посмотрите на структуру поплавка вы можете увидеть, что максимальное значение a float равен (приблизительно) 2^127, что намного больше максимального значения int (2^32), что исключает значительную часть чисел, которые могут быть представлены поплавком. Это моя окончательная реализация:
/** * Function generates a random float using the upper_bound float to determine * the upper bound for the exponent and for the fractional part. * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127) * @param max_exp sets the maximum number to 2 * e^max_exp (max 126) * @param sign_flag if sign_flag = 0 the random number is always positive, if * sign_flag = 1 then the sign bit is random as well * @return a random float */ float randf(int min_exp, int max_exp, char sign_flag) { assert(min_exp <= max_exp); int min_exp_mod = min_exp + 126; int sign_mod = sign_flag + 1; int frac_mod = (1 << 23); int s = rand() % sign_mod; // note x % 1 = 0 int e = (rand() % max_exp) + min_exp_mod; int f = rand() % frac_mod; int tmp = (s << 31) | (e << 23) | f; float r = (float)*((float*)(&tmp)); /** uncomment if you want to see the structure of the float. */ // printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r); return r; }С помощью этой функции
randf(0, 8, 0)вернет случайное число от 0.0 до 255.0
Если вы знаете, что ваш формат с плавающей запятой составляет IEEE 754 (почти все современные процессоры, включая Intel и ARM), то вы можете построить случайное число с плавающей запятой из случайного целого числа с помощью битовых методов. Это следует рассматривать только, если у вас нет доступа к C++11 это
randomилиBoost.Randomкоторые оба намного лучше.float rand_float() { // returns a random value in the range [0.0-1.0) // start with a bit pattern equating to 1.0 uint32_t pattern = 0x3f800000; // get 23 bits of random integer uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand()); // replace the mantissa, resulting in a number [1.0-2.0) pattern |= random23; // convert from int to float without undefined behavior assert(sizeof(float) == sizeof(uint32_t)); char buffer[sizeof(float)]; memcpy(buffer, &pattern, sizeof(float)); float f; memcpy(&f, buffer, sizeof(float)); return f - 1.0; }Это даст лучшее распределение, чем один с помощью деления.
для C++ он может генерировать реальные числа с плавающей запятой в диапазоне, указанном
distпеременная#include <random> //If it doesnt work then use #include <tr1/random> #include <iostream> using namespace std; typedef std::tr1::ranlux64_base_01 Myeng; typedef std::tr1::normal_distribution<double> Mydist; int main() { Myeng eng; eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970); Mydist dist(1,10); dist.reset(); // discard any cached values for (int i = 0; i < 10; i++) { std::cout << "a random value == " << (int)dist(eng) << std::endl; } return (0); }
rand () возвращает int между 0 и RAND_MAX. Чтобы получить случайное число между 0.0 и 1.0, сначала приведите int return by rand() к float, а затем разделите на RAND_MAX.
полностью случайное допустимое число с плавающей запятой генерируется следующим образом: Случайный знак, случайный показатель и случайная мантисса. Вот пример генерации случайных чисел от 0..MAXFLOAT с равномерным распределением:
static float frand(){ float f; UINT32 *fi = (UINT32*)&f; *fi = 0; const int minBitsRandGives = (1<<15); // RAND_MAX is at least (1<<15) UINT32 randExp = (rand()%254)+1; // Exponents are in range of [1..254] UINT32 randMantissa = ((rand() % minBitsRandGives) << 8) | (rand()%256); *fi = randMantissa | (randExp<<23); // Build a float with random exponent and random mantissa return f; }Важное Замечание: RAND_MAX по умолчанию равно 2^16 (на 32-битных системах), поэтому rand () может генерировать не более 15 случайных битов. Поскольку плавающая точка имеет всего 32 бита, мы должны активировать rand() не менее 3 раз для генерации случайных 32 биты. Я использовал 8 бит rand () для генерации экспоненты и еще 2 вызова rand () для генерации 23 бит мантиссы.
распространенная ошибка, чтобы избежать: если вы используете
(float)rand()/MAX_RANDчтобы получить плавающую точку в диапазоне [0..1], вы все равно получите случайные числа в равномерном распределении, но низкая точность. Например, генератор случайных чисел может генерировать и 0.00001 0.00002, но не может генерировать 0.000017. Такая случайность в 256 раз менее точна, чем фактическая плавающая точка представление.оптимизация: моя функция не оптимизирована для скорости. Вы можете улучшить его, заменив деление " % " побитовыми логическими операциями. Например, вместо
%256использовать&0xFF
Comments