Простой: двойной имеет 52-битную точность, предполагающую IEEE. Итак, сгенерируйте 52-битное (или больше) беззнаковое случайное целое число (например, прочитав байты из dev/urandom), преобразуйте его в двойное и разделите на 2 ^ (количество битов, которое было).
Это дает численно равномерное распределение (в том смысле, что вероятность нахождения значения в заданном диапазоне пропорциональна диапазону) вплоть до 52-й двоичной цифры.
Сложно. Однако в диапазоне [0,1] есть много двойных значений, которые вышеописанное не может сгенерировать. Чтобы быть точным, половина значений в диапазоне [0,0,5) (те, у которых установлен младший значащий бит) не могут встречаться. Три четверти значений в диапазоне [0,0,25) (те, у которых установлен любой из их наименьших 2 битов) не могут встречаться и т. д., вплоть до возможного только одного положительного значения меньше 2 ^ -51, несмотря на то, что двойник способен представлять сквиллионы таких значений. Таким образом, нельзя сказать, что он действительно однороден в указанном диапазоне с полной точностью.
Конечно, мы не хотим выбирать один из этих дублей с равной вероятностью, потому что тогда результирующее число в среднем будет слишком маленьким. Нам по-прежнему нужно, чтобы вероятность того, что результат находится в заданном диапазоне, была пропорциональна диапазону, но с более высокой точностью в отношении того, для каких диапазонов это работает.
Я думаю, что работает следующее. Я особо не изучал и не тестировал этот алгоритм (как вы, вероятно, можете сказать по тому, что там нет кода), и лично я бы не стал его использовать, не найдя надлежащих ссылок, указывающих на то, что он действителен. Но вот:
- Начните экспоненту с 52 и выберите 52-битное случайное целое число без знака (при условии, что мантисса 52 бита).
- Если старший значащий бит целого числа равен 0, увеличьте показатель степени на единицу, сдвиньте целое число влево на единицу и заполните младший значащий бит новым случайным битом.
- Повторяйте до тех пор, пока либо вы не нажмете 1 в самом значимом месте, либо показатель степени не станет слишком большим для вашего удвоения (1023. Или, возможно, 1022).
- Если вы нашли 1, разделите свое значение на 2 ^ показатель степени. Если вы получили все нули, верните 0 (я знаю, что на самом деле это не особый случай, но подчеркивается, насколько маловероятен возврат 0 [Редактировать: на самом деле это может быть особый случай - это зависит от того, хотите ли вы генерировать denorms, Если нет, то, как только у вас будет достаточно 0 в строке, вы отбрасываете все, что осталось, и возвращаете 0. Но на практике это настолько маловероятно, что им можно пренебречь, если только случайный источник не является случайным).
Я не знаю, есть ли на самом деле какое-то практическое применение для такого случайного двойника, заметьте. Ваше определение случайности должно в какой-то степени зависеть от того, для чего оно предназначено. Но если вы можете извлечь выгоду из того, что все 52 его значащих бита являются случайными, это может быть действительно полезно.
person
Steve Jessop
schedule
29.09.2008