用于随机选取范围之间的数字的滑动概率标度

时间:2013-10-03 02:47:37

标签: ruby algorithm probability

假设我有大量现金,我想以500美元到5,000美元之间的随机增量给出。我希望范围的下端比更高的范围更可能。我能用Ruby编写哪种最有效的算法,以这种方式随机分发现金?

3 个答案:

答案 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

把它翻译成红宝石应该不难。