Numero casuale tra 2 numeri doppi

È ansible generare un numero casuale tra 2 doppi?

Esempio:

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

Allora lo chiamo con il seguente:

 double result = GetRandomNumber(1.23, 5.34); 

Ogni pensiero sarebbe apprezzato.

Sì.

Random.NextDouble restituisce un doppio tra 0 e 1. Quindi lo moltiplichi per l’intervallo in cui devi entrare (differenza tra il massimo e il minimo) e poi lo aggiungi alla base (minimo).

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

Il codice reale dovrebbe essere casuale un membro statico. Ciò consentirà di risparmiare il costo della creazione del generatore di numeri casuali e ti consentirà di chiamare GetRandomNumber molto frequentemente. Dal momento che stiamo inizializzando un nuovo RNG con ogni chiamata, se chiami abbastanza velocemente che l’ora del sistema non cambia tra le chiamate, l’RNG verrà seminato con lo stesso timestamp e genererà lo stesso stream di numeri casuali.

Johnny5 ha suggerito di creare un metodo di estensione. Ecco un esempio di codice più completo che mostra come potresti fare questo:

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

Ora puoi chiamarlo come se fosse un metodo nella class Random :

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

Si noti che non si devono creare molti nuovi oggetti Random in un ciclo perché questo renderà probabile che si ottenga lo stesso valore molte volte di seguito. Se hai bisogno di molti numeri casuali, crea un’istanza di Random e riutilizzala.

L’approccio più semplice genererebbe semplicemente un numero casuale compreso tra 0 e la differenza tra i due numeri. Quindi aggiungi il più piccolo dei due numeri al risultato.

Attenzione: se stai generando il random all’interno di un ciclo come per esempio for(int i = 0; i < 10; i++) , non inserire la new Random() dichiarazione new Random() all'interno del ciclo.

Da MSDN :

La generazione del numero casuale inizia da un valore seme. Se lo stesso seme viene usato ripetutamente, viene generata la stessa serie di numeri. Un modo per produrre sequenze diverse è quello di rendere il valore seme dipendente dal tempo, producendo quindi una serie diversa con ogni nuova istanza di Random. Per impostazione predefinita, il costruttore senza parametri della class Random utilizza l'orologio di sistema per generare il suo valore di inizializzazione ...

Quindi, sulla base di questo fatto, fai qualcosa come:

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

In questo modo hai la garanzia che otterrai due valori diversi.

Potresti usare un codice come questo:

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

Potresti fare questo:

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

Cosa succede se uno dei valori è negativo? Non sarebbe un’idea migliore essere:

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

A proposito di generare lo stesso numero casuale se lo si chiama in un ciclo una soluzione elegante è dichiarare il nuovo object Random () al di fuori del ciclo come variabile globale.

Si noti che è necessario dichiarare l’istanza della class Random al di fuori della funzione GetRandomInt se si eseguirà questo in un ciclo.

“Perché chiedi questo.

Bene, la class Random genera effettivamente numeri pseudo casuali, con il “seme” per il randomizzatore che è l’ora del sistema. Se il tuo loop è sufficientemente veloce, il tempo di clock del sistema non apparirà diverso dal randomizzatore e ogni nuova istanza della class Random inizierà con lo stesso seme e ti darà lo stesso numero pseudo casuale.

La fonte è qui: http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/

Se hai bisogno di un numero casuale nell’intervallo [ 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) 

Usa invece:

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

Sono un po ‘in ritardo per la festa, ma ho dovuto implementare una soluzione generale e ho scoperto che nessuna delle soluzioni in grado di soddisfare le mie esigenze.

La soluzione accettata è buona per le piccole gamme; tuttavia, maximum - minimum può essere infinito per grandi intervalli. Quindi una versione corretta può essere questa versione:

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

Questo genera numeri casuali anche tra double.MinValue e double.MaxValue . Ma questo introduce un altro “problema”, che è ben presentato in questo post : se usiamo intervalli così grandi i valori potrebbero sembrare troppo “innaturali”. Ad esempio, dopo aver generato 10.000 doppi random tra 0 e double.MaxValue tutti i valori erano compresi tra 2.9579E + 304 e 1.7976E + 308.

Così ho creato anche un’altra versione, che genera numeri su scala logaritmica:

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

Alcuni test:

Ecco i risultati ordinati della generazione di 10.000 numeri doppi casuali tra 0 e Double.MaxValue con entrambe le strategie. I risultati vengono visualizzati utilizzando la scala logaritmica:

0..Double.MaxValue

Sebbene i valori casuali lineari sembrino sbagliati a prima vista, le statistiche mostrano che nessuno di loro è “migliore” dell’altro: anche la strategia lineare ha una distribuzione uniforms e la differenza media tra i valori è praticamente la stessa con entrambe le strategie .

Giocare con gamme diverse mi ha mostrato che la strategia lineare diventa “sana di mente” con range compreso tra 0 e ushort.MaxValue con un valore minimo “ragionevole” di 10.78294704 (per ulong intervallo più lungo il valore minimo era 3.03518E + 15; int : 353341) . Questi sono gli stessi risultati di entrambe le strategie visualizzate con scale diverse:

0..UInt16.MaxValue

E il riassunto dei miei test:

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