如何在C#中生成介于0和1之间的随机数?

时间:2017-01-29 19:12:59

标签: c# .net random

我想得到1到0之间的随机数。但是,我每次都得0。有人可以解释我为什么一直都是0的原因吗? 这是我试过的代码。

Random random = new Random();
int test = random.Next(0, 1);
Console.WriteLine(test);
Console.ReadKey();

6 个答案:

答案 0 :(得分:15)

根据documentationNext返回(包含)最小值与(不包括)最大值之间的整数随机数:

  

返回值

     

大于或等于minValue且小于maxValue的32位有符号整数;也就是说,返回值的范围包括minValue但不包括maxValue。如果minValue等于maxValue,则返回minValue。

唯一符合

的整数
0 <= x < 1

0,因此您始终获得值0。换句话说,0是半闭区间[0, 1)内唯一的整数。

因此,如果您确实对整数值01感兴趣,请使用2作为上限:

var n = random.Next(0, 2);

如果您希望获得0到1之间的小数,请尝试:

var n = random.NextDouble();

希望这会有所帮助: - )

答案 1 :(得分:4)

你可以,但你应该这样做:

double test = random.NextDouble();

如果你想获得随机整数(0或1),你应该将上限设置为2,因为它是独占

int test = random.Next(0, 2);

答案 2 :(得分:2)

本页上关于双打的每个答案都是错误的,这很有趣,因为每个人都在引用文档。如果使用NextDouble()生成双精度数,则不会得到0到1之间(包括1)的数字,而不会得到0到1之间的数字(不包括1)。

要获得双倍奖赏,您将需要执行以下操作:

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

然后致电

NextRandomRange(0,1 + Double.Epsilon);

看起来像那样行得通,不是吗? 1 + Double.Epsilon在使用double时应该是1之后的第二大数字,对吗?这是解决int问题的方法。

Wellllllllllllllll .........

我怀疑这将无法正常工作,因为基础代码将生成一些字节的随机性,然后执行一些数学技巧以使其符合预期范围。简短的答案是,适用于int的逻辑在使用浮点数时工作原理并不完全相同。

让我们看看吧? (https://referencesource.microsoft.com/#mscorlib/system/random.cs,e137873446fcef75

  /*=====================================Next=====================================
  **Returns: A double [0..1)
  **Arguments: None
  **Exceptions: None
  ==============================================================================*/
  public virtual double NextDouble() {
    return Sample();
  }

Sample()到底是什么?

  /*====================================Sample====================================
  **Action: Return a new random number [0..1) and reSeed the Seed array.
  **Returns: A double [0..1)
  **Arguments: None
  **Exceptions: None
  ==============================================================================*/
  protected virtual double Sample() {
      //Including this division at the end gives us significantly improved
      //random number distribution.
      return (InternalSample()*(1.0/MBIG));
  }

好的,开始到某个地方。 MBIG顺便说一句,是Int32.MaxValue(2147483647或2 ^ 31-1),这使得除法运算如下:

InternalSample()*0.0000000004656612873077392578125;

好吧,InternalSample()到底是什么?

  private int InternalSample() {
      int retVal;
      int locINext = inext;
      int locINextp = inextp;

      if (++locINext >=56) locINext=1;
      if (++locINextp>= 56) locINextp = 1;

      retVal = SeedArray[locINext]-SeedArray[locINextp];

      if (retVal == MBIG) retVal--;          
      if (retVal<0) retVal+=MBIG;

      SeedArray[locINext]=retVal;

      inext = locINext;
      inextp = locINextp;

      return retVal;
  }

嗯...就是这样。但是,这个SeedArray和inext废话到底是什么?

  private int inext;
  private int inextp;
  private int[] SeedArray = new int[56];

所以事情开始融为一体。种子数组是一个整数数组,用于从中生成值。如果您看一下init函数def,您会发现要进行大量的位加法运算和技巧运算,可以将55个值的数组随机化为初始准随机值。

  public Random(int Seed) {
    int ii;
    int mj, mk;

    //Initialize our Seed array.
    //This algorithm comes from Numerical Recipes in C (2nd Ed.)
    int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
    mj = MSEED - subtraction;
    SeedArray[55]=mj;
    mk=1;
    for (int i=1; i<55; i++) {  //Apparently the range [1..55] is special (All hail Knuth!) and so we're skipping over the 0th position.
      ii = (21*i)%55;
      SeedArray[ii]=mk;
      mk = mj - mk;
      if (mk<0) mk+=MBIG;
      mj=SeedArray[ii];
    }
    for (int k=1; k<5; k++) {
      for (int i=1; i<56; i++) {
    SeedArray[i] -= SeedArray[1+(i+30)%55];
    if (SeedArray[i]<0) SeedArray[i]+=MBIG;
      }
    }
    inext=0;
    inextp = 21;
    Seed = 1;
  }

好吧,回到InternalSample(),我们现在可以看到通过获取两个加扰的32位整数的差,将结果限制在0到2147483647-1之间,然后乘以结果,可以生成随机双精度数通过1/2147483647。在使用种子值时,要花更多的时间来加扰种子值列表,但实际上就是这样。

(有趣的是,获得2到31-2范围内任何数字的机会大约是1 / r,这是2 *(1 / r)!因此,如果您认为某些dumbass编码器是使用RandNext()在视频扑克机上生成数字,您应该始终下注2 ^ 32-2!这就是为什么我们不对任何重要的东西使用Random的原因之一...

因此,如果InternalSample()的输出为0,我们将其乘以0.0000000004656612873077392578125并得到0,即我们范围的底端。如果我们得到2147483646,我们最终得到0.9999999995343387126922607421875,那么NextDouble产生[0,1)结果的说法是...对吗?准确地说,它是[0,0.9999999995343387126922607421875]的范围。

我建议的上述解决方案将落在它的表面上,因为double.Epsilon = 4.94065645841247E-324,它比0.0000000004656612873077392578125(您要加到上面的结果中得到1的值)还小。

具有讽刺意味的是,如果不是要在InternalSample()方法中减去1:

if (retVal == MBIG) retVal--;

在返回的返回值中我们可以达到1。因此,要么复制Random类中的所有代码,然后省略retVal--行,要么将NextDouble()输出乘以1.0000000004656612612875245796924106之类的值,以稍微拉伸输出范围以使其包含1。实际测试该值可以使我们真正接近,但我不知道我进行的几亿次测试是否未产生2147483646(很有可能)或方程中是否存在浮点误差。我怀疑前者。数百万次测试不太可能产生20亿分之一的赔率。

NextRandomRange(0,1.0000000004656612875245796924106); // try to explain where you got that number during the code review...

TLDR?包含随机双打的包容范围非常棘手...

答案 3 :(得分:1)

因为Random.Next(a,b)返回范围[a,b]中的数字,大于或等于a,小于b,所以你得到零。

如果你想获得{0,1}中的一个,你应该使用:

var random = new Random();
var test = random.Next(0, 2);

答案 4 :(得分:0)

因为您要求的数字小于1

documentation说:

  

返回值
  大于或等于minValue且小于maxValue的32位有符号整数;也就是说,返回值的范围   包括minValue但不包括maxValue。如果minValue等于maxValue,   返回minValue。

答案 5 :(得分:0)

如果您要定位0.0到1.0

,请重写这样的代码
Random random = new Random();

double test = random.NextDouble();

Console.WriteLine(test);

Console.ReadKey();