Número aleatorio en el largo scope, ¿es este el camino?

¿Alguien puede verificar este método? Necesito un número de tipo largo dentro de un rango de dos largos. Uso la función .NET Random.Next (min, max) que devuelve int. ¿Es correcto mi razonamiento si simplemente divido el largo por 2, genero el número aleatorio y finalmente lo multiplico por 2 nuevamente? O soy demasiado entusiasta … Entiendo que mi resolución aleatoria disminuirá, pero ¿hay algún otro error que no conduzca a ese número aleatorio?

long min = st.MinimumTime.Ticks; //long is Signed 64-bit integer long max = st.MaximumTime.Ticks; int minInt = (int) (min / 2); //int is Signed 64-bit integer int maxInt = (int) (max / 2); //int is Signed 64-bit integer Random random = new Random(); int randomInt = random.Next(minInt, maxInt); long randomLong = (randomInt * 2); 

¿Por qué no solo Int64 dos valores aleatorios de Int32 y haces un Int64 de ellos?

 long LongRandom(long min, long max, Random rand) { long result = rand.Next((Int32)(min >> 32), (Int32)(max >> 32)); result = (result << 32); result = result | (long)rand.Next((Int32)min, (Int32)max); return result; } 

Lo siento, olvidé agregar límites la primera vez. Se agregaron parámetros mínimos y max . Puedes probarlo así:

 long r = LongRandom(100000000000000000, 100000000000000050, new Random()); 

Los valores de r estarán en el rango deseado.

EDITAR: la implementación anterior es defectuosa. Probablemente valga la pena generar 4 enteros de 16 bits en lugar de 2 de 32 bits para evitar problemas con signo no firmado. Pero en este momento la solución pierde su elegancia, así que creo que es mejor seguir con la versión Random.NextBytes :

 long LongRandom(long min, long max, Random rand) { byte[] buf = new byte[8]; rand.NextBytes(buf); long longRand = BitConverter.ToInt64(buf, 0); return (Math.Abs(longRand % (max - min)) + min); } 

Se ve bastante bien en términos de distribución de valores (a juzgar por las pruebas muy simples que realicé).

Esto crea un Int64 aleatorio al usar bytes aleatorios, evitando el sesgo de módulo volviendo a intentar si el número está fuera del rango seguro.

 static class RandomExtensions { public static long RandomLong(this Random rnd) { byte[] buffer = new byte[8]; rnd.NextBytes (buffer); return BitConverter.ToInt64(buffer, 0); } public static long RandomLong(this Random rnd, long min, long max) { EnsureMinLEQMax(ref min, ref max); long numbersInRange = unchecked(max - min + 1); if (numbersInRange < 0) throw new ArgumentException("Size of range between min and max must be less than or equal to Int64.MaxValue"); long randomOffset = RandomLong(rnd); if (IsModuloBiased(randomOffset, numbersInRange)) return RandomLong(rnd, min, max); // Try again else return min + PositiveModuloOrZero(randomOffset, numbersInRange); } static bool IsModuloBiased(long randomOffset, long numbersInRange) { long greatestCompleteRange = numbersInRange * (long.MaxValue / numbersInRange); return randomOffset > greatestCompleteRange; } static long PositiveModuloOrZero(long dividend, long divisor) { long mod; Math.DivRem(dividend, divisor, out mod); if(mod < 0) mod += divisor; return mod; } static void EnsureMinLEQMax(ref long min, ref long max) { if(min <= max) return; long temp = min; min = max; max = temp; } } 

Algunas otras respuestas aquí tienen dos problemas: tener un sesgo de módulo y no manejar correctamente los valores de max = long.MaxValue . ( La respuesta de Martin no tiene ningún problema, pero su código es irrazonablemente lento con rangos grandes).

El siguiente código solucionará todos estos problemas:

 //Working with ulong so that modulo works correctly with values > long.MaxValue ulong uRange = (ulong)(max - min); //Prevent a modolo bias; see https://stackoverflow.com/a/10984975/238419 //for more information. //In the worst case, the expected number of calls is 2 (though usually it's //much closer to 1) so this loop doesn't really hurt performance at all. ulong ulongRand; do { byte[] buf = new byte[8]; random.NextBytes(buf); ulongRand = (ulong)BitConverter.ToInt64(buf, 0); } while (ulongRand > ulong.MaxValue - ((ulong.MaxValue % uRange) + 1) % uRange); return (long)(ulongRand % uRange) + min; 

La siguiente clase completamente documentada se puede soltar en su base de código para implementar la solución anterior fácilmente y sin cerebro. Al igual que todos los códigos en Stackoverflow, tiene licencia bajo atribución CC, por lo que puede usarlo para usarlo básicamente para lo que desee.

 using System; namespace MyNamespace { public static class RandomExtensionMethods { ///  /// Returns a random long from min (inclusive) to max (exclusive) ///  /// The given random instance /// The inclusive minimum bound /// The exclusive maximum bound. Must be greater than min public static long NextLong(this Random random, long min, long max) { if (max <= min) throw new ArgumentOutOfRangeException("max", "max must be > min!"); //Working with ulong so that modulo works correctly with values > long.MaxValue ulong uRange = (ulong)(max - min); //Prevent a modolo bias; see https://stackoverflow.com/a/10984975/238419 //for more information. //In the worst case, the expected number of calls is 2 (though usually it's //much closer to 1) so this loop doesn't really hurt performance at all. ulong ulongRand; do { byte[] buf = new byte[8]; random.NextBytes(buf); ulongRand = (ulong)BitConverter.ToInt64(buf, 0); } while (ulongRand > ulong.MaxValue - ((ulong.MaxValue % uRange) + 1) % uRange); return (long)(ulongRand % uRange) + min; } ///  /// Returns a random long from 0 (inclusive) to max (exclusive) ///  /// The given random instance /// The exclusive maximum bound. Must be greater than 0 public static long NextLong(this Random random, long max) { return random.NextLong(0, max); } ///  /// Returns a random long over all possible values of long (except long.MaxValue, similar to /// random.Next()) ///  /// The given random instance public static long NextLong(this Random random) { return random.NextLong(long.MinValue, long.MaxValue); } } } 

Uso:

 Random random = new Random(); long foobar = random.NextLong(0, 1234567890L); 

Aquí hay una solución que aprovecha las otras respuestas usando Random.NextBytes , pero también presta una cuidadosa atención a los casos límite. Lo he estructurado como un conjunto de métodos de extensión. Además, he tenido en cuenta el sesgo de módulo, al muestrear otro número aleatorio que cae fuera del rango.

Una de mis quejas (al menos para la situación en la que estaba tratando de usarla) es que el máximo suele ser exclusivo, así que si quieres tirar un dado, haces algo como Random.Next(0,7) . Sin embargo, esto significa que nunca puede obtener esta sobrecarga para devolver el .MaxValue para el tipo de datos ( int , long , ulong , what-have-you). Por lo tanto, he agregado una bandera inclusiveUpperBound para alternar este comportamiento.

 public static class Extensions { //returns a uniformly random ulong between ulong.Min inclusive and ulong.Max inclusive public static ulong NextULong(this Random rng) { byte[] buf = new byte[8]; rng.NextBytes(buf); return BitConverter.ToUInt64(buf, 0); } //returns a uniformly random ulong between ulong.Min and Max without modulo bias public static ulong NextULong(this Random rng, ulong max, bool inclusiveUpperBound = false) { return rng.NextULong(ulong.MinValue, max, inclusiveUpperBound); } //returns a uniformly random ulong between Min and Max without modulo bias public static ulong NextULong(this Random rng, ulong min, ulong max, bool inclusiveUpperBound = false) { ulong range = max - min; if (inclusiveUpperBound) { if (range == ulong.MaxValue) { return rng.NextULong(); } range++; } if (range <= 0) { throw new ArgumentOutOfRangeException("Max must be greater than min when inclusiveUpperBound is false, and greater than or equal to when true", "max"); } ulong limit = ulong.MaxValue - ulong.MaxValue % range; ulong r; do { r = rng.NextULong(); } while(r > limit); return r % range + min; } //returns a uniformly random long between long.Min inclusive and long.Max inclusive public static long NextLong(this Random rng) { byte[] buf = new byte[8]; rng.NextBytes(buf); return BitConverter.ToInt64(buf, 0); } //returns a uniformly random long between long.Min and Max without modulo bias public static long NextLong(this Random rng, long max, bool inclusiveUpperBound = false) { return rng.NextLong(long.MinValue, max, inclusiveUpperBound); } //returns a uniformly random long between Min and Max without modulo bias public static long NextLong(this Random rng, long min, long max, bool inclusiveUpperBound = false) { ulong range = (ulong)(max - min); if (inclusiveUpperBound) { if (range == ulong.MaxValue) { return rng.NextLong(); } range++; } if (range <= 0) { throw new ArgumentOutOfRangeException("Max must be greater than min when inclusiveUpperBound is false, and greater than or equal to when true", "max"); } ulong limit = ulong.MaxValue - ulong.MaxValue % range; ulong r; do { r = rng.NextULong(); } while(r > limit); return (long)(r % range + (ulong)min); } } 

Su randomLong siempre será parejo y habrá eliminado aún más valores porque está muy lejos del máximo por long , el máximo para long es 2 ^ 32 * max para int. Deberías usar Random.NextBytes .

Comience por lo mínimo, agregue un porcentaje aleatorio de la diferencia entre el mínimo y el máximo. El problema con esto es que NextDouble devuelve un número x tal que 0 <= x <1, por lo que existe la posibilidad de que nunca llegue al número máximo.

 long randomLong = min + (long)(random.NextDouble() * (max - min)); 

Puede probar la biblioteca CryptoRandom of the Inferno :

 public class CryptoRandom : Random // implements all Random methods, as well as: public byte[] NextBytes(int count) public long NextLong() public long NextLong(long maxValue) public long NextLong(long minValue, long maxValue) 

Es mejor que tome la diferencia entre el mínimo y el máximo (si cabe en un int), obtenga un valor aleatorio entre 0 y eso, y sume al mínimo.

¿Hay algo de malo con el uso de este enfoque simple?

  long min = 10000000000001; long max = 99999999999999; Random random = new Random(); long randomNumber = min + random.Next() % (max - min); 

re

Mi solución trabajada Probado por más de 1000 veces:

 public static long RandomLong(long min, long max) { return min + (long)RandomULong(0, (ulong)Math.Abs(max - min)); } public static ulong RandomULong(ulong min, ulong max) { var hight = Rand.Next((int)(min >> 32), (int)(max >> 32)); var minLow = Math.Min((int)min, (int)max); var maxLow = Math.Max((int)min, (int)max); var low = (uint)Rand.Next(minLow, maxLow); ulong result = (ulong)hight; result <<= 32; result |= (ulong)low; return result; } 
 private long randomLong() { Random random = new Random(); byte[] bytes = new byte[8]; _random.NextBytes(bytes); return BitConverter.ToInt64(bytes, 0); } 

¿Qué hay de generar bytes y convertir a int64?

 /* generate a byte array, then convert to unint64 */ var r = new Random(); // DONT do this for each call - use a static Random somewhere var barray = new byte[64/8]; r.NextBytes(barray); var rint64 = BitConverter.ToUInt64(barray, 0); 

Ve a trabajar para mí (:

¿Qué hay de malo en generar un double para que sea un factor que se utilizará para calcular el valor real real a partir del valor máximo que puede ser un valor long ?

 long result = (long)Math.Round( random.NextDouble() * maxLongValue ); 
  • NextDouble genera un número aleatorio entre [0.0, 0.99999999999999978] ( msdn doc )

  • Multiplica este número aleatorio por su maxLongValue .

  • Math.Round . Math.Round ese resultado para que pueda obtener la oportunidad de obtener maxLongValue todos modos (por ejemplo: simule que obtuvo 1.0 de NextDouble).

  • Haces retroceder a long .