Nombre aléatoire entre 2 numéros doubles

Est-il possible de générer un nombre aléatoire entre 2 doubles?

Exemple:

public double GetRandomeNumber(double minimum, double maximum) { return Random.NextDouble(minimum, maximum) } 

Alors je l’appelle avec ce qui suit:

 double result = GetRandomNumber(1.23, 5.34); 

Toute reflection sera apprécié.

Oui.

Random.NextDouble renvoie un double entre 0 et 1. Vous multipliez ensuite cela par la plage que vous devez entrer (différence entre maximum et minimum), puis ajoutez-la à la base (minimum).

 public double GetRandomNumber(double minimum, double maximum) { Random random = new Random(); return random.NextDouble() * (maximum - minimum) + minimum; } 

Le code réel devrait avoir un membre statique aléatoire. Cela permettra d’économiser le coût de création du générateur de nombres aléatoires et vous permettra d’appeler très fréquemment GetRandomNumber. Comme nous initialisons un nouveau RNG à chaque appel, si vous appelez assez rapidement pour que l’heure système ne change pas entre les appels, le RNG sera doté du même horodatage et générera le même stream de nombres aléatoires.

Johnny5 a suggéré de créer une méthode d’extension. Voici un exemple de code plus complet montrant comment procéder:

 public static class RandomExtensions { public static double NextDouble( this Random random, double minValue, double maxValue) { return random.NextDouble() * (maxValue - minValue) + minValue; } } 

Maintenant, vous pouvez l’appeler comme s’il s’agissait d’une méthode de la classe Random :

 Random random = new Random(); double value = random.NextDouble(1.23, 5.34); 

Notez que vous ne devez pas créer beaucoup de nouveaux objects Random dans une boucle, car cela rendra probablement la même valeur plusieurs fois de suite. Si vous avez besoin de beaucoup de nombres aléatoires, créez une instance de Random et réutilisez-la.

L’approche la plus simple générerait simplement un nombre aléatoire compris entre 0 et la différence des deux nombres. Ajoutez ensuite le plus petit des deux nombres au résultat.

Attention: si vous générez le random dans une boucle comme par exemple for(int i = 0; i < 10; i++) , ne placez pas la new Random() déclaration new Random() dans la boucle.

De MSDN :

La génération de nombres aléatoires commence à partir d'une valeur de départ. Si la même graine est utilisée à plusieurs resockets, la même série de nombres est générée. Une façon de produire des séquences différentes consiste à rendre la valeur de départ dépendant du temps, produisant ainsi une série différente avec chaque nouvelle instance de Random. Par défaut, le constructeur sans paramètre de la classe Random utilise l'horloge système pour générer sa valeur de départ ...

Donc, sur cette base, faites quelque chose comme:

 var random = new Random(); for(int d = 0; d < 7; d++) { // Actual BOE boes.Add(new LogBOEViewModel() { LogDate = criteriaDate, BOEActual = GetRandomDouble(random, 100, 1000), BOEForecast = GetRandomDouble(random, 100, 1000) }); } double GetRandomDouble(Random random, double min, double max) { return min + (random.NextDouble() * (max - min)); } 

De cette façon, vous avez la garantie d'obtenir des valeurs doubles différentes.

Vous pouvez utiliser un code comme celui-ci:

 public double getRandomNumber(double minimum, double maximum) { return minimum + randomizer.nextDouble() * (maximum - minimum); } 

Vous pourriez faire ceci:

 public class RandomNumbers : Random { public RandomNumbers(int seed) : base(seed) { } public double NextDouble(double minimum, double maximum) { return base.NextDouble() * (maximum - minimum) + minimum; } } 

Et si l’une des valeurs est négative? Ne serait pas une meilleure idée d’être:

 double NextDouble(double min, double max) { if (min >= max) throw new ArgumentOutOfRangeException(); return random.NextDouble() * (Math.Abs(max-min)) + min; } 

A propos de la génération du même nombre aléatoire si vous l’appelez en boucle, une solution astucieuse consiste à déclarer le nouvel object Random () en dehors de la boucle en tant que variable globale.

Notez que vous devez déclarer votre instance de la classe aléatoire en dehors de la fonction GetRandomInt si vous souhaitez l’exécuter en boucle.

“Pourquoi est-ce?” Vous demandez.

Eh bien, la classe aléatoire génère en fait des nombres pseudo-aléatoires, la «graine» pour le randomiseur étant l’heure système. Si votre boucle est suffisamment rapide, l’heure de l’horloge du système ne sera pas différente de celle du randomiseur et chaque nouvelle instance de la classe aléatoire commencera avec la même graine et vous donnera le même numéro pseudo-aléatoire.

La source est ici: http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/

Si vous avez besoin d’un nombre aléatoire dans la plage [ double.MinValue ; double.MaxValue ]

 // Because of: double.MaxValue - double.MinValue == double.PositiveInfinity // This will be equals to NaN or PositiveInfinity random.NextDouble() * (double.MaxValue - double.MinValue) 

Utilisez plutôt:

 public static class RandomExtensions { public static double NextDoubleInMinMaxRange(this Random random) { var bytes = new byte[sizeof(double)]; var value = default(double); while (true) { random.NextBytes(bytes); value = BitConverter.ToDouble(bytes, 0); if (!double.IsNaN(value) && !double.IsInfinity(value)) return value; } } } 

Je suis un peu en retard pour la fête mais je devais mettre en place une solution générale et il s’est avéré qu’aucune des solutions ne pouvait satisfaire mes besoins.

La solution acceptée est bonne pour les petites gammes; Cependant, le maximum - minimum peut être infini pour les grandes plages. Donc, une version corrigée peut être cette version:

 public static double NextDoubleLinear(this Random random, double minValue, double maxValue) { // TODO: some validation here... double sample = random.NextDouble(); return (maxValue * sample) + (minValue * (1d - sample)); } 

Cela génère bien des nombres aléatoires même entre double.MinValue et double.MaxValue . Mais cela introduit un autre “problème”, qui est bien présenté dans cet article : si nous utilisons des plages aussi grandes, les valeurs peuvent sembler trop “non naturelles”. Par exemple, après avoir généré 10 000 doubles aléatoires entre 0 et double.MaxValue toutes les valeurs étaient comsockets entre 2,9579E + 304 et 1,7976E + 308.

J’ai donc créé une autre version, qui génère des nombres sur une échelle logarithmique:

 public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue) { // TODO: some validation here... bool posAndNeg = minValue < 0d && maxValue > 0d; double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue)); double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue)); int sign; if (!posAndNeg) sign = minValue < 0d ? -1 : 1; else { // if both negative and positive results are expected we select the sign based on the size of the ranges double sample = random.NextDouble(); var rate = minAbs / maxAbs; var absMinValue = Math.Abs(minValue); bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample; sign = isNeg ? -1 : 1; // now adjusting the limits for 0..[selected range] minAbs = 0d; maxAbs = isNeg ? absMinValue : Math.Abs(maxValue); } // Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because // that would cause too many almost zero results, which are much smaller than the original NextDouble values. double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d); double maxExponent = Math.Log(maxAbs, 2d); if (minExponent == maxExponent) return minValue; // We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0 if (maxExponent < minExponent) minExponent = maxExponent - 4; double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent)); // protecting ourselves against inaccurate calculations; however, in practice result is always in range. return result < minValue ? minValue : (result > maxValue ? maxValue : result); } 

Quelques tests:

Voici les résultats sortingés de la génération de 10 000 nombres doubles aléatoires entre 0 et Double.MaxValue avec les deux stratégies. Les résultats sont affichés avec une échelle logarithmique:

0..Double.MaxValue

Bien que les valeurs aléatoires linéaires semblent fausses à première vue, les statistiques montrent qu’aucune d’entre elles n’est “meilleure” que l’autre: même la stratégie linéaire a une dissortingbution uniforme et la différence moyenne entre les valeurs est sensiblement la même avec les deux stratégies .

Jouer avec différentes gammes m’a montré que la stratégie linéaire peut être “saine” avec une plage comprise entre 0 et ushort.MaxValue avec une valeur minimale “raisonnable” de 10.78294704 (pour la plage ulong , la valeur minimale était 3.03518E + 15; int : 353341) . Ce sont les mêmes résultats des deux stratégies affichées avec des échelles différentes:

0..UInt16.MaxValue

Et le résumé de mes tests:

 0..Double.MaxValue | Linear | Log -------------------+-------------+------------ Min | 2.9579E+304 | 1.71803E-05 Max | 1.7976E+308 | 1.7627E+308 Min Diff | 1.0045E+300 | 9.48956E-09 Max Diff | 1.9674E+305 | 5.0426E+307 Average Diff | 1.7977E+304 | 1.7632E+304 0..UInt64.MaxValue | Linear | Log -------------------+-------------+------------ Min | 3.03518E+15 | 1.53986E-05 Max | 1.84462E+19 | 1.84188E+19 Min Diff | 1.03079E+11 | 1.43294E-10 Max Diff | 2.01884E+16 | 4.71314E+17 Average Diff | 1.84467E+15 | 1.84244E+15 0..Int32.MaxValue | Linear | Log -------------------+-------------+------------ Min | 353341 | 1.53408E-05 Max | 2147425016 | 2145574420 Min Diff | 12 | 5.96876E-11 Max Diff | 2350242 | 32744094.27 Average Diff | 214747.6949 | 214621.8286 0..UInt16.MaxValue | Linear | Log -------------------+-------------+------------ Min | 10.78294704 | 1.53146E-05 Max | 65533.21075 | 65495.32523 Min Diff | 0.000366205 | 2.11068E-11 Max Diff | 71.72259946 | 690.9718768 Average Diff | 6.55347956 | 6.551497971 0..Byte.MaxValue | Linear | Log -------------------+-------------+------------ Min | 0.041956992 | 1.53006E-05 Max | 254.9930379 | 254.884236 Min Diff | 1.42492E-06 | 1.05023E-11 Max Diff | 0.279076263 | 2.032731396 Average Diff | 0.02549992 | 0.025496071 
 Random random = new Random(); double NextDouble(double minimum, double maximum) { return random.NextDouble()*random.Next(minimum,maximum); }