Il modo più veloce per generare un booleano casuale


87

Quindi ci sono diversi modi per creare un bool casuale in C #:

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

C'è davvero una differenza? In tal caso, quale ha effettivamente le prestazioni migliori? O c'è un altro modo in cui non ho visto, che potrebbe essere ancora più veloce?



7
È davvero questo il collo di bottiglia?
Brian Rasmussen

2
Senza effettivamente eseguirlo (perché qualsiasi metodo sarà ridicolmente veloce), la mia ipotesi sarebbe quella di utilizzare NextBytesper pre-popolare un array di byte, usarlo BitArrayper trasformarlo in una raccolta di booleani e recuperare quei booleani da a Queuefinché non viene svuotato, quindi ripetere il processo. Con questo metodo, stai usando il randomizer solo una volta, quindi qualsiasi overhead che crea si verifica solo quando riempi la coda. Questo potrebbe essere utile quando si ha a che fare con un generatore di numeri casuali sicuro piuttosto che con la Randomclasse normale .
Joe Enos

2
@JoeEnos MS ha incasinato l'implementazione di NextBytes, quindi è sorprendentemente lento
CodesInChaos

1
@CodesInChaos Wow, è interessante - Ho appena cercato in un disassemblatore per vedere a cosa ti riferivi: - Suppongo buffer[i] = (byte)(this.InternalSample() % 256);che sia quello di cui stai parlando, che avrebbero potuto prendere quel numero intero casuale e dividerlo in 3 byte , popolando l'array di byte con circa 1/3 del lavoro. Mi chiedo se ci fosse una ragione o se fosse solo una svista da parte degli sviluppatori.
Joe Enos

Risposte:


72

La prima opzione : rand.Next(2)esegue dietro le quinte il codice seguente:

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

e per la seconda opzione - rand.NextDouble():

return this.Sample();

Poiché la prima opzione contiene maxValueconvalida, moltiplicazione e casting, la seconda opzione è probabilmente più veloce .


Grazie, è tutto quello che volevo sapere.
orario

5
I miei tempi dicono che la seconda opzione è circa il 5% più veloce della prima.
ClickRick

61

Piccolo miglioramento per la seconda opzione :

Secondo MSDN

public virtual double NextDouble()

ritorna

Un numero in virgola mobile a precisione doppia maggiore o uguale a 0,0 e minore di 1,0.

Quindi, se vuoi un bool casuale distribuito in modo uniforme, dovresti usare >= 0.5

rand.NextDouble() >= 0.5

Intervallo 1: [0,0 ... 0,5 [
Intervallo 2: [0,5 ... 1,0 [
| Intervallo 1 | = | Intervallo 2 |


10

Il più veloce. Chiamare il metodo Random.Nextha il minore overhead. Il metodo di estensione di seguito è più veloce del 20% Random.NextDouble() > 0.5e del 35% più veloce di 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]
}

Più veloce del più veloce. È possibile generare booleani casuali con la Randomclasse ancora più velocemente, utilizzando trucchi. I 31 bit significativi di un generato intpossono essere utilizzati per 31 produzioni booleane successive. L'implementazione di seguito è del 40% più veloce di quella precedentemente dichiarata come la più veloce.

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;
    }
}

Grazie! Per coloro che utilizzano UnityEngine per scrivere script, assicurati di utilizzare System.Random e non UnityEngine.Random, poiché non sono la stessa cosa!
DonCarleone

6

Ho eseguito i test con il cronometro. 100.000 iterazioni:

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

Le CPU amano gli interi, quindi il metodo Next (2) era più veloce. 3.700 contro 7.500 ms, che è abbastanza consistente. Inoltre: penso che i numeri casuali possano essere un collo di bottiglia, ho creato circa 50 ogni fotogramma in Unity, anche con una piccola scena che ha notevolmente rallentato il mio sistema, quindi speravo anche di trovare un metodo per creare un bool casuale. Quindi ho anche provato

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

ma la chiamata a una funzione statica era ancora più lenta con 9.600 ms. Vale un tentativo. Alla fine ho saltato il confronto e ho creato solo 100.000 valori casuali, per assicurarmi che il confronto tra int e doppio non influenzasse il tempo trascorso, ma il risultato era praticamente lo stesso.


1
DateTime.Now è notoriamente lento. Idealmente dovrebbero essere utilizzate soluzioni dipendenti dall'hardware o almeno dal sistema operativo per renderlo veloce.
Do-do-new

Usa DateTime.UtcNow, è molto più veloce di DateTime.Now.
Theodor Zoulias
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.