Número aleatorio entre 2 números dobles

¿Es posible generar un número aleatorio entre 2 dobles?

Ejemplo:

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

Entonces lo llamo con lo siguiente:

 double result = GetRandomNumber(1.23, 5.34); 

Cualquier pensamiento sería apreciado.

Sí.

Random.NextDouble devuelve un doble entre 0 y 1. Luego lo multiplica por el rango al que debe ir (diferencia entre máximo y mínimo) y luego lo agrega a la base (mínimo).

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

El código real debería tener al azar ser un miembro estático. Esto ahorrará el costo de crear el generador de números aleatorios y le permitirá llamar GetRandomNumber con mucha frecuencia. Como estamos inicializando un nuevo RNG con cada llamada, si llama lo suficientemente rápido como para que la hora del sistema no cambie entre llamadas, el RNG se sembrará con la misma marca de tiempo y generará el mismo flujo de números aleatorios.

Johnny5 sugirió crear un método de extensión. Aquí hay un ejemplo de código más completo que muestra cómo puede hacer esto:

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

Ahora puede llamarlo como si fuera un método en la clase Random :

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

Tenga en cuenta que no debe crear muchos objetos Random nuevos en un bucle porque esto hará que sea probable que obtenga el mismo valor muchas veces seguidas. Si necesita muchos números aleatorios, cree una instancia de Random y vuelva a utilizarla.

El enfoque más simple generaría simplemente un número aleatorio entre 0 y la diferencia de los dos números. Luego agregue el menor de los dos números al resultado.

Cuidado: si está generando el random dentro de un bucle como, por ejemplo, for(int i = 0; i < 10; i++) , no coloque la new Random() statement new Random() dentro del bucle.

Desde MSDN :

La generación de números aleatorios comienza desde un valor inicial. Si la misma semilla se usa repetidamente, se genera la misma serie de números. Una forma de producir secuencias diferentes es hacer que el valor inicial sea dependiente del tiempo, produciendo así una serie diferente con cada instancia nueva de Aleatorio. De forma predeterminada, el constructor sin parámetros de la clase Random usa el reloj del sistema para generar su valor inicial ...

Entonces, basándote en este hecho, haz algo como:

 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 esta manera usted tiene la garantía de que obtendrá diferentes valores dobles.

Puede usar un código como este:

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

Podrías hacer esto:

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

¿Qué pasa si uno de los valores es negativo? No sería una mejor idea:

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

Acerca de generar el mismo número aleatorio si lo llama en un bucle, una solución ingeniosa es declarar el nuevo objeto Random () fuera del bucle como una variable global.

Observe que debe declarar su instancia de la clase Random fuera de la función GetRandomInt si va a ejecutar esto en un bucle.

“¿Por qué es esto?”, Preguntas.

Bueno, la clase aleatoria en realidad genera números seudoaleatorios, con la “semilla” para que el aleatorizador sea la hora del sistema. Si su ciclo es lo suficientemente rápido, la hora del reloj del sistema no aparecerá diferente al aleatorizador y cada nueva instancia de la clase Random comenzaría con la misma semilla y le dará el mismo número pseudo aleatorio.

La fuente está aquí: http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/

Si necesita un número aleatorio en el rango [ 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) 

Use en su lugar:

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

Llegué un poco tarde a la fiesta, pero necesitaba implementar una solución general y resultó que ninguna de las soluciones puede satisfacer mis necesidades.

La solución aceptada es buena para rangos pequeños; sin embargo, el maximum - minimum puede ser infinito para grandes rangos. Entonces, una versión corregida puede ser esta versión:

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

Esto genera números aleatorios muy bien incluso entre double.MinValue y double.MaxValue . Pero esto introduce otro “problema”, que está muy bien presentado en esta publicación : si usamos rangos tan grandes, los valores pueden parecer demasiado “antinaturales”. Por ejemplo, después de generar 10.000 dobles aleatorios entre 0 y double.MaxValue todos los valores estaban entre 2.9579E + 304 y 1.7976E + 308.

Así que también creé otra versión, que genera números en una escala logarítmica:

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

Algunas pruebas:

Aquí están los resultados ordenados de generar 10,000 números dobles al azar entre 0 y Double.MaxValue con ambas estrategias. Los resultados se muestran con una escala logarítmica:

0..Double.MaxValue

Aunque los valores aleatorios lineales parecen estar equivocados a primera vista, las estadísticas muestran que ninguno de ellos es “mejor” que el otro: incluso la estrategia lineal tiene una distribución uniforme y la diferencia promedio entre los valores es prácticamente la misma con ambas estrategias .

Jugar con diferentes rangos me mostró que la estrategia lineal llega a ser “sensata” con un rango entre 0 y ushort.MaxValue con un valor mínimo “razonable” de 10.78294704 (para un rango ulong el valor mínimo era 3.03518E + 15; int : 353341) . Estos son los mismos resultados de ambas estrategias mostradas con diferentes escalas:

0..UInt16.MaxValue

Y el resumen de mis pruebas:

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