Le moyen le plus rapide de générer un booléen aléatoire

87

Il existe donc plusieurs façons de créer un booléen aléatoire en C #:

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

Y a-t-il vraiment une différence? Si tel est le cas, lequel a réellement les meilleures performances? Ou y a-t-il une autre façon que je n'ai pas vue, qui pourrait être encore plus rapide?

timedt
la source
7
Est-ce vraiment le goulot d'étranglement?
Brian Rasmussen
2
Sans l'exécuter réellement (car toute méthode sera ridiculement rapide), je suppose que je devrais utiliser NextBytespour pré-remplir un tableau d'octets, l'utiliser BitArraypour le transformer en une collection de booléens et récupérer ces booléens de a Queuejusqu'à ce qu'il soit vidé, puis répétez le processus. Avec cette méthode, vous n'utilisez le randomiseur qu'une seule fois, donc toute surcharge qu'il crée ne se produit que lorsque vous remplissez la file d'attente. Cela peut être utile lorsqu'il s'agit d'un générateur de nombres aléatoires sécurisé plutôt que de la Randomclasse régulière .
Joe Enos
2
@JoeEnos MS a gâché la mise en œuvre de NextBytes, donc c'est étonnamment lent
CodesInChaos
1
@CodesInChaos Wow, c'est intéressant - je viens de le chercher dans un désassembleur pour voir à quoi vous faisiez référence: buffer[i] = (byte)(this.InternalSample() % 256);- Je suppose que c'est ce dont vous parlez, qu'ils auraient pu prendre cet entier aléatoire et le diviser en 3 octets , remplissant le tableau d'octets avec environ 1/3 du travail. Je me demande s'il y avait une raison à cela ou s'il s'agissait simplement d'un oubli des développeurs.
Joe Enos

Réponses:

72

La première option - rand.Next(2)exécute en coulisses le code suivant:

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

et pour la deuxième option - rand.NextDouble():

return this.Sample();

Étant donné que la première option contient la maxValuevalidation, la multiplication et la conversion, la deuxième option est probablement plus rapide .

Aviran Cohen
la source
Merci, c'est tout ce que je voulais savoir.
chronométré
5
Mon propre timing dit que la deuxième option est environ 5% plus rapide que la première.
ClickRick
60

Petite amélioration pour la deuxième option :

Selon MSDN

public virtual double NextDouble()

Retour

Un nombre à virgule flottante double précision supérieur ou égal à 0,0 et inférieur à 1,0.

Donc, si vous voulez une booléenne aléatoire uniformément répartie, vous devez utiliser >= 0.5

rand.NextDouble() >= 0.5

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

DaRich
la source
9

Le plus rapide. L'appel de la méthode Random.Nexta le moins de frais généraux. La méthode d'extension ci-dessous fonctionne 20% plus vite que Random.NextDouble() > 0.5et 35% plus vite que 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]
}

Plus rapide que le plus rapide. Il est possible de générer des booléens aléatoires avec la Randomclasse encore plus rapidement, en utilisant des astuces. Les 31 bits significatifs d'un généré intpeuvent être utilisés pour 31 productions booléennes ultérieures. La mise en œuvre ci-dessous est 40% plus rapide que celle précédemment déclarée comme la plus rapide.

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
la source
Merci! Pour ceux qui utilisent UnityEngine pour écrire des scripts, assurez-vous d'utiliser System.Random et non UnityEngine.Random, car ce n'est pas la même chose!
DonCarleone
6

J'ai fait des tests avec un chronomètre. 100 000 itérations:

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

Les processeurs aiment les entiers, donc la méthode Next (2) était plus rapide. 3700 contre 7500 ms, ce qui est assez substantiel. Aussi: je pense que les nombres aléatoires peuvent être un goulot d'étranglement, j'ai créé environ 50 images dans Unity, même avec une petite scène qui ralentissait sensiblement mon système, donc j'espérais aussi trouver une méthode pour créer un booléen aléatoire. Alors j'ai aussi essayé

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

mais l'appel d'une fonction statique était encore plus lent avec 9 600 ms. Ça vaut le coup. Enfin, j'ai sauté la comparaison et créé seulement 100000 valeurs aléatoires, pour m'assurer que la comparaison int vs double n'influençait pas le temps écoulé, mais le résultat était à peu près le même.

Frederik Steinmetz
la source
1
DateTime.Now est notoirement lent. Idéalement, des solutions dépendantes du matériel ou au moins dépendant du système d'exploitation devraient être utilisées pour le rendre rapide.
À faire
Utilisation DateTime.UtcNow, c'est beaucoup plus rapide que DateTime.Now.
Theodor Zoulias