-1

假设我有很多现金,我想以 500 美元到 5,000 美元之间的随机增量发放。我希望范围的下限比更高的范围更有可能。我可以用 Ruby 编写以这种方式随机发放现金的最有效算法是什么?

4

3 回答 3

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% 的时间返回。

于 2013-10-03T06:58:08.047 回答
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}

在这里,[1001, 1500]权重为 15 的范围 被选择的可能性比四个最高范围中的任何一个高 50%,每个范围的权重为 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)

顺便说一句,我在赠送随机金额方面非常有经验。让我知道我是否可以提供帮助。

于 2013-10-03T05:07:39.510 回答
-1

听起来您想生成具有向左(或向右,我永远无法保持笔直;驼峰在左侧)倾斜的高斯(又名正态)分布的随机数。

此处为采样倾斜正态分布的算法的 VBA 实现(警告:弹出窗口):http ://www.ozgrid.com/forum/showthread.php?t=108175

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

于 2013-10-03T02:57:13.200 回答