我试图生成一个数字,它遵循一个周期增加的余弦曲线。目标是生成0和1之间的数字,但能够提供幅度/因子和周期/间隔。
例如,给定以下:
10_000.times.map do
num = randcos(factor: 5, intervals: 3)
(num * 13).floor # Group in 12 groups for graphing visibility
end
然后根据频率绘制这些点,我想要一个看起来像这样的图表:
因为我们设置了intervals: 3
,所以我们有3个“尖峰”,这些数字组更有可能。低点仍然会出现,但可能性约为1/5,因为我们设置了factor: 5
。
我一直在尝试使用Math.cos
来实现这一点,但是当我试图将这些更高的数字Map到生成新集合的可能性时,我被卡住了。我可以让它显示一个“尖峰”只使用Math.sin/Math.cos
,但我希望能够自定义有多少他们显示。
下面是我最近一次迭代的一个例子,尽管它只有一个降序图:
def randcos(factor:, intervals:)
max_scale = intervals*Math::PI
min_scale = -max_scale
# Grab a random index and apply it to the squished cos
x = min_scale + (2 * max_scale * rand)
num = (Math.cos(x)+1)/2 # Normalize 0..1 instead of -1..1
# Trying to use the `num` from above to then multiply by the factor to give us
# more likely high numbers when the cos is nearer to 1
rand * num * factor
end
1条答案
按热度按时间368yc8dk1#
这听起来像一个有趣的问题,所以我试了一下。这段代码是用javascript写的,因为我比ruby更熟悉它,也因为它可以嵌入到S.O.中,但原理是一样的,你应该能够翻译它。
我分三部分做了这件事。
1.余弦公式
我们需要一个余弦函数,在最可能的数字和最不可能的数字之间具有给定的幅度。你把它命名为
factor
。我们还希望该函数在最小值处开始和结束,并达到最大值一定次数。您将其命名为
intervals
。这个函数看起来像:
其中a表示
intervals
,b表示factor
。在这个例子中,我使用了因子5和间隔3来生成这个图。这个函数允许我输入任何x来得到它的相对概率。
转换为JS代码的函数看起来像这样:
2.概率权重预计算。
现在我们有了这个函数,我们可以确定任何数字出现的可能性有多大。
Math.random()
总是返回一个介于0和1之间的数字,我们希望将该值Map到可能值的范围。在您的示例中,这是0 - 12或13个可能的值。我们上面定义的函数的域是[0,1],所以我们将其分成13个相等的步骤来计算每个数字的概率。
然后,我们将对每个权重进行累积求和,以使
weights
数组中的每个值等于其自身加上前面所有权重的总和。这为我们提供了每个指数的值范围,但比例是关闭的。为了解决这个问题,我们只需将数组中的每个值除以最大值(或最后一个值)。3.Map值。
现在我们已经有了一个权重范围数组,我们可以简单地调用
Math.random()
来获得一个随机数,并将其Map到基于权重范围的可能值。假设我有这些权重:
[0.1, 0.3, 0.6, 1]
如果我调用
Math.random()
并得到0.4
,它将Map到索引2,因为0.4
在0.3
和0.6
之间。我们对预先计算的余弦权重做同样的事情。n = 13,factor = 5,intervals = 3的实际权重数组如下所示:
代码的最后一部分只是计算10,000个随机数,对它们进行排序,并将它们Map到各自的索引。我这样做是为了模拟10,000次运行的性能,但使用权重数组,您可以直接将[0,1]之间的任何随机数Map到其相应的权重。
最终的输出被打印到控制台,它看起来与您的问题中的模型图非常相似。在我的例子中,我得到: