- Анатолий М. Георгиевский, ИТМО
Преобразование чисел в формат float32 дает однородное распределение [0,1) вероятности
static inline float u64_float(uint64_t x) {
return ((x&0xFFFFFFFFU) >> 8) * 0x1.0p-24;
}
float uniform (uint64_t *state) {
return u64_float(mwc64x(state));
}
Аналогично получается преобразование в формат double
, и системные форматы включая: _Float32x
, _Float32
и _Float16
, с учетом разрядности мантиссы. Из личного опыта, рекомендуется использовать только младшую часть числа 32-бита, чтобы избежать водяных знаков, так как старшая и младшая часть числа связаны константой преобразования. При этом для улучшения однородности распределения можно использовать только нечетные или только нечетные вызовы функции. Для получения однородного распределения чисел в формате double
, _Float64
, _Float64x
рекомендуется использовать генератор MWC128.
The standard Box–Muller transform generates values from the standard normal distribution (i.e. standard normal deviates) with mean 0 and standard deviation 1.
Пусть
Тогда
float gaussian(uint64_t *state)
{
float u1 = uniform(state); // однородное распределение [0,1)
float u2 = uniform(state); // однородное распределение [0,1)
return sqrt(-2.0f*log(1.0f-u1))*cos(2*M_PI*u2);
}
В данном алгоритме применил трюк (1-U), что дает распределение (0,1]
Общая идея для получения заданной функции распределения - применить обратную функцию для отображения интервала выходных значений. Так, например, можно синтезировать функцию с экспоненциальным распределением вероятности.
float exponent(uint64_t *state) {
float u1 = uniform(state);
return -log(1.0f-u1);
}
By Davidjessop - Own work, CC BY-SA 4.0, Link
An animation of how inverse transform sampling generates normally distributed random values from uniformly distributed random values
Распределение Максвелла получается из идеи квадратичного суммирования функций в евклидовом пространстве. Данный метод закрывает потребности синтеза начальных условий в классической динамике и молекулярной динамике. Так начальное условие будет соответствовать нормальному распределению проекций скорости молекул и подчиняться распределению максвелла по скоростям.
float maxwell(uint64_t *state)
{
float x = gaussian(state);
float y = gaussian(state);
float z = gaussian(state);
return sqrtf(x*x + y*y + z*z);
}
Распределение Максвелла записывается для модуля скорости частицы и имеет плотность: