Масштабирование Int равномерного случайного диапазона в Double - PullRequest
0 голосов
/ 29 марта 2011

На самом деле, у меня есть несколько вопросов переплетения. (Если это имеет значение, я использую C #.)

Во-первых. У меня есть prng, который генерирует случайные числа в диапазоне UInt32, от 0 до UInt32.Max включительно. Я хочу максимально сохранить однородность. Какова основная идея получить [a, b], (a, b) двойные диапазоны (такие как [0,1], [0,1), (0,1), [-2,4], (- 10,10?))

Меня беспокоит следующее. У меня 4 294 967 296 результатов. Меньше чисел в [0,1] двойном диапазоне - 2 ^ 53. Поэтому я строю 4 294 967 296-иное число из 2 цифр, которое является случайным и единообразным в [0, 4294967295 * 4294967296 + 4294967295]. Это максимальное значение больше, чем 2 ^ 53 на 1, поэтому, если вы его получите, выкините его, пересчитайте, используйте мод 2 ^ 53 и получите равномерное число, например, [0,1]. Здесь я должен представить максимальное значение как double (предположим, что нет типа Int64) - есть ли у него недостатки?

Теперь, если я хочу получить [0,1), я считаю, что число результатов равно (2 ^ 53) - 1. Добавление к последнему результату 1 / (2 ^ 53) приведет к случайному удвоению в (0 , 1]. Чтобы получить (0,1), я рассматриваю (2 ^ 53) - 2 новых результата и добавляю 1 / (2 ^ 53) к результату на основе 0. Это все правильно?

Но как получить двойные диапазоны, близкие или равные всему двойному диапазону? Даже если я построю n-арное число, как указано выше, оно может стать больше, чем Double.Max. Может быть, возможен какой-то подход бит-сдвигов / бит-масок?

Во-вторых. Теперь есть двойной prng с результатами в [0,1), возможно ли получить диапазон [Double.Min, Double.Max]? Сколько всего двойных чисел? Если есть полный двойной диапазон prng, каков наилучший способ получить диапазон UInt - отобразить «напрямую» или масштабировать до [0,1] раньше?

В-третьих. Я нашел этот код (http://www.math.sci.hiroshima -u.ac.jp / ~ m-mat / MT / MT2002 / CODES / mt19937ar.c):

 /* generates a random number on [0,1) with 53-bit resolution*/
 double genrand_res53(void) 
 { 
     unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
     return(a*67108864.0+b)*(1.0/9007199254740992.0); 
 } 

Почему a и b сдвинуты на 5 и 6 и почему после этого a * 67108864.0 + b является однородным?

Спасибо.

1 Ответ

1 голос
/ 29 марта 2011

Хорошие генераторы случайных чисел производят случайные биты во всех позициях.Определенные классы плохих производят плохую случайность в младших битах.Таким образом, если вам нужно 53 бита и сгенерировать 64, вы хотите отбросить 11 младших битов - в случае примера кода, который вы разместили, 5 из одного числа и 6 из другого.Теперь у вас есть 26-битное число и 27-битное число;2 ^ 26 - 67108864, а 2 ^ 53 - 9007199254740992, что должно объяснить, почему эти константы используются для масштабирования этих чисел в [0,1).(Это смешанное базовое число: 67108864 для первой цифры и 134217728 для второй.)

(причина, по которой часто используются 53 бита, состоит в том, что они делают числа симметричными при вычитании -в противном случае значения между 2 ^ -53 и 2 ^ -64 исчезнут, когда вы вычтете их из 1.)

Кроме того, вам не следует пересчитывать, когда у вас слишком много битов - просто отбрасывайте лишние биты(если у вас меньше одного).

В любом случае, очевидный метод дает вам [0,1).Если вы хотите (0,1), то это 1 - [0,1).Если вы хотите (0,1), попробуйте снова, если вы получите и a = 0, и b = 0.Если вы хотите [0,1], обратите внимание, что есть шанс 1 (2 ^ 53 + 1) получить 1, в противном случае у вас есть [0,1).Вы можете аппроксимировать это, получив случайное число в [0,1) и проверив, равняется ли оно нулю, и выбрав 1 в качестве ответа, если это так, или выбрав снова из [0,1), если нет.Вероятно, у вашего генератора случайных чисел недостаточно длинный период, чтобы быть более точным, чем этот.

...