Код для генерации случайных чисел Гаусса (нормально распределенных) в Ruby
Что такое код для генерации нормально распределенных случайных чисел в рубине?
(Примечание: я ответил на свой вопрос, но я подожду несколько дней, прежде чем принимать, чтобы узнать, есть ли у кого лучший ответ.)
EDIT:
Для этого я просмотрел все страницы на SO в результате двух поисков:
+ "нормальное распределение" ruby
и
+ гауссовский + случайный рубин
Ответы
Ответ 1
Python random.gauss() и Boost normal_distribution оба используют Box-Muller transform, так что это тоже должно быть достаточно для Ruby.
def gaussian(mean, stddev, rand)
theta = 2 * Math::PI * rand.call
rho = Math.sqrt(-2 * Math.log(1 - rand.call))
scale = stddev * rho
x = mean + scale * Math.cos(theta)
y = mean + scale * Math.sin(theta)
return x, y
end
Метод может быть завернут в класс, который возвращает образцы по одному.
class RandomGaussian
def initialize(mean, stddev, rand_helper = lambda { Kernel.rand })
@rand_helper = rand_helper
@mean = mean
@stddev = stddev
@valid = false
@next = 0
end
def rand
if @valid then
@valid = false
return @next
else
@valid = true
x, y = self.class.gaussian(@mean, @stddev, @rand_helper)
@next = y
return x
end
end
private
def self.gaussian(mean, stddev, rand)
theta = 2 * Math::PI * rand.call
rho = Math.sqrt(-2 * Math.log(1 - rand.call))
scale = stddev * rho
x = mean + scale * Math.cos(theta)
y = mean + scale * Math.sin(theta)
return x, y
end
end
(CC0)
Насколько это возможно по закону, antonakos отказался от всех авторских и смежных или смежных прав класса RandomGaussian
Ruby. Эта работа опубликована: Дания.
Заявление о лицензии не означает, что я забочусь об этом коде. Напротив, я не использую код, я его не тестировал, и я не программирую в Ruby.
Ответ 2
Оригинальный вопрос, заданный для кода, но комментарий к комментарию автора подразумевает интерес к использованию существующих библиотек. Меня интересовало то же самое, и мои поиски показали эти два рубиновых камня:
gsl - "Интерфейс Ruby для научной библиотеки GNU" (вам необходимо установить GSL). Вызывающая последовательность для нормально распределенных случайных чисел со средним значением = 0 и заданным стандартным отклонением составляет
rng = GSL::Rng.alloc
rng.gaussian(sd) # a single random sample
rng.gaussian(sd, 100) # 100 random samples
rubystats - "порт библиотек статистики из PHPMath" (чистый рубин). Вызывающая последовательность для нормально распределенных случайных чисел с заданным средним и стандартным отклонением
gen = Rubystats::NormalDistribution.new(mean, sd)
gen.rng # a single random sample
gen.rng(100) # 100 random samples
Ответ 3
+1 на ответ @antonakos. Здесь реализация Box-Muller, которую я использовал; это существенно идентичный, но немного более жесткий код:
class RandomGaussian
def initialize(mean = 0.0, sd = 1.0, rng = lambda { Kernel.rand })
@mean, @sd, @rng = mean, sd, rng
@compute_next_pair = false
end
def rand
if (@compute_next_pair = [email protected]_next_pair)
# Compute a pair of random values with normal distribution.
# See http://en.wikipedia.org/wiki/Box-Muller_transform
theta = 2 * Math::PI * @rng.call
scale = @sd * Math.sqrt(-2 * Math.log(1 - @rng.call))
@g1 = @mean + scale * Math.sin(theta)
@g0 = @mean + scale * Math.cos(theta)
else
@g1
end
end
end
Конечно, если вы действительно заботитесь о скорости, вы должны реализовать Алгоритм Зиггурата:).
Ответ 4
Другой вариант, который используется с помощью distribution, написанного одним из стипендиатов SciRuby.
Это немного проще использовать, я думаю.
require 'distribution'
normal = Distribution::Normal.rng(1)
norm_distribution = 1_000.times.map {normal.call}