Tout d'abord la présentation que vous avez lié ne parle que de nombres aléatoires pour des raisons de sécurité. Afin de ne pas réclamer Random
est mauvais pour la santé non à des fins de sécurité.
Mais je prétends qu'il est. L' .net 4 mise en œuvre de l' Random
est entachée de plusieurs façons. Je recommande que si vous n'avez pas de soins sur la qualité de vos nombres aléatoires. Je recommande d'utiliser mieux tiers des implémentations.
Défaut 1: Le semis
Le constructeur par défaut graines à l'heure actuelle. Ainsi, toutes les instances de l' Random
créé avec le constructeur par défaut à l'intérieur d'un court laps de temps de retour de la séquence. Ceci est documenté et "design". Ce qui est particulièrement gênant si vous voulez multi-thread de votre code, puisque vous ne pouvez pas il suffit de créer une instance de Random
au début de chaque threads d'exécution.
La solution de contournement est d'être très prudent lors de l'utilisation du constructeur par défaut et amorcer manuellement si nécessaire.
Un autre problème est que la semence de l'espace est plutôt restreint. Donc, si vous générez 50k cas d' Random
parfaitement aléatoire graines que vous obtiendrez probablement une séquence de nombres aléatoires à deux reprises(Voir le paradoxe d'anniversaire). Donc manuel de semis n'est pas facile d'obtenir de bon.
Défaut 2: La répartition des nombres aléatoires retourné par Next(int maxValue)
est biaisé
Il y a des paramètres pour qui Next(int maxValue)
est clairement pas uniforme. Par exemple, si vous calculez r.Next(1431655765)%2
, vous obtiendrez 0
chez environ 2/3 des échantillons (Échantillon de code à la fin de la réponse).
Faille 3: L' NextBytes()
méthode est inefficace.
La par octet coût de l' NextBytes()
qui est aussi gros que le coût pour générer un nombre entier de l'échantillon avec Next()
. À partir de ce que je soupçonne qu'ils créent en effet un échantillon par octet.
Une meilleure mise en œuvre à l'aide de 3 octets de chaque échantillon de vitesse, NextBytes()
par près d'un facteur 3.
Grâce à cette faille Random.NextBytes()
n'est que d'environ 25% plus rapide que l' System.Security.Cryptography.RNGCryptoServiceProvider.GetBytes
sur ma machine (Win7, Core i3 2600MHz)
Je suis sûr que si quelqu'un a inspecté la source/décompilé de byte code qu'il avait trouver encore plus de défauts que j'ai trouvé avec ma boîte noire de l'analyse.
Des exemples de Code:
r.Next(1431655765)%2
est fortement biaisé:
Random r=new Random();
const int mod=2;
int[] hist=new int[mod];
for(int i=0;i<10000000;i++)
{
int num=r.Next(1431655765);
int num2=num % 2;
hist[num2]++;
}
for(int i=0;i<mod;i++)
Console.WriteLine(hist[i]);
Performance:
byte[] bytes=new byte[8*1024];
var cr=new System.Security.Cryptography.RNGCryptoServiceProvider();
Random r=new Random();
// Random.NextBytes
for(int i=0;i<100000;i++)
{
r.NextBytes(bytes);
}
//One sample per byte
for(int i=0;i<100000;i++)
{
for(int j=0;j<bytes.Length;j++)
bytes[j]=(byte)r.Next();
}
//One sample per 3 bytes
for(int i=0;i<100000;i++)
{
for(int j=0;j+2<bytes.Length;j+=3)
{
int num=r.Next();
bytes[j+2]=(byte)(num>>16);
bytes[j+1]=(byte)(num>>8);
bytes[j]=(byte)num;
}
//Yes I know I'm not handling the last few bytes, but that won't have a noticeable impact on performance
}
//Crypto
for(int i=0;i<100000;i++)
{
cr.GetBytes(bytes);
}