假设我有大量现金,我想以500美元到5,000美元之间的随机增量给出。我希望范围的下端比更高的范围更可能。我能用Ruby编写哪种最有效的算法,以这种方式随机分发现金?
答案 0 :(得分:2)
我认为最简单的方法就是使用case语句:
def get_price
case rand(100) + 1
when 1..50 then 500
when 50..75 then 1000
when 75..99 then 2500
when 99..100 then 10000
end
end
p get_price # => 500
调用get_price将以50%的概率返回500,但10000只会在2%的时间内返回。
答案 1 :(得分:1)
一种方法是首先定义多个范围并为每个范围分配概率“权重”。这是一个例子:
weights = {[500, 1000] => 17,
[1001, 1500] => 15,
[1501, 2000] => 13,
[2001, 2500] => 12,
[2501, 3000] => 11,
[3001, 3500] => 10,
[3501, 4000] => 10,
[4001, 4500] => 10,
[4501, 5000] => 10}
此处,重量为15的范围[1001, 1500]
比四个最高范围中的任何一个都更容易被选择,每个范围的权重为10.您可以拥有任意数量的范围和(如此处)权重不需要总和为100.这里你可以用单一范围[3001, 5000] => 40
替换四个最高范围。
我们的想法是随机选择一个范围,使用您提供的权重,然后选择该范围内的随机值,其中范围内的每个值都可以选择。
ranges = weights.keys # => [[500, 1000], [1001, 1500],.., [4501, 5000]]
cum_wights = weights.values # => [17, 15,.., 10]
(1..weights.size-1).each {|i| cum_weights[i] += cum_weights[i-1]}
# cum_weights => [17, 32,.., 108]
# Obtain range randomly
rn = rand(cum_weights) # => random number between 0 and cum_weights.last (here 108)
i = 0 # range index
i += 1 while cum_weights[i] <= rn
rr = ranges[i] # random range
# Obtain uniform random value in range rr
# Obtain uniform random value in range i
# Since `rn` is equally-likely for any value in `rr`,
cwt_min, cwt_max = (i > 0 ? cum_weights[i-1] + 1 : 0), cum_weights[i]
random_amount = rr.first + ((rn - cwt_min).to_f/(cwt_max - cwt_min + 1)) * (rr.last-rr.first + 1)
或简单地生成另一个随机数:
random_amount = rr.first + rand(rr.last-rr.first)
顺便说一下,我在随意赠送金钱方面非常有经验。如果我能提供帮助,请告诉我。
答案 2 :(得分:-1)
听起来你想生成一个随机数字,其高斯(也就是正常)分布向左倾斜(或者右边,我永远不能让它们保持笔直;驼峰在左边)。
这里采用VBA实现的偏差正态分布采样算法(警告:弹出窗口):http://www.ozgrid.com/forum/showthread.php?t=108175
把它翻译成红宝石应该不难。