简体   繁体   English

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

[英]How do I generate random number between 0 and 1 in C#?

I want to get the random number between 1 and 0. However, I'm getting 0 every single time. 我想获得1到0之间的随机数。但是,我每次都得到0。 Can someone explain me the reason why I and getting 0 all the time? 有人可以向我解释为什么我总是得到0的原因吗? This is the code I have tried. 这是我尝试过的代码。

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

According to the documentation , Next returns an integer random number between the (inclusive) minimum and the (exclusive) maximum: 根据文档Next返回(最小)(最大值)(最大)之间的整数随机数:

Return Value 返回值

A 32-bit signed integer greater than or equal to minValue and less than maxValue; 一个大于或等于minValue且小于maxValue的32位有符号整数; that is, the range of return values includes minValue but not maxValue. 也就是说,返回值的范围包括minValue但不包括maxValue。 If minValue equals maxValue, minValue is returned. 如果minValue等于maxValue,则返回minValue。

The only integer number which fulfills 唯一满足的整数

0 <= x < 1

is 0 , hence you always get the value 0 . 0 ,因此您总是得到值0 In other words, 0 is the only integer that is within the half-closed interval [0, 1) . 换句话说, 0是半封闭间隔[0, 1)内的唯一整数。

So, if you are actually interested in the integer values 0 or 1 , then use 2 as upper bound: 因此,如果您实际上对整数值01感兴趣,则使用2作为上限:

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

If instead you want to get a decimal between 0 and 1, try: 相反,如果您想获取0到1之间的小数,请尝试:

var n = random.NextDouble();

Hope this helps :-) 希望这可以帮助 :-)

You could, but you should do it this way: 您可以,但是您应该这样做:

double test = random.NextDouble();

If you wanted to get random integer ( 0 or 1), you should set upper bound to 2, because it is exclusive 如果要获取随机整数(0或1),则应将上限设置为2,因为它是互斥的

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

Every single answer on this page regarding doubles is wrong, which is sort of hilarious because everyone is quoting the documentation. 此页面上有关双打的每个答案都是错误的,这很有趣,因为每个人都在引用文档。 If you generate a double using NextDouble(), you will not get a number between 0 and 1 inclusive of 1, you will get a number from 0 to 1 exclusive of 1. 如果使用NextDouble()生成双精度数,则不会得到0到1之间(包括1)的数字,而不会得到0到1之间的数字(不包括1)。

To get a double, you would have to do some trickery like this: 要获得双倍奖励,您将需要执行以下操作:

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

and then call 然后打电话

NextRandomRange(0,1 + Double.Epsilon);

Seems like that would work, doesn't it? 似乎可行,不是吗? 1 + Double.Epsilon should be the next biggest number after 1 when working with doubles, right? 1 + Double.Epsilon在使用double时应该是1之后的第二大数字,对吗? This is how you would solve the problem with ints. 这是解决int问题的方法。

Wellllllllllllllll......... Wellllllllllllllll .........

I suspect that this will not work correctly, since the underlying code will be generating a few bytes of randomness, and then doing some math tricks to fit it in the expected range. 我怀疑这将无法正常工作,因为基础代码将生成一些字节的随机性,然后执行一些数学技巧以使其符合预期范围。 The short answer is that Logic that applies to ints doesn't quite work the same when working with floats. 简短的答案是,适用于int的逻辑在使用浮点数时效果并不完全相同。

Lets look, shall we? 让我们看看,好吗? ( https://referencesource.microsoft.com/#mscorlib/system/random.cs,e137873446fcef75 ) 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();
  }

What the hell is 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));
  }

Ok, starting to get somewhere. 好吧,开始到某个地方。 MBIG btw, is Int32.MaxValue(2147483647 or 2^31-1), making the division work out to: MBIG btw是Int32.MaxValue(2147483647或2 ^ 31-1),使除法运算为:

InternalSample()*0.0000000004656612873077392578125;

Ok, what the hell is InternalSample()? 好吧,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;
  }

Well...that is something. 好吧...那是什么。 But what is this SeedArray and inext crap all about? 但是,这个SeedArray和inext废话到底是什么?

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

So things start to fall together. 所以事情开始融为一体。 Seed array is an array of ints that is used for generating values from. 种子数组是一个整数数组,用于从中生成值。 If you look at the init function def, you see that there is a whole lot of bit addition and trickery being done to randomize an array of 55 values with initial quasi-random values. 如果您看一下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;
  }

Ok, going back to InternalSample(), we can now see that random doubles are generated by taking the difference of two scrambled up 32 bit ints, clamping the result into the range of 0 to 2147483647 - 1 and then multiplying the result by 1/2147483647. 好的,回到InternalSample(),我们现在可以看到,通过取两个加扰的32位整数的差,将结果限制在0到2147483647-1之间,然后将结果乘以1,可以生成随机双精度数。 2147483647。 More trickery is done to scramble up the list of seed values as it uses values, but that is essentially it. 在使用种子值时,要花更多的时间来加扰种子值列表,但实际上就是这样。

(It is interesting to note that the chance of getting any number in the range is roughly 1/r EXCEPT for 2^31-2, which is 2 * (1/r)! So if you think some dumbass coder is using RandNext() to generate numbers on a video poker machine, you should always bet on 2^32-2! This is one reason why we don't use Random for anything important...) (有趣的是,获得2到31-2范围内任何数字的机会大约为1 / r,即2 *(1 / r)!因此,如果您认为某些dumbass编码器正在使用RandNext( )在视频扑克机上生成数字,您应该始终下注2 ^ 32-2!这就是为什么我们不将Random用作重要内容的原因之一...)

so, if the output of InternalSample() is 0 we multiply that by 0.0000000004656612873077392578125 and get 0, the bottom end of our range. 因此,如果InternalSample()的输出为0,则将其乘以0.0000000004656612873077392578125,得到0,即范围的底端。 if we get 2147483646, we end up with 0.9999999995343387126922607421875, so the claim that NextDouble produces a result of [0,1) is...sort of right? 如果我们得到2147483646,我们最终得到0.9999999995343387126922607421875,那么NextDouble产生[0,1)结果的说法是...对吗? It would be more accurate to say it is int he range of [0,0.9999999995343387126922607421875]. 可以更准确地说是[0,0.9999999995343387126922607421875]的范围。

My suggested above solution would fall on its face, since double.Epsilon = 4.94065645841247E-324, which is WAY smaller than 0.0000000004656612873077392578125 (the amount you would add to our above result to get 1). 我建议的上述解决方案将面面俱到,因为double.Epsilon = 4.94065645841247E-324,该方式小于0.0000000004656612873077392578125(您将添加到上述结果中得到的金额为1)。

Ironically, if it were not for the subtraction of one in the InternalSample() method: 具有讽刺意味的是,如果不是要在InternalSample()方法中减去一个:

if (retVal == MBIG) retVal--;

we could get to 1 in the return values that come back. 我们可以将返回的返回值设为1。 So either you copy all the code in the Random class and omit the retVal-- line, or multiply the NextDouble() output by something like 1.0000000004656612875245796924106 to slightly stretch the output to include 1 in the range. 因此,要么复制Random类中的所有代码,然后省略retVal--行,要么将NextDouble()输出乘以1.0000000004656612612875245796924106之类的值,以稍微拉伸输出范围以使其包含1。 Actually testing that value gets us really close, but I don't know if the few hundred million tests I ran just didn't produce 2147483646 (quite likely) or there is a floating point error creeping into the equation. 实际测试该值可以使我们真正接近,但我不知道我进行的几亿次测试是否未产生2147483646(很有可能)或方程中是否存在浮点误差。 I suspect the former. 我怀疑前者。 Millions of test are unlikely to yield a result that has 1 in 2 billion odds. 数百万次测试不太可能产生20亿分之一的赔率。

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

TLDR? TLDR? Inclusive ranges with random doubles is tricky... 随机双打的包容范围非常棘手...

You are getting zero because Random.Next(a,b) returns number in range [a, b), which is greater than or equal to a, and less than b. 您将得到零,因为Random.Next(a,b)返回范围[a,b)中的数字,该数字大于或等于a且小于b。

If you want to get one of the {0, 1}, you should use: 如果要获取{0,1}之一,则应使用:

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

Because you asked for a number less than 1 . 因为您要求的数字小于1

The documentation says: 文件说:

Return Value 返回值
A 32-bit signed integer greater than or equal to minValue and less than maxValue; 一个大于或等于minValue且小于maxValue的32位有符号整数; that is, the range of return values includes minValue but not maxValue. 也就是说,返回值的范围包括minValue但不包括maxValue。 If minValue equals maxValue, minValue is returned. 如果minValue等于maxValue,则返回minValue。

Rewrite the code like this if you are targeting 0.0 to 1.0 如果目标是0.0到1.0,请像这样重写代码

Random random = new Random();

double test = random.NextDouble();

Console.WriteLine(test);

Console.ReadKey();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM