Der schnellste Weg, um einen zufälligen Booleschen Wert zu generieren

85

Es gibt also verschiedene Möglichkeiten, einen zufälligen Bool in C # zu erstellen:

  • Verwenden von Random.Next (): rand.Next(2) == 0
  • Verwenden von Random.NextDouble (): rand.NextDouble() > 0.5

Gibt es wirklich einen Unterschied? Wenn ja, welches hat tatsächlich die bessere Leistung? Oder gibt es einen anderen Weg, den ich nicht gesehen habe, der vielleicht noch schneller ist?

timedt
quelle
7
Ist das wirklich der Engpass?
Brian Rasmussen
2
Ohne es tatsächlich auszuführen (weil jede Methode lächerlich schnell sein wird), würde ich davon ausgehen, NextBytesein Byte-Array vorab zu BitArrayfüllen, es in eine Sammlung von Booleschen Werten umzuwandeln und diese Booleschen Werte von a abzurufen, Queuebis es geleert ist, und dann zu wiederholen der Prozess. Bei dieser Methode verwenden Sie den Randomizer nur einmal, sodass der dadurch entstehende Overhead nur auftritt, wenn Sie die Warteschlange wieder auffüllen. Dies kann nützlich sein, wenn es sich um einen sicheren Zufallszahlengenerator handelt und nicht um die reguläre RandomKlasse.
Joe Enos
2
@ JoeEnos MS hat die Implementierung von durcheinander gebracht NextBytes, so dass es überraschend langsam ist
CodesInChaos
1
@CodesInChaos Wow, das ist interessant - ich habe es gerade in einem Disassembler nachgeschlagen, um zu sehen, worauf Sie sich bezogen haben: buffer[i] = (byte)(this.InternalSample() % 256);- Ich gehe davon aus, dass Sie darüber sprechen, dass sie diese zufällige Ganzzahl hätten nehmen und in 3 Bytes aufteilen können , das Byte-Array mit etwa 1/3 der Arbeit zu füllen. Ich frage mich, ob es einen Grund dafür gab oder ob es nur ein Versehen der Entwickler war.
Joe Enos

Antworten:

69

Die erste Option - rand.Next(2)führt hinter den Kulissen den folgenden Code aus:

if (maxValue < 0)
{
    throw new ArgumentOutOfRangeException("maxValue",
        Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", new object[] { "maxValue" }));
}
return (int) (this.Sample() * maxValue);

und für die zweite Option - rand.NextDouble():

return this.Sample();

Da die erste Option maxValueValidierung, Multiplikation und Casting enthält, ist die zweite Option wahrscheinlich schneller .

Aviran Cohen
quelle
Danke, das ist alles was ich wissen wollte.
Timedt
4
Mein eigenes Timing besagt, dass die zweite Option etwa 5% schneller ist als die erste.
ClickRick
56

Kleine Verbesserung für die zweite Option :

Laut MSDN

public virtual double NextDouble()

kehrt zurück

Eine Gleitkommazahl mit doppelter Genauigkeit größer oder gleich 0,0 und kleiner als 1,0.

Wenn Sie also einen gleichmäßig verteilten zufälligen Bool möchten, sollten Sie ihn verwenden >= 0.5

rand.NextDouble() >= 0.5

Bereich 1: [0.0 ... 0.5 [
Bereich 2: [0.5 ... 1.0 [
| Bereich 1 | = | Bereich 2 |

DaRich
quelle
8

Die schnellste. Das Aufrufen der Methode Random.Nexthat den geringeren Aufwand. Die unten stehende Erweiterungsmethode läuft 20% schneller als Random.NextDouble() > 0.5und 35% schneller als Random.Next(2) == 0.

public static bool NextBoolean(this Random random)
{
    return random.Next() > (Int32.MaxValue / 2);
    // Next() returns an int in the range [0..Int32.MaxValue]
}

Schneller als der Schnellste. RandomMit Tricks ist es möglich, zufällige Boolesche Werte mit der Klasse noch schneller zu generieren . Die 31 signifikanten Bits eines generierten intkönnen für 31 nachfolgende boolesche Produktionen verwendet werden. Die unten stehende Implementierung ist 40% schneller als die zuvor als die schnellste deklarierte.

public class RandomEx : Random
{
    private uint _boolBits;

    public RandomEx() : base() { }
    public RandomEx(int seed) : base(seed) { }

    public bool NextBoolean()
    {
        _boolBits >>= 1;
        if (_boolBits <= 1) _boolBits = (uint)~this.Next();
        return (_boolBits & 1) == 0;
    }
}
Theodor Zoulias
quelle
6

Ich habe Tests mit Stoppuhr durchgeführt. 100.000 Iterationen:

System.Random rnd = new System.Random();
if (rnd.Next(2) == 0)
     trues++;

CPUs mögen Ganzzahlen, daher war die Next (2) -Methode schneller. 3.700 gegenüber 7.500 ms, was ziemlich beachtlich ist. Außerdem: Ich denke, Zufallszahlen können ein Engpass sein. Ich habe in Unity ungefähr 50 Frames pro Frame erstellt, selbst mit einer winzigen Szene, die mein System merklich verlangsamt hat. Daher hatte ich gehofft, eine Methode zum Erstellen eines zufälligen Bools zu finden. Also habe ich es auch versucht

if (System.DateTime.Now.Millisecond % 2 == 0)
       trues++;

Das Aufrufen einer statischen Funktion war mit 9.600 ms jedoch noch langsamer. Einen Versuch wert. Schließlich habe ich den Vergleich übersprungen und nur 100.000 Zufallswerte erstellt, um sicherzustellen, dass der Vergleich zwischen int und double keinen Einfluss auf die verstrichene Zeit hat, aber das Ergebnis war ziemlich gleich.

Frederik Steinmetz
quelle
1
DateTime.Now ist notorisch langsam. Idealerweise sollten hardwareabhängige Lösungen oder zumindest betriebssystemabhängige Lösungen verwendet werden, um dies zu beschleunigen.
Do-do-new
Verwenden Sie DateTime.UtcNowes ist viel schneller als DateTime.Now.
Theodor Zoulias