Quelle est la meilleure façon de générer un flottant aléatoire en C#? Mise à jour: Je veux des nombres à virgule flottante de float.Minvalue à float.Maxvalue. J'utilise ces nombres dans les tests unitaires de certaines méthodes mathématiques.Meilleure façon de générer un flottant aléatoire en C#
Répondre
Meilleure approche, aucune valeur folle, distributed with respect to the representable intervals on the floating-point number line (enlevé « uniforme » que par rapport à une ligne numérique en continu, il est décidément non uniforme):
static float NextFloat(Random random)
{
double mantissa = (random.NextDouble() * 2.0) - 1.0;
double exponent = Math.Pow(2.0, random.Next(-126, 128));
return (float)(mantissa * exponent);
}
une autre approche qui vous donnera des valeurs déments (répartition uniforme des motifs de bits), potentiellement utile pour fuzzing:
static float NextFloat(Random random)
{
var buffer = new byte[4];
random.NextBytes(buffer);
return BitConverter.ToSingle(buffer,0);
}
approche moins utile:
static float NextFloat(Random random)
{
// Not a uniform distribution w.r.t. the binary floating-point number line
// which makes sense given that NextDouble is uniform from 0.0 to 1.0.
// Uniform w.r.t. a continuous number line.
//
// The range produced by this method is 6.8e38.
//
// Therefore if NextDouble produces values in the range of 0.0 to 0.1
// 10% of the time, we will only produce numbers less than 1e38 about
// 10% of the time, which does not make sense.
var result = (random.NextDouble()
* (Single.MaxValue - (double)Single.MinValue))
+ Single.MinValue;
return (float)result;
}
ligne de nombre à virgule flottante à partir de: Intel Architecture Software Developer's Manual Volume 1: Basic Architecture. L'axe des Y est logarithmique (base 2) en raison des nombres à virgule flottante binaires consécutives ne diffèrent pas de façon linéaire.
Il ne semble pas y avoir de méthode BitConverter.GetSingle. Voulez-vous dire ToSingle? – KrisTrip
Ce serait ce que je veux dire ... – user7116
L'utilisation d'octets aléatoires peut facilement aboutir à une valeur NaN, et la distribution pourrait bien ne pas être uniforme. (Je ne voudrais pas prédire la distribution.) –
N'importe quelle raison pour ne pas utiliser Random.NextDouble
, puis passer à float
? Cela vous donnera un flottant entre 0 et 1.
Si vous voulez une forme différente de «meilleur», vous devrez spécifier vos besoins. Notez que Random
ne devrait pas être utilisé pour des sujets sensibles tels que la finance ou la sécurité - et vous devriez généralement réutiliser une instance existante dans votre application, ou une par thread (car Random
n'est pas thread-safe).
EDIT: Comme suggéré dans les commentaires, convertir à un éventail de float.MinValue
, float.MaxValue
:
// Perform arithmetic in double type to avoid overflowing
double range = (double) float.MaxValue - (double) float.MinValue;
double sample = rng.NextDouble();
double scaled = (sample * range) + float.MinValue;
float f = (float) scaled;
EDIT: Vous avez mentionné que cela est pour les tests unitaires, je ne suis pas sûr que c'est un approche idéale. Vous devriez probablement tester avec des valeurs concrètes - en vous assurant de tester avec des échantillons dans chacune des catégories pertinentes - infinis, NaNs, nombres dénormaux, très grands nombres, zéro, etc.
Je pense que NextDouble fournit juste des valeurs de 0.0 à 1.0 et je veux plus de portée que cela (comme de float.MinValue à float.MaxValue). Je suppose que j'aurais dû spécifier :) – KrisTrip
Il suffit de le multiplier par (MaxValue-MinValue) et lui ajouter MinValue? Donc, quelque chose comme Random.NextDouble * (float.MaxValue-float.MinValue) + float.MinValue – Xzhsh
La distribution des valeurs qui produit est bimodale, je crois que cela a à voir avec la taille des valeurs dans la gamme. – user7116
Je pris une approche légèrement différente que d'autres
static float NextFloat(Random random)
{
double val = random.NextDouble(); // range 0.0 to 1.0
val -= 0.5; // expected range now -0.5 to +0.5
val *= 2; // expected range now -1.0 to +1.0
return float.MaxValue * (float)val;
}
Les commentaires expliquent ce que je fais. Obtenez le double suivant, convertissez ce nombre à une valeur comprise entre -1 et 1, puis multipliez cela par float.MaxValue
.
Une autre solution consiste à faire:
static float NextFloat(Random random)
{
float f;
do
{
byte[] bytes = new byte[4];
random.NextBytes(bytes);
f = BitConverter.ToSingle(bytes, 0);
}
while (float.IsInfinity(f) || float.IsNaN(f));
return f;
}
Une version plus ... (je pense que celui-ci est assez bon)
static float NextFloat(Random random)
{
(float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5));
}
//inline version
float myVal = (float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5));
Je pense que ce ...
- est le 2ème plus rapide (voir repères)
- est réparti uniformément
Et une version plus ... (pas aussi bon, mais l'affichage de toute façon)
static float NextFloat(Random random)
{
return float.MaxValue * ((rand.Next()/1073741824.0f) - 1.0f);
}
//inline version
float myVal = (float.MaxValue * ((rand.Next()/1073741824.0f) - 1.0f));
Je pense que cela ...
- est le plus rapide (voir les tests de performance)
- est distribué uniformément mais parce que Next() est une valeur aléatoire de 31 bits, il ne retournera que 2^31 valeurs. (50% des valeurs voisines aura la même valeur)
Test de la plupart des fonctions de cette page: (I7 libération, sans mise au point, 2^28 boucles)
Sunsetquest1: min: 3.402823E+38 max: -3.402823E+38 time: 3096ms
SimonMourier: min: 3.402823E+38 max: -3.402819E+38 time: 14473ms
AnthonyPegram:min: 3.402823E+38 max: -3.402823E+38 time: 3191ms
JonSkeet: min: 3.402823E+38 max: -3.402823E+38 time: 3186ms
Sixlettervar: min: 1.701405E+38 max: -1.701410E+38 time: 19653ms
Sunsetquest2: min: 3.402823E+38 max: -3.402823E+38 time: 2930ms
Etes-vous sûr que ce sera plus rapide parce que c'est une puissance de deux? Je suppose qu'il serait implicitement moulé à un flotteur * (qui ne représenterait pas exactement la valeur, puis utiliser la division flottante régulière). * – ideasman42
Merci de remarquer que c'était une bonne prise! Vous avez raison de dire qu'il a été converti en un flottant en premier afin que le compilateur ne puisse pas utiliser une instruction shift. J'ai enlevé le "est plus rapide parce que c'est une puissance de deux". Comme vous pouvez le voir, j'ai fait plusieurs autres changements, y compris l'ajout d'une nouvelle fonction et aussi faire des repères. – Sunsetquest
Voici une autre méthode que j'ai trouvée: Disons que vous voulez obtenir un flottant entre 5,5 et 7, avec 3 décimales.
float myFloat;
int myInt;
System.Random rnd = new System.Random();
void GenerateFloat()
{
myInt = rnd.Next(1, 2000);
myFloat = (myInt/1000) + 5.5f;
}
De cette façon, vous obtiendrez toujours un plus grand nombre de 5,5 et un nombre inférieur à 7.
Je préfère utiliser le code suivant pour générer un nombre décimal à virgule décimale poing. vous pouvez copier coller la 3ème ligne pour ajouter plus de nombres après le point décimal en ajoutant ce nombre dans la chaîne "combinée". Vous pouvez définir la valeur minimum et maximum en changeant le 0 et le 9 à votre valeur préférée.
Random r = new Random();
string beforePoint = r.Next(0, 9).ToString();//number before decimal point
string afterPoint = r.Next(0,9).ToString();//1st decimal point
//string secondDP = r.Next(0, 9).ToString();//2nd decimal point
string combined = beforePoint+"."+afterPoint;
decimalNumber= float.Parse(combined);
Console.WriteLine(decimalNumber);
J'espère que cela vous a aidé.
- 1. Comment générer un nombre aléatoire en C#?
- 2. Comment créer un flottant aléatoire en Objective-C?
- 3. C# façon de définir un tampon flottant en mémoire
- 4. Générer une énumération aléatoire en C# 2.0
- 5. CSS: Meilleure façon d'aligner un flottant à gauche: section droite
- 6. Meilleure façon de générer une sortie de rapport C#
- 7. Comment générer un numéro pseudo-aléatoire cryptographiquement sécurisé en C#?
- 8. Meilleure façon de générer des tuiles
- 9. Meilleure façon de générer une liste d'images
- 10. La meilleure façon de lancer un flottant dans un int pour l'arithmétique?
- 11. La meilleure façon de générer un document personnalisé?
- 12. Quelle est la meilleure façon de choisir un pinceau aléatoire de la collection de pinceaux en C#?
- 13. meilleure façon de générer une instruction d'insertion en masse dans C#?
- 14. Générer un nombre aléatoire avec une longueur de nombre aléatoire dans Objective-C
- 15. Générer un index aléatoire pour un tableau
- 16. Quelle est la meilleure façon de générer des fichiers KML en C#?
- 17. Meilleure façon de générer du HTML à partir de json
- 18. Setprecision() pour un nombre flottant en C++?
- 19. La meilleure façon d'analyser un fichier journal en C#
- 20. Quelle est la meilleure façon d'enregistrer un RichTextFile en C#?
- 21. Générer un terrain aléatoire dans Blender3D
- 22. Comment générer un produit flottant de multiplicateurs int?
- 23. Comment créer au mieux un flottant aléatoire dans une plage entre deux flotteurs
- 24. générer un seul nombre aléatoire dans une vue en xcode
- 25. générer un fichier aléatoire en utilisant le script shell
- 26. Générer une branche d'arbre aléatoire
- 27. Générer chaîne aléatoire, sans SecureRandom
- 28. La meilleure façon de transformer un entier en un nom de mois en C#?
- 29. Quelle est la meilleure façon d'accéder à un nombre aléatoire de contrôles dans WPF DataTemplate
- 30. quelle est la meilleure façon de créer des ID mysql aléatoire en utilisant PHP
4.0 - aléatoire choisi par un jet de dés à virgule flottante. –
@ JesseC.Slicer Vous avez oublié de fournir le lien: http://xkcd.com/221/ – jpmc26