В вашем ответе есть три вопроса: приоритет операций в q
, как генерировать случайную переменную в [-1; 1] и условие для переменной sq
.
Приоритет операций:
Напомним, что ниже a1
и a2
различны:
u:rand[1f];
a1:-1+2.0*u;
a2:2.0*u-1;
u:0.5
a1:0f
a2:-1f
u:0
a1:-1f
a2:-2f
Генерация случайной величины в [-1; 1]:
Используйте следующее:
a:-1+2.0*rand[1.0];
b:-1+2.0*rand[1.0];
Состояние на sq
:
Вы действительно приняли во внимание условие sq >= 1
, но у вас также есть проблема, если sq = 0
, поскольку вы должны делить на sq
на последнем шаге.
Кроме того, в вашей реализации вы вычисляете a
дважды, что 1) не оптимально и 2) не соответствует методологии, поскольку тот же самый a
должен использоваться при вычислении sq
в последнем шаг, последний уступает очень большим числам. Я получил некоторое вдохновение со страницы википедии , где они предлагают восстановить sq
, если вышеуказанное условие не выполнено. Отсюда рекурсивный вызов функции в приведенной ниже реализации:
.stat.GetOneGaussianByBoxMuller:{
a:-1+2.0*rand[1.0];
b:-1+2.0*rand[1.0];
sq:(a*a)+(b*b);
if[(sq>=1)|(sq=0);
:.stat.GetOneGaussianByBoxMuller[];
];
:a*sqrt[(neg[2]*log[sq])%sq];
};
Теперь вы можете взглянуть на данные, сгенерированные путем построения гистограммы следующего набора данных:
([]val:{:.stat.GetOneGaussianByBoxMuller[]} each til 100000)
EDIT:
На самом деле вы могли бы иметь более эффективную реализацию, генерируя 2 случайных числа для вызова функции следующим образом:
.stat.GetOneGaussianByBoxMuller:{
a:-1+2.0*rand[1.0];
b:-1+2.0*rand[1.0];
sq:(a*a)+(b*b);
if[(sq>=1)|(sq=0);
:.stat.GetOneGaussianByBoxMuller[];
];
:(a*sqrt[(neg[2]*log[sq])%sq];b*sqrt[(neg[2]*log[sq])%sq]);
};
([]val:raze {.stat.GetOneGaussianByBoxMuller[]} each til 50000)
Эта реализация требует 150 мс для генерации 100000 нормально распределенных случайных чисел, в то время как приведенная выше занимает 245 мс.