【问题标题】:Generate a Random Number within a Range生成范围内的随机数
【发布时间】:2010-12-24 01:36:45
【问题描述】:

我以前做过这个,但现在我又遇到了麻烦,我想我不理解这个问题背后的数学原理。

我想在1 两侧的小范围内设置一个随机数。例如.981.02.941.1 等。我发现的所有示例都描述了在0100 之间获取一个随机数,但我如何使用它来进入我想要的范围?

编程语言在这里并不重要,尽管我使用的是 Pure Data。有人可以解释一下所涉及的数学吗?

【问题讨论】:

  • 如果你想要什么样的分布,多接近1才足够接近?
  • 随机数的界限是多少? 0.0 到 2.0?

标签: math random


【解决方案1】:

我不明白这个(对不起):

我正在尝试在 1 的任一侧设置一个随机数:.98、1.02、.94、1.1 等。

所以,我将为这个问题提供一个通用的解决方案。


转换随机数生成器

如果您有一个在给定范围 [0, 1)* 内具有均匀分布的随机数生成器,您可以使用以下方法将其转换为任何分布:

1 - 将分布描述为定义在输出范围内且总面积为 1 的函数。所以这个函数是 f(x) = 获得值 x 的概率。

2 - 集成**函数。

3 - 将其等同于“随机”*

4 - 求解 x 的方程。所以 ti 给你 x 在随机函数中的值。

*:任何输入分布的泛化如下。

**:积分函数的常数项为0(即丢弃)。

**:表示生成一个在[0, 1)范围内均匀分布的随机数的结果的变量。 [我不确定这是否是正确的英文名称]

示例

假设您想要一个分布为f(x)=x^2 from 0 to 100 的值。好吧,该函数没有标准化,因为该范围内函数下方的总面积是 1000000/3 而不是 1。所以你标准化它在垂直轴上缩放曲线(保持相对比例),即除以总面积:@ 987654323@.

现在,我们有一个总面积为 1 的函数。下一步是对它进行积分(您可能已经这样做以获得面积)并将其等同于随机数。

集成函数为:F(x)=x^3/1000000+c。并将其等同于随机数:r=x^3/1000000(请记住,我们丢弃了常数项)。

现在,我们需要求解 x 的方程,得到的表达式:x=100*r^(1/3)。现在您可以使用此公式生成具有所需分布的数字。

泛化

如果你有一个自定义分布的随机数生成器,并且想要另一个不同的任意分布,你首先需要源分布函数,然后用它来表达目标任意随机数生成器。要获得分布函数,请执行最多 3 步。对于目标,请执行所有步骤,然后将 randomic 替换为您从源分布中获得的表达式。

举个例子就更好理解了……

示例

您有一个在 [0, 100) 范围内均匀分布的随机数生成器,并且您想要.. 为简单起见,相同的分布 f(x)=3*x^2 / 1000000 from 0 to 100 [因为我们已经完成了所有步骤,为我们提供了 x=100*r^(1/3)] .

由于源分布是均匀的,因此函数是恒定的:f(z)=1。但我们需要对范围进行归一化,留下:f(z)=1/100

现在,我们整合它:F(z)=z/100。并将其等同于随机数:r=z/100,但这次我们不为 x 求解,而是用它来替换目标中的 r:

x=100*r^(1/3) where r = z/100
=>
x=100*(z/100)^(1/3)
=>
x=z^(1/3)

现在您可以使用x=z^(1/3) 来计算分布f(x)=3*x^2 / 1000000 from 0 to 100 的随机数,从分布f(z)=1/100 from 0 to 100 中的一个随机数开始[uniform]。

注意:如果您有正态分布,请改用 bell 函数。相同的方法适用于任何其他发行版。注意某些分布可能产生的渐近线,您可能需要尝试不同的方法来求解方程。

关于离散分布

有时您需要表达离散分布,例如,您希望以 95% 的机会获得 0,以 5% 的机会获得 1。那你是怎么做到的呢?

好吧,您将其划分为矩形分布,使范围连接到 [0, 1) 并使用随机数进行评估:

         0 if r is in [0, 0.95)
f(r) = {
         1 if r is in [0.95, 1)

或者你可以走复杂的路径,就是这样写一个分布函数(让每个选项正好是长度为1的范围):

         0.95 if x is in [0, 1)
f(x) = {
         0.5 if x is in [1, 2)

由于每个范围的长度为 1,并且分配的值总和为 1,我们知道总面积为 1。现在下一步是对其进行积分:

         0.95*x if x is in [0, 1)
F(x) = {
         (0.5*(x-1))+0.95 = 0.5*x + 0.45 if x is in [1, 2)

将其等同于随机:

         0.95*x if x is in [0, 1)
r = {
         0.5*x + 0.45 if x is in [1, 2)

然后解方程...

好的,要求解这种方程,首先通过应用函数计算输出范围:

[0, 1) becomes [0, 0.95)
[1, 2) becomes [0.95, {(0.5*(x-1))+0.95 where x = 2} = 1)

现在,这些是解决方案的范围:

         ? if r is in [0, 0.95)
x = {
         ? if r is in [0.95, 1)

现在,解决内部函数:

         r/0.95 if r is in [0, 0.95)
x = {
         2*(r-0.45) = 2*r-0.9 if r is in [0.95, 1)

但是,由于输出是离散的,我们在做整数部分后得到相同的结果:

         0 if r is in [0, 0.95)
x = {
         1 if r is in [0.95, 1)

注意:使用随机表示伪随机。


编辑:找到on wikipedia(我知道不是我发明的)。

【讨论】:

    【解决方案2】:

    对于从 0.9 到 1.1 的数字

    种子 = 1

    范围 = 0,1

    如果你的随机数来自 0..100

    f_rand = 随机/100

    生成的数字

    gen_number = (seed+f_rand*range*2)-range

    你会得到 1,04; 1,08; 1,01; 0,96; ...

    种子 3,范围 2 => 1,95; 4,08; 2,70; 3,06; ...

    【讨论】:

      【解决方案3】:

      多近?您可以使用平均值为 1 且标准差较小的 Gaussian (a.k.a. Normal) distribution

      如果您希望接近 1 的数字比远离 1 的数字更频繁,则适合使用高斯。

      某些语言 (such as Java) 将在标准库中支持高斯。

      【讨论】:

        【解决方案4】:

        Box-Müller 来救援。

        var z2_cached;
        function normal_random(mean, variance) {
        
            if ( z2_cached ) {
                    var z2 = z2_cached;
                    z2_cached = 0
                    return z2 * Math.sqrt(variance) + mean;
            }
        
            var x1 = Math.random();
            var x2 = Math.random();
        
            var z1 = Math.sqrt(-2 * Math.log(x1) ) * Math.cos( 2*Math.PI * x2);
            var z2 = Math.sqrt(-2 * Math.log(x1) ) * Math.sin( 2*Math.PI * x2);
        
            z2_cached = z2;
            return z1 * Math.sqrt(variance) + mean;
        }
        

        与均值 1 和方差的值一起使用,例如0.01

        for ( var i=0; i < 20; i++ ) console.log( normal_random(1, 0.01) );
        0.937240893365304
        1.072511121460833
        0.9950053748909895
        1.0034139439164074
        1.2319710866884104
        0.9834737343090275
        1.0363970887198277
        0.8706648577217094
        1.0882382154101415
        1.0425139197341595
        0.9438723605883214
        0.935894021237943
        1.0846400276817076
        1.0428213927823682
        1.020602499547105
        0.9547701472093025
        1.2598174560413493
        1.0086997644531541
        0.8711594789918106
        0.9669499056660755
        

        函数给出大约。具有给定方差的均值正态分布。

        【讨论】:

          【解决方案5】:
          var randomNumber = Math.random();
          while(randomNumber<0.9 && randomNumber>0.1){
              randomNumber = Math.random();
          }
          
          if(randomNumber>=0.9){
              alert(randomNumber);
          }
          else if(randomNumber<=0.1){
              alert(1+randomNumber);
          }
          

          【讨论】:

            【解决方案6】:

            您在寻找随机号码吗?从范围 1 到 2,例如 1.1、1.5、1.632 等。如果是,那么这里是一个简单的 python 代码:

            import random
            print (random.random%2)+1
            

            【讨论】:

              【解决方案7】:

              一般来说,要获得一个范围内的随机数,您不会获得介于0100 之间的数字,而是获得介于01 之间的数字。但是,这无关紧要,因为您可以通过将 # 除以 100 来简单地得到 0-1 数字 - 所以我不会强调这一点。

              在考虑其伪代码时,您需要将01 之间的数字视为百分比。换句话说,如果我在ab 之间有一个任意范围,那么两个端点之间的百分比 就是我随机选择的点。 (因此0.52的随机结果意味着52%ab之间的距离)

              考虑到这一点,这样考虑问题:

              1. 设置范围的起点和终点。

                var min = 0.9;

                var max = 1.1;

              2. 获取01之间的随机数

                var random = Math.random();

              3. 获取起点和终点之间的差异 (b - a)

                var range = max - min;

              4. 将随机数乘以差

                var adjustment = range * random;

              5. 加回你的最小值。

                var result = min + adjustment;

              而且,这样你就可以按顺序理解每一步的值了:

              var min = 0.9;
              var max = 1.1;
              var random = Math.random();      // random     == 0.52796 (for example)
              var range = max - min;           // range      == 0.2
              var adjustment = range * random; // adjustment == 0.105592
              var result = min + adjustment;   // result     == 1.005592
              

              请注意,结果保证在您的范围内。最小随机值为0,最大随机值为1。在这两种情况下,会发生以下情况:

              var min = 0.9;
              var max = 1.1;
              var random = Math.random();      // random     == 0.0 (minimum)
              var range = max - min;           // range      == 0.2
              var adjustment = range * random; // adjustment == 0.0
              var result = min + adjustment;   // result     == 0.9 (the range minimum)
              
              var min = 0.9;
              var max = 1.1;
              var random = Math.random();      // random     == 1.0 (maximum)
              var range = max - min;           // range      == 0.2
              var adjustment = range * random; // adjustment == 0.2
              var result = min + adjustment;   // result     == 1.1 (the range maximum)
              

              【讨论】:

                【解决方案8】:

                Rand() 已经为您提供了一个介于 0 和 100 之间的随机数。您可以获得的最大不同随机数是 100,因此假设您想要最多三个十进制数 0.950-1.050 是您要查看的范围.

                然后可以通过

                来实现分发
                0.95 + ((rand() / 100) 
                

                【讨论】:

                  【解决方案9】:

                  您可以通过changing variable 在范围 [0,1) 内构建任何您喜欢的均匀分布。特别是,如果您想要一些具有累积分布函数 F 的随机分布,您只需将 [0,1) 中的均匀随机替换为所需 CDF 的逆函数。

                  一个特殊的(也许是最流行的)情况是正态分布 N(0,1)。在这里你可以使用Box-Muller transform。使用 stdev 对其进行缩放并添加一个平均值,您可以获得具有所需参数的正态分布。

                  您可以对均匀随机数求和并得到一些正态分布的近似值,上面的 Nick Fortescue 考虑了这种情况。

                  如果您的源随机数是整数,您应该首先在实域中构造一个具有某些已知分布的随机数。例如,[0,1) 中的均匀分布可以这样构造。你得到0到99范围内的第一个整数,乘以0.01,得到第二个整数,乘以0.0001并添加到第一个等等。这样你就得到了一个数字 0.XXYYZZ... 双精度大约是 16 个十进制数字,所以你需要 8 个整数随机数来构造双均匀数。

                  【讨论】:

                    【解决方案10】:

                    制服

                    如果您想要 0.9 和 1.1 之间的(伪)均匀分布(均匀分布),那么以下方法将起作用:

                      range = 0.2
                      return 1-range/2+rand(100)*range/100
                    

                    相应地调整范围。

                    伪正常

                    如果您想要一个正态分布(钟形曲线),则需要特殊代码,这将是特定于语言/库的。您可以使用以下代码获得近似值:

                    sd = 0.1
                    mean = 1
                    count = 10
                    sum = 0
                    for(int i=1; i<count; i++) 
                      sum=sum+(rand(100)-50)
                    }
                    normal = sum / count
                    normal = normal*sd + mean
                    

                    【讨论】:

                    • 制服? p(0.9) != p(0.9001)。我承认这是 IEEE754 的一个重要问题。
                    • 公平点-但鉴于问题缺乏精确性,我怀疑这对提问者来说很重要。伪制服会公平吗? :-)
                    • 这很好,但也许应该提到 rand 的参数是什么意思?有时标准库随机数函数会给你一个从 0..1 开始的浮点数,这取决于语言 - rand(100) 是一个非常 BASIC 风格的东西......
                    【解决方案11】:

                    您希望从 -1 到 1 的范围作为 rand() 表达式的输出。

                    ( rand(2) - 1 )
                    

                    然后根据需要缩放 -1 到 1 的范围。比如说,对于任一侧的 .1 变体:

                    (( rand(2) - 1 ) / 10 )
                    

                    然后添加一个。

                    (( rand(2) - 1 ) / 10 ) + 1
                    

                    【讨论】:

                      【解决方案12】:

                      如果 rand() 返回一个介于 0 到 100 之间的随机数,那么你需要做的就是:

                      (rand() / 100) * 2
                      

                      获取 0 到 2 之间的随机数。

                      另一方面,如果您想要 0.9 到 1.1 的范围,请使用以下内容:

                      0.9 + ((rand() / 100) * 0.2)
                      

                      【讨论】:

                        【解决方案13】:

                        low + (random() / 100) * range

                        例如:

                        0.90 + (random() / 100) * 0.2

                        【讨论】:

                          【解决方案14】:
                          return 0.9 + rand(100) / 500.0
                          

                          还是我错过了什么?

                          【讨论】:

                            【解决方案15】:

                            除以 100 并加 1。(我假设您正在寻找从 0 到 2 的范围?)

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2011-03-01
                              • 2016-05-04
                              • 2010-11-26
                              • 1970-01-01
                              相关资源
                              最近更新 更多