【问题标题】:What's the correct way to expand a [0,1] interval to [a,b]?将 [0,1] 区间扩展到 [a,b] 的正确方法是什么?
【发布时间】:2010-06-14 09:37:06
【问题描述】:

许多随机数生成器返回 0 到 1 之间的浮点数。

ab 之间获得 整数 的最佳和正确方法是什么?

【问题讨论】:

  • 您是否希望 b 在“正常” ([0,1]) 随机数中与 1.0 一样不可能?还是这个范围内的所有整数都应该有相同的概率?
  • @Tim:所有整数应该具有相同的概率。 (这就是让它变得更难的原因。)
  • 如果 (B-A) = n,则应将 [0,1] 中的 n+1 个区间(bins)映射到 [A,B] 中的整数 构造区间的方法是取 (n ) 区间 [0,1] 的除法(一个除法,即 0.5 映射到两个连续整数 A,A+1)。如果随机数在区间 (i) 中,则对应的整数为 A+i-1。

标签: language-agnostic random


【解决方案1】:

将区间 [0,1] 划分为 B-A+1 个 bin

示例 A=2,B=5

        [----+----+----+----]
        0    1/4  1/2  3/4  1
Maps to    2    3    4    5

公式的问题

 Int (Rnd() * (B-A+1)) + A

是你的 Rnd() 生成间隔在两边都是闭合的,因此 0 和 1 都是可能的输出,当 Rnd() 正好为 1 时,公式给出 6。

在真正的随机分布(非伪)中,1 的概率为零。我认为编写如下代码足够安全:

 r=Rnd()
 if r equal 1
     MyInt = B
 else
     MyInt = Int(r * (B-A+1)) + A
 endif

编辑

Mathematica 中快速测试一下:

定义我们的函数:

f[a_, b_] :=  If[(r = RandomReal[]) == 1, b, IntegerPart[r (b - a + 1)] + a]

用 [1,100] 中的 3 个 10^5 数字建立一个表:

table = SortBy[Tally[Table[f[1, 100], {300000}]], First]

检查最小值和最大值:

In[137]:= {Max[First /@ table], Min[First /@ table]}

Out[137]= {100, 1}  

让我们看看分布:

BarChart[Last /@ SortBy[Tally[Table[f[1, 100], {300000}]], First],
        ChartStyle -> "DarkRainbow"]  

【讨论】:

  • 或者,如果您愿意,将 6 映射到 2 而不是 5 // mod(Int(r*(B-A+1), (B-A+1)))+A
  • 在 Python 中,random.random() 返回一个介于 0 和“刚好低于”1 之间的值,因此伪随机数也是安全的。见stackoverflow.com/questions/3037952
  • @Tim Pietzcker 很好! (虽然依赖于实现)
  • @user359996 这个问题被标记为“与语言无关”,所以我试图给出一个一般性的答案。我相信该算法的工作原理与源区间的开放性无关。数学中的常用符号是使用“[..]”表示闭区间,“(..)”表示开区间。 OP使用“[..]”
【解决方案2】:
X = (Rand() * (B - A)) + A

【讨论】:

【解决方案3】:

另一种看待它的方式,其中 r 是 0 到 1 范围内的随机数:

(1-r)a + rb

至于您对结果是整数的额外要求,也许(除了使用内置转换)模数运算符可以帮助您。看看这个问题和答案:

Expand a random range from 1–5 to 1–7

【讨论】:

  • 我不认为链接的问题在这里有用,因为在那个问题中生成的随机数是一个整数值。
  • 在问题中,粗体字是什么?
  • 我认为 Joachim Sauer 指的是输入,而不是输出。在链接的问题中,返回 1 到 5 之间的随机整数的函数被转换为返回 1 到 7 之间的整数的函数。这些问题不等价。
  • @Tim - 是的。我可能不应该把这个问题联系起来,但我会把它留在那里。它可能会给某人一个想法。
【解决方案4】:

好吧,为什么不直接看看 Python 是如何做到的呢?在安装的lib 目录中读取random.py

在将其删除为仅支持 random.randint() 的行为(这是您想要的)并删除对非整数或越界参数的所有错误检查后,您会得到:

import random
def randint(start, stop):
    width = stop+1 - start
    return start + int(random.random()*width)

测试:

>>> l = []
>>> for i in range(2000000):
...     l.append(randint(3,6))
...
>>> l.count(3)
499593
>>> l.count(4)
499359
>>> l.count(5)
501432
>>> l.count(6)
499616
>>>

【讨论】:

    【解决方案5】:

    假设r_a_bab 之间的所需随机数,r_0_101 之间的随机数,以下应该可以正常工作:

    r_a_b = (r_0_1 * (b-a)) + a
    

    【讨论】:

    • 对不起,我忘了补充说我对整数感兴趣。
    • @Ralph:Georg 在我发布此答案后添加了他需要整数结果的信息,而对于浮点结果,我的代码是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 2020-02-13
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多