it-swarm.com.de

Wie generiere ich eine Zufallszahl zwischen und 1 in C #?

Ich möchte die Zufallszahl zwischen 1 und 0 erhalten. Ich bekomme jedoch jedes Mal 0. Kann mir jemand den Grund erklären, warum ich die ganze Zeit 0 bekomme? Dies ist der Code, den ich ausprobiert habe.

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

Gemäß der Dokumentation gibt Next eine ganzzahlige Zufallszahl zwischen dem (inklusive) Minimum und dem (exklusiven) Maximum zurück:

Rückgabewert

Eine 32-Bit-Ganzzahl mit Vorzeichen, die größer oder gleich minValue und kleiner als maxValue ist. Das heißt, der Bereich der Rückgabewerte umfasst minValue, nicht aber maxValue. Wenn minValue gleich maxValue ist, wird minValue zurückgegeben.

Die einzige ganze Zahl, die erfüllt

0 <= x < 1

ist 0, daher erhalten Sie immer den Wert 0. Mit anderen Worten, 0 ist die einzige Ganzzahl, die innerhalb des halb geschlossenen Intervalls [0, 1) liegt.

Wenn Sie also wirklich an den ganzzahligen Werten 0 oder 1 interessiert sind, verwenden Sie 2 als obere Grenze:

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

Wenn Sie stattdessen eine Dezimalzahl zwischen 0 und 1 erhalten möchten, versuchen Sie Folgendes:

var n = random.NextDouble();

Hoffe das hilft :-)

13
Golo Roden

Sie könnten, aber Sie sollten es so machen:

double test = random.NextDouble();

Wenn Sie eine zufällige ganze Zahl (0 oder 1) erhalten möchten, sollten Sie die Obergrenze auf 2 setzen, da es exklusiv ist.

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

Jede einzelne Antwort auf dieser Seite in Bezug auf Doppel ist falsch, was irgendwie komisch ist, weil jeder die Dokumentation zitiert. Wenn Sie mit NextDouble () ein Double generieren, erhalten Sie keine Zahl zwischen 0 und 1 einschließlich 1, sondern eine Zahl zwischen 0 und 1 ohne 1.

Um ein Double zu bekommen, müsst ihr einige Tricksereien machen:

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

und dann anrufen

NextRandomRange(0,1 + Double.Epsilon);

Anscheinend würde das funktionieren, nicht wahr? 1 + Double.Epsilon sollte bei der Arbeit mit Doubles die nächstgrößere Zahl nach 1 sein, oder? So würden Sie das Problem mit Ints lösen. 

Wellllllllllllllll .........

Ich vermute, dass dies nicht richtig funktionieren wird, da der zugrunde liegende Code einige Bytes Zufälligkeit generiert und dann einige mathematische Tricks ausführt, um ihn in den erwarteten Bereich zu bringen. Die kurze Antwort ist, dass die Logik, die für Ints gilt, nicht ganz gleich funktioniert, wenn Sie mit Floats arbeiten.

Schauen wir mal, sollen wir? ( 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();
  }

Was zur Hölle ist 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, irgendwohin zu kommen. MBIG ist übrigens Int32.MaxValue (2147483647 oder 2 ^ 31-1), so dass sich die Division wie folgt ausarbeitet:

InternalSample()*0.0000000004656612873077392578125;

Ok, was zum Teufel ist 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;
  }

Nun ... das ist etwas. Aber worum geht es in diesem SeedArray und Inext-Mist?

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

So fallen die Dinge zusammen. Das Array Seed ist ein Array von Ints, aus dem Werte generiert werden. Wenn Sie sich die init-Funktion def ansehen, sehen Sie, dass eine ganze Reihe von Bits hinzugefügt wird und ein Trick ausgeführt wird, um ein Array mit 55 Werten mit anfänglichen quasi-zufälligen Werten zu randomisieren.

  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 (Knuth) and so we're wasting the 0'th 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, zurück zu InternalSample (), wir können jetzt sehen, dass zufällige Doubles erzeugt werden, indem die Differenz zweier verschlüsselter 32-Bit-Ints genommen wird, das Ergebnis in den Bereich von 0 bis 2147483647 - 1 geklemmt wird und das Ergebnis dann mit 1 multipliziert wird. 2147483647. Die Liste der Startwerte wird durch die Verwendung von Werten mit noch mehr Tricksern durcheinander gebracht, aber das ist es im Wesentlichen. 

(Es ist interessant zu bemerken, dass die Chance, eine beliebige Zahl im Bereich zu erhalten, nur 1/r ist, AUSSER für 2 ^ 31-2, was 2 * (1/r) ist. Wenn Sie also der Meinung sind, dass ein dummer Codierer RandNext verwendet ( ) Um Zahlen auf einer Video-Poker-Maschine zu generieren, sollten Sie immer auf 2 ^ 32-2 setzen! Dies ist ein Grund, warum wir Random nicht für alles Wichtige verwenden ...) 

wenn also die Ausgabe von InternalSample () 0 ist, multiplizieren wir diese mit 0,0000000004656612873077392578125 und erhalten 0, das untere Ende unseres Bereichs. Wenn wir 2147483646 erhalten, landen wir am Ende bei 0,9999999995343387126922607421875, also ist die Behauptung, NextDouble sei [0,1], irgendwie ... richtig? Es wäre genauer zu sagen, dass es sich um einen Bereich von [0,0.9999999995343387126922607421875] handelt.

Meine vorgeschlagene Lösung würde auf ihr Gesicht fallen, da double.Epsilon = 4.94065645841247E-324, was WEG kleiner als 0,0000000004656612873077392578125 ist (die Menge, die Sie unserem obigen Ergebnis hinzufügen würden, um 1 zu erhalten). 

Ironischerweise, wenn nicht die Subtraktion von eins in der InternalSample () -Methode wäre:

if (retVal == MBIG) retVal--;

wir könnten bei den Rückgabewerten, die zurückkommen, 1 erreichen. Sie kopieren also entweder den gesamten Code in der Random-Klasse und lassen die retVal-- -Zeile weg oder multiplizieren die NextDouble () - Ausgabe mit etwas wie 1.0000000004656612875245796924106, um die Ausgabe etwas zu strecken, um 1 in den Bereich aufzunehmen. Ein genauer Test dieses Werts bringt uns sehr nahe, aber ich weiß nicht, ob die wenigen hundert Millionen Tests, die ich durchführte, nur 2147483646 (ziemlich wahrscheinlich) produziert haben oder dass es einen Gleitkommafehler gibt, der sich in die Gleichung einschleicht. Ich vermute das erstere.

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

TLDR? Inklusive Bereiche mit zufälligen Doppeln sind schwierig ...

1
Roger Hill

Sie erhalten Null, weil Random.Next(a,b) eine Zahl im Bereich [a, b) zurückgibt, die größer oder gleich a ist und kleiner als b ist.

Wenn Sie eines von {0, 1} erhalten möchten, sollten Sie Folgendes verwenden:

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

Weil Sie nach einer Nummer unter 1 gefragt haben.

Die Dokumentation sagt:

Rückgabewert
Eine 32-Bit-Ganzzahl mit Vorzeichen, die größer oder gleich minValue und kleiner als maxValue ist. das ist der Bereich der Rückgabewerte beinhaltet minValue, aber nicht maxValue. Wenn minValue gleich maxValue ist, minValue wird zurückgegeben.

0
SLaks

Schreiben Sie den Code wie folgt um, wenn Sie auf 0,0 bis 1,0 abzielen

Random random = new Random();

double test = random.NextDouble();

Console.WriteLine(test);

Console.ReadKey();
0
technoclem