簡體   English   中英

如何在C#中生成0到1之間的隨機數?

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

我想獲得1到0之間的隨機數。但是,我每次都得到0。 有人可以向我解釋為什么我總是得到0的原因嗎? 這是我嘗試過的代碼。

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

根據文檔Next返回(最小)(最大值)(最大)之間的整數隨機數:

返回值

一個大於或等於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();

希望這可以幫助 :-)

您可以,但是您應該這樣做:

double test = random.NextDouble();

如果要獲取隨機整數(0或1),則應將上限設置為2,因為它是互斥的

int test = random.Next(0, 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 btw是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()方法中減去一個:

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? 隨機雙打的包容范圍非常棘手...

您將得到零,因為Random.Next(a,b)返回范圍[a,b)中的數字,該數字大於或等於a且小於b。

如果要獲取{0,1}之一,則應使用:

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

因為您要求的數字小於1

文件說:

返回值
一個大於或等於minValue且小於maxValue的32位有符號整數; 也就是說,返回值的范圍包括minValue但不包括maxValue。 如果minValue等於maxValue,則返回minValue。

如果目標是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