What is some code to generate normally distributed random numbers in ruby?
在ruby中生成正态分布随机数的代码是什么?
(Note: I answered my own question, but I'll wait a few days before accepting to see if anyone has a better answer.)
(注:我已经回答了自己的问题,但我要等上几天,才能接受是否有更好的答案。)
EDIT:
编辑:
Searching for this, I looked at all pages on SO resulting from the two searches:
搜索这个,我查看了所有的页面,所以从这两个搜索结果:
+"normal distribution" ruby
ruby +“正态分布”
and
和
+gaussian +random ruby
+高斯随机ruby
4 个解决方案
#1
44
Python's random.gauss() and Boost's normal_distribution both use the Box-Muller transform, so that should be good enough for Ruby too.
Python的随机性.gauss()和Boost的normal_distribution都使用Box-Muller转换,因此对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
The method can be wrapped up in a class that returns the samples one by one.
方法可以封装在一个类中,该类逐个返回示例。
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)
To the extent possible under law, antonakos has waived all copyright and related or neighboring rights to the RandomGaussian
Ruby class. This work is published from: Denmark.
在法律允许的范围内,antonakos放弃了随机性高斯Ruby类的所有版权和相关或邻近的权利。本著作出版于:丹麦。
The license statement does not mean I care about this code. On the contrary, I don't use the code, I haven't tested it, and I don't program in Ruby.
许可声明并不意味着我关心这段代码。相反,我不使用代码,也没有测试它,也没有在Ruby中编程。
#2
19
The original question asked for code, but the author's followup comment implied an interest in using existing libraries. I was interested in the same, and my searches turned up these two ruby gems:
最初的问题需要代码,但是作者的后续评论暗示了对使用现有库的兴趣。我也有同样的兴趣,我的搜索发现了这两个红宝石宝石:
gsl - "Ruby interface to the GNU Scientific Library" (requires you to install GSL). The calling sequence for normally distributed random numbers with mean = 0 and a given standard deviation is
gsl -“GNU科学图书馆的Ruby接口”(要求您安装gsl)。均值为0且给定标准差的正态分布随机数的调用序列为
rng = GSL::Rng.alloc
rng.gaussian(sd) # a single random sample
rng.gaussian(sd, 100) # 100 random samples
rubystats - "a port of the statistics libraries from PHPMath" (pure ruby). The calling sequence for normally distributed random numbers with a given mean and standard deviation is
rubystats——“来自PHPMath的统计库的一个端口”(纯ruby)。具有给定均值和标准差的正态分布随机数的调用序列为
gen = Rubystats::NormalDistribution.new(mean, sd)
gen.rng # a single random sample
gen.rng(100) # 100 random samples
#3
10
+1 on @antonakos's answer. Here's the implementation of Box-Muller that I've been using; it's essentially identical but slightly tighter code:
+ 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 = !@compute_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
Of course, if you really cared about speed, you should implement the Ziggurat Algorithm :).
当然,如果你真的关心速度,你应该实现Ziggurat算法:)。
#4
10
Another option, this one using the distribution gem, written by one of the SciRuby fellows.
另一个选择,这个使用发行版gem,由一个SciRuby伙伴编写。
It is a little simpler to use, I think.
我认为它使用起来比较简单。
require 'distribution'
normal = Distribution::Normal.rng(1)
norm_distribution = 1_000.times.map {normal.call}
#1
44
Python's random.gauss() and Boost's normal_distribution both use the Box-Muller transform, so that should be good enough for Ruby too.
Python的随机性.gauss()和Boost的normal_distribution都使用Box-Muller转换,因此对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
The method can be wrapped up in a class that returns the samples one by one.
方法可以封装在一个类中,该类逐个返回示例。
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)
To the extent possible under law, antonakos has waived all copyright and related or neighboring rights to the RandomGaussian
Ruby class. This work is published from: Denmark.
在法律允许的范围内,antonakos放弃了随机性高斯Ruby类的所有版权和相关或邻近的权利。本著作出版于:丹麦。
The license statement does not mean I care about this code. On the contrary, I don't use the code, I haven't tested it, and I don't program in Ruby.
许可声明并不意味着我关心这段代码。相反,我不使用代码,也没有测试它,也没有在Ruby中编程。
#2
19
The original question asked for code, but the author's followup comment implied an interest in using existing libraries. I was interested in the same, and my searches turned up these two ruby gems:
最初的问题需要代码,但是作者的后续评论暗示了对使用现有库的兴趣。我也有同样的兴趣,我的搜索发现了这两个红宝石宝石:
gsl - "Ruby interface to the GNU Scientific Library" (requires you to install GSL). The calling sequence for normally distributed random numbers with mean = 0 and a given standard deviation is
gsl -“GNU科学图书馆的Ruby接口”(要求您安装gsl)。均值为0且给定标准差的正态分布随机数的调用序列为
rng = GSL::Rng.alloc
rng.gaussian(sd) # a single random sample
rng.gaussian(sd, 100) # 100 random samples
rubystats - "a port of the statistics libraries from PHPMath" (pure ruby). The calling sequence for normally distributed random numbers with a given mean and standard deviation is
rubystats——“来自PHPMath的统计库的一个端口”(纯ruby)。具有给定均值和标准差的正态分布随机数的调用序列为
gen = Rubystats::NormalDistribution.new(mean, sd)
gen.rng # a single random sample
gen.rng(100) # 100 random samples
#3
10
+1 on @antonakos's answer. Here's the implementation of Box-Muller that I've been using; it's essentially identical but slightly tighter code:
+ 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 = !@compute_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
Of course, if you really cared about speed, you should implement the Ziggurat Algorithm :).
当然,如果你真的关心速度,你应该实现Ziggurat算法:)。
#4
10
Another option, this one using the distribution gem, written by one of the SciRuby fellows.
另一个选择,这个使用发行版gem,由一个SciRuby伙伴编写。
It is a little simpler to use, I think.
我认为它使用起来比较简单。
require 'distribution'
normal = Distribution::Normal.rng(1)
norm_distribution = 1_000.times.map {normal.call}