Генерация случайных чисел с плавающей точкой

271

Как мне генерировать случайные числа с плавающей точкой в ​​C ++?

Я думал, что смогу взять целое число рандов и разделить его на что-нибудь, будет ли этого достаточно?

Hasen
источник
2
Это зависит скорее от того, для чего вы хотите получить число, и от того, насколько оно случайное. обычно rand () дает 15 битов случайности, но значения с плавающей точкой имеют 23-битную точность, поэтому некоторые значения будут пропущены.
Пит Киркхам,
1
Я обновил свой ответ, включив в него все основные доступные опции, и мой выбор сосредоточиться на randomзаголовке, добавленном в C ++ 11, подкрепляется стандартным документом N3924: не рекомендуется rand () в C ++ 14 . Я включаю rand()в свой ответ, в основном, исторические соображения, но также существует понимание того, что устаревшие приложения существуют.
Шафик Ягмур
Мой ответ включает в себя, как не получать одинаковые цифры каждый раз с <random>заголовком
Andreas DM

Ответы:

381

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)));

Обратите внимание, что rand()функции часто будет недостаточно, если вам нужны действительно случайные числа.


Перед тем, как позвонить rand(), вы должны сначала «запустить» генератор случайных чисел, позвонив srand(). Это должно быть сделано один раз во время выполнения вашей программы - не один раз при каждом вызове rand(). Это часто делается так:

srand (static_cast <unsigned> (time(0)));

Для того, чтобы позвонить randили srandнеобходимо #include <cstdlib>.

Для того, чтобы позвонить time, необходимо #include <ctime>.

Джон Диблинг
источник
22
Не забудьте сначала посеять семена!
Klaim
14
Лучше всего отметить, что оба ограничения включены.
dmckee --- котенок экс-модератора
14
Этот ответ вводит в заблуждение. Это было освещено на Going Native 2013 на прошлой неделе; rand () Считается вредным, channel9.msdn.com/Events/GoingNative/2013/… для очень подробного объяснения.
Аде Миллер
14
Я не понимаю, почему так много людей проголосовали за этот ответ. Это математически неверно. RAND_MAX - очень небольшое число (обычно 2 ^ 16). Это означает, что из 23 битов с плавающей точкой вы делаете только 15 случайных. Остальные, вероятно, будут равны нулю. Вы действительно получите случайные числа в равномерном распределении, но с низкой точностью. Например, ваш генератор случайных чисел может генерировать 0,00001 и 0,00002, но не может генерировать 0,000017. Таким образом, вы получаете равномерное распределение, но с низкой точностью (в 256 раз меньше точности, чем фактическая плавающая точка).
DanielHsH
10
@DanielHsH: ОП специально спросил, с какой механикой можно генерировать случайные поплавки rand(). Этот вопрос и мой ответ были специально сосредоточены на изучении основ и не касались высокой степени точности. Вы должны научиться ходить, прежде чем научиться бегать.
Джон Диблинг
138

C ++ 11 дает вам много новых опций random. Канонической статьей на эту тему будет N3551, Генерация случайных чисел в C ++ 11

Чтобы понять, почему использование rand()может быть проблематичным, смотрите презентацию rand () «Считается вредным » Стефана Т. Лававея, данную во время мероприятия GoingNative 2013 . Слайды в комментариях, но здесь есть прямая ссылка .

Я также расскажу boostи об использовании, randтак как устаревший код все еще может требовать его поддержки.

Приведенный ниже пример извлечен из сайта cppreference и использует механизм std :: mersenne_twister_engine и std ::iform_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для mean и 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;
}

Результаты будут выглядеть примерно так:

5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C 6C JS 7S 6S

Увеличение

Конечно, Boost.Random также всегда доступен , здесь я использую boost :: random ::iform_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 для получения инструкций о том, как генерировать случайные числа с плавающей запятой? , который в основном дает пример, подобный этому для генерации на интервале [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) ) ) ;  
}
Шафик Ягмур
источник
1
вы можете исправить ваши randMToNпожалуйста? либо обратите внимание, что это [M,N]или добавить обратно + 1.из выше randZeroToOne. -> Думайте о том, чтобы называть это так:randMToN(0.0, 1.0);
BeyelerStudios
1
Также будьте осторожны с делением на ноль при (N-M). Хороший способ справиться с этой ошибкой можно найти здесь: stackoverflow.com/questions/33058848/…
Dr Beco
61

Взгляните на Boost.Random . Вы могли бы сделать что-то вроде этого:

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, вместо того, чтобы каждый раз создавать новый, но, надеюсь, вы поняли идею.

rlbond
источник
1
iform_real использует полуоткрытый интервал [min, max), что означает, что вы получите минимальное значение, но никогда не достигнете максимального значения. Это то, что нужно учитывать, хотя, если вы каким-то образом округлите, вы можете преодолеть эту проблему.
TehWan
20
Теперь это часть C ++ 11.
Томас Андрле
@ Вольф в практических приложениях вероятность попадания любого конкретного значения с плавающей запятой настолько мала, что не имеет значения, включена ли конечная точка или исключена. Если вам нужно , maxно можно использовать с открытым концом min, вы можете полностью изменить интервал легко: return min + max - gen();.
Марк Рэнсом
26

В современном c++вы можете использовать <random>заголовок, который идет с c++11.
Чтобы получить случайные float, вы можете использовать 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в контейнер, например 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
Андреас Д.М.
источник
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.
Тройсеф
1
Это должен быть принятый ответ, это чертовски 2020 год.
Алекс
25

Назовите код с двумя floatзначениями, код работает в любом диапазоне.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Иван Проданов
источник
Возможно, стоит упомянуть, что это потенциальный вариант использования fmaf()(или fma()перегрузки с плавающей точкой в C ++) в C99 или C ++ 11, который может сохранить большую точность. Как и в fmaf((float)rand() / RAND_MAX, b - a, a).
Тим
22

Если вы используете C ++, а не C, то помните, что в техническом отчете 1 (TR1) и в черновике C ++ 0x они добавили средства для генератора случайных чисел в заголовочном файле, я считаю, что он идентичен Boost. Случайная библиотека и определенно более гибкая и «современная», чем функция библиотеки C, rand.

Этот синтаксис дает возможность выбрать генератор (например, mersenne twister 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;
стог
источник
2
Теперь это в C ++ 11, также dist может быть инициализирован значениями min и max.
Этьен
Мне кажется странным помещать минимальное и максимальное значения в инициализатор и предоставлять генератор при получении значения - я бы предпочел, если бы это было наоборот, да ладно.
йо
6

В некоторых системах (Windows с VC приходит на ум, в настоящее время), RAND_MAXэто смехотворно мало, т.е. е. только 15 бит. При делении на RAND_MAXвас генерируется только мантисса из 15 бит вместо 23 возможных бит. Это может или не может быть проблемой для вас, но вы пропустите некоторые значения в этом случае.

О, просто заметил, что уже есть комментарий к этой проблеме. В любом случае, вот код, который может решить эту проблему для вас:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Не проверено, но может работать :-)

детеныш
источник
Как насчет float r = (float) ((rand () << 9) | rand ()) / RAND_MAX? (также не проверено)
Trap
О, извини, деление на RAND_MAX никуда тебя не приведет ... весь смысл этого трюка состоял в том, чтобы иметь что-то большее, чем RAND_MAX ... исправил это и для меня.
Джои
2
Будьте осторожны при составлении случайных чисел без теории ... последовательные вызовы rand () могут быть не полностью независимыми. Подсказка: если это линейный конгруэнтный генератор, следите за
младшим
Я знаю. Для некоторых приложений этого может быть достаточно. Но да, вам, вероятно, следует использовать более двух вызовов в этом случае. В этом случае серебряной пули нет, вы даже не можете полагаться на то, что она является LCG. Другие PRNG имеют слабые старшие биты. Решение Boost должно быть лучшим здесь.
Джои
(nb: младший бит, возвращаемый rand в MSVC, не является самым младшим битом состояния RNG. Для 100 вызовов rand () я получаю следующее: 110010000011111110101001001001101010111011011011101001111110010000000001010001101100000010011100100010100011011000000100101100011. Java использует только 48-битный LCG, кажется, что только VC использует 48-битный LCG, 32C-битный LCG, только для VC, и LCC только 48-битный, V-образный бит, VC, только 28-битный LCG, 32C-битный LCG, только для VC, и LCC только 48-битный сделать это аналогично)
Joey
4

drand48(3)это стандартный способ POSIX. GLibC также предоставляет реентерабельную версию drand48_r(3).

Функция была объявлена ​​устаревшей в SVID 3, но не было предоставлено адекватной альтернативы, поэтому IEEE Std 1003.1-2013 все еще включает ее и не имеет никаких замечаний о том, что она появится где-нибудь в ближайшее время.

В Windows стандартным способом является CryptGenRandom () .

ivan_pozdeev
источник
2

Пока что я не был удовлетворен ни одним из ответов, поэтому я написал новую функцию случайного числа. Это делает побитовые предположения о типе данных с плавающей точкой. Для этого все еще нужна функция 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));
}
iNFiNiTyLoOp
источник
7
интересный подход, я хотел бы высказать мнение, но я действительно не понимаю, что происходит
hasen
2

По моему мнению, приведенный выше ответ дает некоторое «случайное» смещение, но ни один из них не является действительно случайным смещением (то есть они пропускают часть представления с плавающей точкой). Прежде чем я углублюсь в свою реализацию, давайте сначала посмотрим на стандартный формат ANSI / IEEE для float:

| знак (1 бит) | е (8 бит) | f (23 бита) |

число, представленное этим словом, (-1 * знак) * 2 ^ e * 1.f

обратите внимание, что число 'e' является смещенным (с смещением 127) числом, таким образом, в диапазоне от -127 до 126. Самая простая (и фактически самая случайная) функция - просто записать данные случайного int в число с плавающей точкой, таким образом

int tmp = rand();
float f = (float)*((float*)&tmp);

обратите внимание, что если вы сделаете float f = (float)rand();это, он преобразует целое число в число с плавающей точкой (таким образом, 10 станет 10,0).

Так что теперь, если вы хотите ограничить максимальное значение, вы можете сделать что-то вроде (не уверен, что это работает)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

но если вы посмотрите на структуру числа с плавающей точкой, то увидите, что максимальное значение числа с плавающей точкой составляет (приблизительно) 2 ^ 127, что намного больше, чем максимальное значение целого числа (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

user2546926
источник
1
у тебя ошибка rand ()% frac_mod не будет работать, так как MAX_RAND обычно ниже, чем (1 << 23).
DanielHsH
Я должен признать, что я не знаю точный размер MAX_RAND. Тем не менее, это все равно будет работать, возможно, это бесполезное утверждение, но оно все равно будет работать. 8% 10 = 8, это нормально, но если MAX_RAND всегда меньше, то (1 << 23) вы действительно можете удалить его.
user2546926
2
Нет, вы немного не правы. RandMax обычно составляет ~ 65 000. Это означает, что из 23 битов вы делаете только 15 случайных. Остальные, вероятно, будут равны нулю. Вы действительно получите случайные числа, но с низкой точностью. Например, ваш генератор случайных чисел может генерировать 0,001 и 0,002, но не может генерировать 0,0017. Таким образом, у вас равномерное распределение, но с низкой точностью (точность в 256 раз меньше, чем с плавающей точкой).
DanielHsH
В этом ответе есть две ошибки. Исправление диапазона экспонент: int e = (rand() % (max_exp - min_exp)) + min_exp_mod;и мантисса: int f = (int)(frac_mod * (float)rand() / RAND_MAX);замена соответствующих строк выше. Обратите внимание, что ошибка мантиссы является основной: для RAND_MAXменьших 1 << 23вы бы случайным образом рандомизировали младшие значащие биты и получали 0 для самых значимых битов все время!
BeyelerStudios
2

Если вы знаете, что ваш формат с плавающей запятой - это 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;
}

Это даст лучшее распределение, чем разделение с использованием.

Марк Рэнсом
источник
8
Я не уверен, почему вы говорите, что это даст "лучшее распределение". На самом деле, это даст точно такое же распределение, как и просто return (float)random23 / (1 << 23). (Да, я только что проверил это , изменив вашу функцию random32в качестве параметра и запустив ее для всех значений от нуля до (1 << 23)-1. И да, ваш метод действительно дает точно такие же результаты, что и деление на 1 << 23.)
Ilmari Karonen
1

Для 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);
}
Marco167
источник
1
Вы только что скопировали и вставили код из этого ответа? stackoverflow.com/a/1118739/1538531
Дерек
На самом деле нет. Я немного удивлен, увидев, как они похожи! Но я действительно инициализировал двигатель-генератор.
Marco167
Справедливо. Я заметил, что вы инициализировали генератор в эпоху, но, черт возьми, этот код похож!
Дерек
Я нахожу немного странным приводить пример TR1. Можете ли вы объяснить, в каких случаях кому-то придется использовать TR1 в отличие от C ++ 11?
Шафик Ягмур
0

rand () возвращает int между 0 и RAND_MAX. Чтобы получить случайное число в диапазоне от 0,0 до 1,0, сначала приведите значение int, возвращаемое rand (), к float, а затем разделите на RAND_MAX.

Джеймс Керран
источник
0
#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

/* single precision float offers 24bit worth of linear distance from 1.0f to 0.0f */
float getval() {
    /* rand() has min 16bit, but we need a 24bit random number. */
    uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
    /* 5.9604645E-8 is (1f - 0.99999994f), 0.99999994f is the first value less than 1f. */
    return (double)r * 5.9604645E-8;
}

int main()
{
    srand(time(NULL));
...

Я не мог опубликовать два ответа, так что вот второе решение. log2 случайные числа, массивный уклон в сторону 0,0f, но это действительно случайное смещение от 1,0f до 0,0f.

#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

float getval () {
    union UNION {
        uint32_t i;
        float f;
    } r;
    /* 3 because it's 0011, the first bit is the float's sign.
     * Clearing the second bit eliminates values > 1.0f.
     */
    r.i = (rand () & 0xffff) + ((rand () & 0x3fff) << 16);
    return r.f;
}

int main ()
{
    srand (time (NULL));
...
Майк Местник
источник