Подтвердить что ты не робот

Случайное число на большом расстоянии, так ли?

Может ли кто-нибудь проверить этот метод. Мне нужен длинный номер в пределах двух длин. Я использую функцию .NET Random.Next(min, max), возвращающую int. Правильно ли я рассуждаю, если я просто разделил длинный на 2, сгенерировал случайное число и, наконец, снова умножил его на 2? Или я слишком восторжен... Я понимаю, что мое случайное разрешение уменьшится, но есть ли другие ошибки, которые не приведут к такому случайному числу.

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);
4b9b3361

Ответ 1

Почему бы вам просто не создать два случайных значения Int32 и сделать из них Int64?

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

Извините, я забыл добавлять границы в первый раз. Добавлены параметры min и max. Вы можете проверить это следующим образом:

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

Значения r будут находиться в нужном диапазоне.

РЕДАКТИРОВАТЬ: описанная реализация ошибочна. Вероятно, это стоит того, чтобы генерировать 4 16-битных целых числа, а не 2 32-разрядных, чтобы избежать проблем с подписью без знака. Но на данный момент решение теряет свою элегантность, поэтому я думаю, что лучше всего придерживаться версии 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);
}

Это выглядит довольно хорошо с точки зрения распределения стоимости (судя по очень простым тестам, которые я запускал).

Ответ 2

Это создает случайный Int64 с использованием случайных байтов, избегая смещения по модулю путем повторной попытки, если число находится за пределами безопасного диапазона.

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

Ответ 3

В некоторых других ответах есть два вопроса: наличие модульного смещения и невозможность корректно обрабатывать значения max = long.MaxValue. (ответ Мартина не имеет проблем, но его код необоснованно медленный с большими диапазонами.)

Следующий код исправит все эти проблемы:

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

Следующий полностью документированный класс можно отбросить в вашу кодовую базу, чтобы реализовать это решение легко и без мозгов. Как и весь код в Stackoverflow, он лицензируется в соответствии с CC-атрибуцией, поэтому вы можете свободно использовать его для использования в основном независимо от того, что вы хотите.

using System;

namespace MyNamespace
{
    public static class RandomExtensionMethods
    {
        /// <summary>
        /// Returns a random long from min (inclusive) to max (exclusive)
        /// </summary>
        /// <param name="random">The given random instance</param>
        /// <param name="min">The inclusive minimum bound</param>
        /// <param name="max">The exclusive maximum bound.  Must be greater than min</param>
        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;
        }

        /// <summary>
        /// Returns a random long from 0 (inclusive) to max (exclusive)
        /// </summary>
        /// <param name="random">The given random instance</param>
        /// <param name="max">The exclusive maximum bound.  Must be greater than 0</param>
        public static long NextLong(this Random random, long max)
        {
            return random.NextLong(0, max);
        }

        /// <summary>
        /// Returns a random long over all possible values of long (except long.MaxValue, similar to
        /// random.Next())
        /// </summary>
        /// <param name="random">The given random instance</param>
        public static long NextLong(this Random random)
        {
            return random.NextLong(long.MinValue, long.MaxValue);
        }
    }
}

Использование:

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

Ответ 4

Вот решение, которое использует другие ответы, используя Random.NextBytes, но также уделяет пристальное внимание граничным случаям. Я структурировал его как набор методов расширения. Кроме того, я учитывал смещение по модулю, путем выборки другого случайного числа, которое выпадает из диапазона.

Одна из моих проблем (по крайней мере, для ситуации, в которой я пытался ее использовать) заключается в том, что максимум обычно является исключительным, поэтому, если вы хотите катить кубик, вы делаете что-то вроде Random.Next(0,7). Однако это означает, что вы никогда не сможете получить эту перегрузку, чтобы вернуть .MaxValue для типа данных (int, long, ulong, what-have-you). Поэтому я добавил флаг inclusiveUpperBound для переключения этого поведения.

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

Ответ 5

Ваш randomLong всегда будет четным, и вы исключите еще больше значений, потому что вы очень далеко от максимума для long, максимум для long - 2 ^ 32 * max для int. Вы должны использовать Random.NextBytes.

Ответ 6

Начните с минимума, добавьте случайный процент от разницы между min и max. Проблема в том, что NextDouble возвращает число x такое, что 0 <= x < 1, так что шанс, что вы никогда не нажмете максимальное количество.

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

Ответ 7

Вы можете попробовать CryptoRandom Inferno library:

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)

Ответ 8

Вам лучше не принимать разницу между минимальным и максимальным (если он подходит в int), получая случайное значение от 0 до этого и добавляя его к минимуму.

Ответ 9

Есть ли что-то неправильное в использовании этого простого подхода?

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

д

Ответ 10

Мое работающее решение. Протестировано более 1000 раз:

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

Ответ 11

private long randomLong()
{
    Random random = new Random();
    byte[] bytes = new byte[8];
    _random.NextBytes(bytes);
    return BitConverter.ToInt64(bytes, 0);
}

Ответ 12

Что не так с созданием double для использования в качестве фактора, который будет использоваться для вычисления фактического значения long, начиная с максимального значения a long, может быть?!

long result = (long)Math.Round( random.NextDouble() * maxLongValue );
  • NextDouble генерирует случайное число между [0.0, 0.99999999999999978] (msdn doc)

  • Вы умножаете это случайное число на maxLongValue.

  • Вы получите Math.Round, чтобы получить возможность получить maxLongValue в любом случае (например: имитировать, что вы получили 1.0 из NextDouble).

  • Вы вернетесь к long.

Ответ 13

Как насчет генерации байтов и преобразования в 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);

Видит работать для меня (: