【问题标题】:Random Number Between 2 Double Numbers两个双数之间的随机数
【发布时间】:2009-06-30 17:17:54
【问题描述】:

是否可以生成 2 个双精度数之间的随机数?

例子:

public double GetRandomeNumber(double minimum, double maximum)
{
    return Random.NextDouble(minimum, maximum) 
}

然后我用以下方式调用它:

double result = GetRandomNumber(1.23, 5.34);

任何想法都将不胜感激。

【问题讨论】:

    标签: c# random


    【解决方案1】:

    是的。

    Random.NextDouble 返回 0 和 1 之间的双精度值。然后将其乘以需要进入的范围(最大值和最小值之差),然后将其添加到基数(最小值)。

    public double GetRandomNumber(double minimum, double maximum)
    { 
        Random random = new Random();
        return random.NextDouble() * (maximum - minimum) + minimum;
    }
    

    真正的代码应该有随机的静态成员。这将节省创建随机数生成器的成本,并使您能够非常频繁地调用 GetRandomNumber。由于我们在每次调用时都会初始化一个新的 RNG,如果您调用的速度足够快以至于系统时间不会在两次调用之间发生变化,那么 RNG 将以完全相同的时间戳作为种子,并生成相同的随机数流。

    【讨论】:

    • 如果你在循环中调用 GetRandomNumber() 请注意,因为它会一遍又一遍地生成相同的值
    • 可能是一个不错的扩展方法,public double GetRandomNumber(this Random random, double minimum, double maximum) {...}
    • 请记住,由于 Random.NextDouble 永远不会返回 1.0,因此该函数也永远不会等于最大数。
    • 我建议将 new Random((int)DateTime.Now.Ticks) 作为种子,即使在快速循环中也应该使其“更加随机”。
    • 如果最小值为 double.MinValue 且最大值为 double.MaxValue,则此方法不起作用。有关如何处理此用例的任何建议?
    【解决方案2】:

    Johnny5 建议创建一个扩展方法。这是一个更完整的代码示例,展示了如何执行此操作:

    public static class RandomExtensions
    {
        public static double NextDouble(
            this Random random,
            double minValue,
            double maxValue)
        {
            return random.NextDouble() * (maxValue - minValue) + minValue;
        }
    }
    

    现在您可以将它当作Random 类的方法来调用:

    Random random = new Random();
    double value = random.NextDouble(1.23, 5.34);
    

    请注意,您不应在循环中创建大量新的Random 对象,因为这可能会导致您连续多次获得相同的值。如果您需要大量随机数,请创建一个 Random 实例并重新使用它。

    【讨论】:

      【解决方案3】:

      注意:如果您在循环中生成random,例如for(int i = 0; i < 10; i++),请不要将new Random() 声明放在循环中。

      来自MSDN

      随机数生成从种子值开始。如果一样 重复使用种子,生成相同的数字序列。一 产生不同序列的方法是使种子值 时间相关,从而产生不同的系列与每个新的 随机的实例。默认情况下,无参数构造函数 Random 类使用系统时钟来生成它的种子值...

      所以基于这个事实,做一些事情:

      var random = new Random();
      
      for(int d = 0; d < 7; d++)
      {
          // Actual BOE
          boes.Add(new LogBOEViewModel()
          {
              LogDate = criteriaDate,
              BOEActual = GetRandomDouble(random, 100, 1000),
              BOEForecast = GetRandomDouble(random, 100, 1000)
          });
      }
      
      double GetRandomDouble(Random random, double min, double max)
      {
           return min + (random.NextDouble() * (max - min));
      }
      

      这样做可以保证您得到不同的双精度值。

      【讨论】:

        【解决方案4】:

        我参加聚会有点晚了,但我需要实施一个通用解决方案,结果发现没有一个解决方案可以满足我的需求。

        公认的解决方案适用于小范围;但是,maximum - minimum 对于大范围可能是无穷大。所以修正后的版本可以是这个版本:

        public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
        {
            // TODO: some validation here...
            double sample = random.NextDouble();
            return (maxValue * sample) + (minValue * (1d - sample));
        }
        

        即使在double.MinValuedouble.MaxValue 之间也能很好地生成随机数。但这引入了另一个“问题”,很好地呈现了in this post:如果我们使用如此大的范围,这些值可能看起来太“不自然”。例如,在 0 和 double.MaxValue 之间生成 10,000 个随机双精度后,所有值都在 2.9579E+304 和 1.7976E+308 之间。

        所以我还创建了另一个版本,它以对数刻度生成数字:

        public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
        {
            // TODO: some validation here...
            bool posAndNeg = minValue < 0d && maxValue > 0d;
            double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
            double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));
        
            int sign;
            if (!posAndNeg)
                sign = minValue < 0d ? -1 : 1;
            else
            {
                // if both negative and positive results are expected we select the sign based on the size of the ranges
                double sample = random.NextDouble();
                var rate = minAbs / maxAbs;
                var absMinValue = Math.Abs(minValue);
                bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
                sign = isNeg ? -1 : 1;
        
                // now adjusting the limits for 0..[selected range]
                minAbs = 0d;
                maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
            }
        
            // Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
            // that would cause too many almost zero results, which are much smaller than the original NextDouble values.
            double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
            double maxExponent = Math.Log(maxAbs, 2d);
            if (minExponent == maxExponent)
                return minValue;
        
            // We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
            if (maxExponent < minExponent)
                minExponent = maxExponent - 4;
        
            double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));
        
            // protecting ourselves against inaccurate calculations; however, in practice result is always in range.
            return result < minValue ? minValue : (result > maxValue ? maxValue : result);
        }
        

        一些测试:

        以下是使用这两种策略生成 0 到 Double.MaxValue 之间的 10,000 个随机双精度数的排序结果。结果使用对数刻度显示:

        虽然线性随机值乍一看似乎是错误的,但统计数据表明它们都没有比另一个“更好”:即使线性策略也有均匀分布,并且值之间的平均差异几乎相同两种策略。

        玩不同的范围向我展示了线性策略变得“理智”,范围在 0 和 ushort.MaxValue 之间,“合理”的最小值为 10.78294704 (对于ulong 范围,最小值为 3.03518E+15;int: 353341)。以下是以不同比例显示的两种策略的相同结果:


        编辑:

        最近我将我的libraries 开源了,欢迎查看带有完整验证的RandomExtensions.NextDouble 方法。

        【讨论】:

          【解决方案5】:

          最简单的方法是简单地生成一个介于 0 和两个数字之差之间的随机数。然后将两个数字中较小的一个添加到结果中。

          【讨论】:

            【解决方案6】:

            你可以使用这样的代码:

            public double getRandomNumber(double minimum, double maximum) {
                return minimum + randomizer.nextDouble() * (maximum - minimum);
            }
            

            【讨论】:

              【解决方案7】:

              你可以这样做:

              public class RandomNumbers : Random
              {
                  public RandomNumbers(int seed) : base(seed) { }
              
                  public double NextDouble(double minimum, double maximum)
                  {
                      return base.NextDouble() * (maximum - minimum) + minimum;
                  }
              }
              

              【讨论】:

                【解决方案8】:

                如果其中一个值为负数怎么办?不是更好的主意:

                double NextDouble(double min, double max)
                {
                       if (min >= max)
                            throw new ArgumentOutOfRangeException();    
                       return random.NextDouble() * (Math.Abs(max-min)) + min;
                }
                

                【讨论】:

                • 我认为Math.Abs() 是多余的。既然您确定了min &gt;= max,那么max - min 无论如何都必须是一个非负数。
                【解决方案9】:

                关于在循环中调用它时生成相同的随机数,一个不错的解决方案是将循环外的新 Random() 对象声明为全局变量。

                请注意,如果要在循环中运行,则必须在 GetRandomInt 函数之外声明 Random 类的实例。

                “这是为什么?”你问。

                好吧,Random 类实际上生成伪随机数,随机化器的“种子”是系统时间。如果您的循环足够快,则系统时钟时间对于随机化器而言不会有所不同,并且 Random 类的每个新实例都将从相同的种子开始并为您提供相同的伪随机数。

                来源在这里:http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/

                【讨论】:

                • 这更适合作为评论,因为它甚至不尝试回答 OP 的实际问题。
                【解决方案10】:
                Random random = new Random();
                
                double NextDouble(double minimum, double maximum)
                {  
                
                    return random.NextDouble()*random.Next(minimum,maximum);
                
                }
                

                【讨论】:

                  【解决方案11】:

                  如果需要 [double.MinValue; 范围内的随机数; double.MaxValue]

                  // Because of:
                  double.MaxValue - double.MinValue == double.PositiveInfinity
                  
                  // This will be equals to NaN or PositiveInfinity
                  random.NextDouble() * (double.MaxValue - double.MinValue)
                  

                  改用:

                  public static class RandomExtensions
                  {
                      public static double NextDoubleInMinMaxRange(this Random random)
                      {
                          var bytes = new byte[sizeof(double)];
                          var value = default(double);
                          while (true)
                          {
                              random.NextBytes(bytes);
                              value = BitConverter.ToDouble(bytes, 0);
                              if (!double.IsNaN(value) && !double.IsInfinity(value))
                                  return value;
                          }
                      }
                  }
                  

                  【讨论】:

                  【解决方案12】:

                  使用静态随机数,否则由于系统时钟播种,数字往往会在紧密/快速的循环中重复。

                  public static class RandomNumbers
                  {
                      private static Random random = new Random();
                      //=-------------------------------------------------------------------
                      // double between min and the max number
                      public static double RandomDouble(int min, int max) 
                      {
                          return (random.NextDouble() * (max - min)) + min;
                      }
                      //=----------------------------------
                      // double between 0 and the max number
                      public static double RandomDouble(int max) 
                      {
                          return (random.NextDouble() * max);
                      }
                      //=-------------------------------------------------------------------
                      // int between the min and the max number
                      public static int RandomInt(int min, int max) 
                      {   
                          return random.Next(min, max + 1);
                      }
                      //=----------------------------------
                      // int between 0 and the max number
                      public static int RandomInt(int max) 
                      {
                          return random.Next(max + 1);
                      }
                      //=-------------------------------------------------------------------
                   }
                  

                  另请参阅:https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.8

                  【讨论】:

                    猜你喜欢
                    • 2015-01-20
                    • 2015-11-07
                    • 1970-01-01
                    • 2012-04-25
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-01-31
                    • 2015-02-12
                    • 2014-10-02
                    相关资源
                    最近更新 更多