инициализируя std::random_device
Да, этот вариант предпочтительней, но он появился только в C++11, поэтому в GF и использовали QueryPerformanceCounter(ведь счётчик тактов - корректный источник энтропии).
В своих фиксах для С1 я тоже переписал rand() на std::mt19937
Как мне кажется, главная проблема - это всё же использование остатка от деления для установки диапазона.
И, как я уже показал выше, в GF её решили довольно элегантно. Вот для наглядности:
std::mt19937_64 генерирует целые числа в диапазоне [0, (2^64)-1] (
0x0000000000000000,
0xFFFFFFFFFFFFFFFF).
Для получения
double числа используются только 53 бита (
0x001FFFFFFFFFFFFF) (количество неслучайно: связано с шириной мантиссы
double).
Далее идёт умножение на один из постоянных
double множителей:
DOUBLE_UNIT_EXCLUSIVE = 1.1102230246251565e-016 (
0x3CA0000000000000)
или
DOUBLE_UNIT_INCLUSIVE = 1.1102230246251568e-016 (
0x3CA0000000000001)
(оба они примерно равны
0.00000000000000011).
После преобразования ряды выглядят так:
C++:
(double)0x0000000000000000 * DOUBLE_UNIT_EXCLUSIVE = 0.00000000000000000
(double)0x0000000000000001 * DOUBLE_UNIT_EXCLUSIVE ~= 0.00000000000000011
(double)0x0000000000000002 * DOUBLE_UNIT_EXCLUSIVE ~= 0.00000000000000022
...
(double)0x001FFFFFFFFFFFFD * DOUBLE_UNIT_EXCLUSIVE ~= 0.99999999999999967
(double)0x001FFFFFFFFFFFFE * DOUBLE_UNIT_EXCLUSIVE ~= 0.99999999999999978
(double)0x001FFFFFFFFFFFFF * DOUBLE_UNIT_EXCLUSIVE ~= 0.99999999999999989
C++:
(double)0x0000000000000000 * DOUBLE_UNIT_INCLUSIVE = 0.00000000000000000
(double)0x0000000000000001 * DOUBLE_UNIT_INCLUSIVE ~= 0.00000000000000011
(double)0x0000000000000002 * DOUBLE_UNIT_INCLUSIVE ~= 0.00000000000000022
...
(double)0x001FFFFFFFFFFFFD * DOUBLE_UNIT_INCLUSIVE ~= 0.99999999999999989
(double)0x001FFFFFFFFFFFFE * DOUBLE_UNIT_INCLUSIVE ~= 1.00000000000000000
(double)0x001FFFFFFFFFFFFF * DOUBLE_UNIT_INCLUSIVE = 1.00000000000000000
На всём протяжении ряды отличаются абсолютно незначительно, важно лишь максимально возможное значение.
В итоге получается 2^53
double значений в диапазоне от 0.0 до 1.0 (проще говоря от 0% до 100%) c шагом ~
0.00000000000000011.