Random number in long range, is this the way?
Asked Answered
C

18

69

Can somebody verify this method. I need a long type number inside a range of two longs. I use the .NET Random.Next(min, max) function which return int's. Is my reasoning correct if I simply divide the long by 2, generate the random number and finally multiply it by 2 again? Or am I too enthusiastic... I understand that my random resolution will decrease but are there any other mistakes which will lead to no such a random number.

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);
Clannish answered 11/7, 2011 at 14:21 Comment(1)
Make sure that the random is only declared one time.Alpine
A
110

Why don't you just generate two random Int32 values and make one Int64 out of them?

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

Sorry, I forgot to add boundaries the first time. Added min and max params. You can test it like that:

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

Values of r will lie in the desired range.

EDIT: the implementation above is flawed. It's probably worth it to generate 4 16-bit integers rather than 2 32-bit ones to avoid signed-unsigned problems. But at this point the solution loses its elegancy, so I think it's best to stick with Random.NextBytes version:

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

It looks pretty well in terms of value distribution (judging by very simple tests I ran).

Asphyxia answered 11/7, 2011 at 14:28 Comment(27)
@user839032: it actually has bugs in it, the snippet above was meant to demonstrate and idea. I'll update the answer later with a robust solutionAsphyxia
I implemented it and a first shot looks good. Can it be that the but is here "result = result | (long)rand.Next((Int32)min, (Int32)max);" where the int casts can become negative?Clannish
@user839032: this is a naive implementation, it will fail at certain samples because Int32 is a signed type so it acts weird when you try to use it as bits of unsigned number. One solution is to make 4 random numbers 16 bytes each, not 2 like in my sampleAsphyxia
@user893032: please check my corrected answer. It seems like it's best to stick with using NextBytes after all, I included the working sample.Asphyxia
Doesn't work properly. LongRandom(long.MinValue, long.MaxValue, new Random()), always returns -9223372036854775808. In any case, Math.Abs() destroys one bit, leaving you with 63 random bits. You can't provide a 64-bit random number if you only have 63 random bits.Ramadan
The will only work if min and max for some powers of two :] e.g. min=0 and max=0x100000000 will only produce those two values. The second will work if max - min doesn't overflow to be a negative number.Comet
As Random works on 32bits even if you generate 8 bytes, there can only be 2^32 possible outcomes. So you will only generate 2^32 longsPirouette
Worth mentioning that in your updated version, the max is exclusive max, consistent with the System.Random.Next() method, which is good.Catlaina
@Asphyxia are you SURE that it will be uniformly generated value?Fiertz
@weston, that's not correct. -- Random can fill an 8 byte array just fine.Spire
@Spire I think my point was, how many seeds can you start random with? 2^32. So how many different 8 byte sequences can a new instance of Random produce? No more than 2^32. So have you made a random 64bit? Not really if the vast majority of 64bit numbers can't be produced in the first draw.Pirouette
@Pirouette That's a good point. You may want to "double seed" the generator by using a random seed, then asking for (and discarding) a random number of bytes.Bullock
@Bullock but where does that second random number come from?Pirouette
@Pirouette I recommend getting it from System.Security.Cryptography.RNGCryptoServiceProviderBullock
@Bullock then you might as well get the long from there.Pirouette
@Pirouette that's correct, if you only need one of them.Bullock
@Bullock I don't know why needing 1 is important. It all depends on what you need it for. If you need a repeatable random long, you can't use a random that can't be seeded. If it's for security or fair gaming, then you would only use a secure random. I do not think you ever want to mix them in one operation.Pirouette
@Pirouette it's a performance issue. Secure crypto is much slower, but you can use it to provide a seed that isn't limited to 2^32 random value streams. Then subsequent random values can come from a more performant library.Bullock
@Bullock I think you've not thought it through fully. What would skipping a random number of values look like? How many is enough? Too low and you've not added enough extra entropy and too high you're going to cause performance issues yourself.Pirouette
@Bullock Let's say you skip between [0..1024) random numbers at the start. Now I accept that first 64 bit random is from a larger set, but this set has just grown from 2^32 to 1024*2^32 = 2^42. It's still not a fair draw in the range of 2^64. To do that we need to skip [0..2^32) random numbers in a loop! That is clearly not practical.Pirouette
@Pirouette That's correct, you need to skip (up to) 32 bits to provide 64 bits. It takes about 8 seconds in the worst case scenario on my PC--acceptable in use cases where some start-up time is acceptable. If something more performant is needed, I'd switch over to SFMT (a hyper-optimized Mersenne Twister).Bullock
@Bullock 8 seconds is acceptable?!! Yet using a secure random is a perf issue? Face facts, this method is simply not a good idea.Pirouette
@Pirouette I can only speak for my uses. My application uses trillions of new random numbers every run. That isn't that unusual. Bear in mind that this is only if you need 2^64 starting positions. If you only need 2^61, it will only take 1 second. If you only need 2^57, it will take less than a tenth of a second.Bullock
Concatenating integers won't really generate a random number because it guarantees that the "random" number generated will never be smaller than the largest possible integer value, plus one. A better method would be to create two random 32-bit integers and multiply them together to get your 64-bit long value.Toland
Need to test your edge cases. If min == long.MinValue and max == long.MaxValue, it always returns the same number.Ladybug
This doesn't work. Ran this in a loop for 10 minutes and wasn't able to produce a value less than int.MaxValueTelephonist
C#10 now has long randoms built in. Use NextInt64 if you can. learn.microsoft.com/en-us/dotnet/api/…Acetophenetidin
E
52

Some other answers here have two issues: having a modulo bias, and failing to correctly handle values of max = long.MaxValue. (Martin's answer has neither problem, but his code is unreasonably slow with large ranges.)

The following code will fix all of those issues:

//Working with ulong so that modulo works correctly with values > long.MaxValue
ulong uRange = (ulong)(max - min);

//Prevent a modolo bias; see https://mcmap.net/q/15753/-why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator
//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;

The following fully-documented class can be dropped into your codebase to implement the above solution easily and brain-free. Like all code on Stackoverflow, it's licensed under CC-attribution, so you can feel free to use to use it for basically whatever you want.

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://mcmap.net/q/15753/-why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator
            //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);
        }
    }
}

Usage:

Random random = new Random();
long foobar = random.NextLong(0, 1234567890L);
Emunctory answered 26/10, 2012 at 22:13 Comment(7)
@agent-j: Good catch on max == min, I'll fix that now (it actually should not work, since max is an exclusive upper-bound; but it was not throwing an exception like it should). However, the bias is already fixed; ulongRand is evenly distributed over 0 to uRange * (int)(ulong.MaxValue / uRange) - 1, meaning ulongRange % uRange is evenly distributed over 0 to uRange - 1Emunctory
There still seems to be a bias for small ranges (though one could argue it's not that very big). The value of ulong.MaxValue is 18,446,744,073,709,551,615 (notice that it ends in 615). If we pick a uRange of size 100, and ulongRand falls the last 15 (ulong.MaxValue % uRange), it should be thrown out, but you are throwing out the last 100 (by subtracting uRange), thus giving a tiny bias. Perhaps this is what you need while (ulongRand >= ulong.MaxValue - (ulong.MaxValue % uRange))Polypropylene
@agent-j: You're right, but that correction still doesn't work quite right (try ulong.MaxValue = 9, uRange = 5 - every value from 0-9 should be valid, but your solution loops for half the space!). You need to add 1 to ulong.MaxValue for it to be correct.. but that still won't work because the value will loop around! So, we need to mod before adding, then mod again (in case we hit uRange). The final correction looks like this: while (ulongRand > ulong.MaxValue - ((ulong.MaxValue % uRange) + 1) % uRange)Emunctory
My timings show that my code takes ~210ms for generating 1,000,000 random numbers between long.MinValue and long.MaxValue and takes yours ~260ms for the same range and number of iterations. Pretty quick either way, I'm just defending that my code is not "unreasonably slow with large ranges"Designation
Your NextLong should map to NextLong(0, long.MaxValue) because Random.Next() returns a non-negative integer. Also, perhaps initialize buf outside the loop for the rare times it loops?Palecek
I guess using random bits to get a unbiased random value that is not in a range of a power of 2, for example a random number from (0, 1, 2) is impossible, as 2^n % 3 is never 0 for any number of bits n.Cinque
What do you think of Dyppl's answer at the top? Is that unbiased? Also, I suggest scrapping the other two overloaded methods and simply declaring the main one like this: public long NextLong(long min=0, long max = long.MaxValue). As well as being flexible, this also imitates C#'s usage of Next much more closely (starts at zero).Avast
P
28

This creates a random Int64 by using random bytes, avoiding modulo bias by retrying if the number is outside the safe range.

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;
   }
}
Polypropylene answered 11/7, 2011 at 14:28 Comment(1)
You should really have named your extension methods NextLong instead of RandomLong, as they would follow the naming convention of the existing methods of the Random class.Spire
D
10

Here is a solution that leverages from the other answers using Random.NextBytes, but also pays careful attention to boundary cases. I've structured it as a set of extension methods. Also, I've accounted for modulo bias, by sampling another random number it falls out of range.

One of my gripes (at least for the situation I was trying to use it) is that the maximum is usually exclusive so if you want to roll a die, you do something like Random.Next(0,7). However, this means you can never get this overload to return the .MaxValue for the datatype (int, long, ulong, what-have-you). Therefore, I've added an inclusiveUpperBound flag to toggle this behavior.

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);
    }
}
Designation answered 24/7, 2012 at 23:24 Comment(1)
This works! Even in corner cases such is (long.MinValue, long.MaxValue).Estancia
L
5
private long randomLong()
{
    Random random = new Random();
    byte[] bytes = new byte[8];
    random.NextBytes(bytes);
    return BitConverter.ToInt64(bytes, 0);
}
Larhondalari answered 17/3, 2016 at 3:4 Comment(1)
Nice, I wasn't interested in a range of values, just wanted a simple way to get some random 64 bits. Thank you.Authorize
G
4

Start at the minimum, add a random percentage of the difference between the min and the max. Problem with this is that NextDouble returns a number x such that 0 <= x < 1, so there's a chance you'll never hit the max number.

long randomLong = min + (long)(random.NextDouble() * (max - min));
Gracious answered 11/7, 2011 at 14:29 Comment(2)
Based on the number of digits in double's precision, this would exclude a lot of numbers, but still a good method.Inflight
I can see that happening if min and max are sufficiently far apart, in which case you'd have to test it millions of times before any problem became apparent.Gracious
N
4

This will get you a secure random long:

using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider()) 
{ 
    byte[] rno = new byte[9];    
    rg.GetBytes(rno);    
    long randomvalue = BitConverter.ToInt64(rno, 0); 
}
Nina answered 29/11, 2019 at 13:12 Comment(1)
Why use 9 bytes?Zachary
A
3

C#10 now has long randoms built in.

Random random = new Random();
long myRandomNumber = random.NextInt64(min, max);
Acetophenetidin answered 14/10, 2022 at 5:45 Comment(1)
Now that C#10 has been out for a couple of years(now on C# 11), this should be near the top.Bordelaise
L
2

I wrote some Test Methods and check my own method and many of the answers from this and the same questions. Generation of redundant values is a big problem. I found @BlueRaja - Danny Pflughoeft answer at this address Is good enough and did not generate redundant values at least for first 10,000,000s. This is a Test Method:

[TestMethod]
    public void TestRand64WithExtensions()
    {
        Int64 rnum = 0;
        HashSet<Int64> hs = new HashSet<long>();
        Random randAgent = new Random((int)DateTime.Now.Ticks);

        for (int i = 0; i < 10000000; i++)
        {
            rnum = randAgent.NextLong(100000000000000, 999999999999999);
            //Test returned value is greater than zero
            Assert.AreNotEqual(0, rnum);
            //Test Length of returned value
            Assert.AreEqual(15, rnum.ToString().Length);
            //Test redundancy
            if (!hs.Contains(rnum)) { hs.Add(rnum); }
            else
            {
                //log redundant value and current length we received
                Console.Write(rnum + " | " + hs.Count.ToString());
                Assert.Fail();
            }
        }
    }

I didn't want to post this as an answer but I can't stuff this in the comment section and I didn't want to add as an edit to answer without author consent. So pardon me as this is not an independent answer and maybe just a prove to one of the answers.

Longueur answered 11/7, 2011 at 14:21 Comment(2)
Great 'answer'. I think Stackoverflow needs to consider 'meta' answers like this as an addition to normal answers.Avast
@DanW Thanks for your kindly response and bringing up an important point. As I said, I was unable to add the source in the comment section, so I had to provide it in the discrete answer. In terms of adding the ability to a meta answer, I agree with you, and I would be glad to accompany you if you decide to make an official suggestion.Longueur
I
2

Your randomLong will always be even and you will have eliminated even more values because you are very far away from the maximum for long, The maximum for long is 2^32 * max for int. You should use Random.NextBytes.

Inflight answered 11/7, 2011 at 14:28 Comment(0)
H
2

You can try CryptoRandom of the 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)
Higdon answered 17/7, 2015 at 10:37 Comment(0)
T
1

I wrote a benchmarking C# console app that tests 5 different methods for generating unsigned 64-bit integers. Some of those methods are mentioned above. Method #5 appeared to consistently be the quickest. I claim to be no coding genius, but if this helps you, you're welcome to it. If you have better ideas, please submit. - Dave ([email protected])

enter code here

  static private Random _clsRandom = new Random();
  private const int _ciIterations = 100000;

  static void Main(string[] args)
  {
      RunMethod(Method1);
      RunMethod(Method2);
      RunMethod(Method3);
      RunMethod(Method4);
      RunMethod(Method5);

      Console.ReadLine();
  }

  static void RunMethod(Func<ulong> MethodX)
  {
      ulong ulResult;
      DateTime dtStart;
      TimeSpan ts;

      Console.WriteLine("--------------------------------------------");
      Console.WriteLine(MethodX.Method.Name);
      dtStart = DateTime.Now;
      for (int x = 1; x <= _ciIterations; x++)
          ulResult = MethodX.Invoke();
      ts = DateTime.Now - dtStart;

      Console.WriteLine(string.Format("Elapsed time: {0} milliseconds", ts.TotalMilliseconds));
  }

  static ulong Method1()
  {
      int x1 = _clsRandom.Next(int.MinValue, int.MaxValue);
      int x2 = _clsRandom.Next(int.MinValue, int.MaxValue);
      ulong y;

      // lines must be separated or result won't go past 2^32
      y = (uint)x1;
      y = y << 32;
      y = y | (uint)x2;

      return y;
  }

  static ulong Method2()
  {
      ulong ulResult = 0;

      for(int iPower = 0; iPower < 64; iPower++)
      {
          double dRandom = _clsRandom.NextDouble();
          if(dRandom > 0.5)
          {
              double dValue = Math.Pow(2, iPower);
              ulong ulValue = Convert.ToUInt64(dValue);
              ulResult = ulResult | ulValue;
          }
      }

      return ulResult;
  }

  static ulong Method3()  // only difference between #3 and #2 is that this one (#3) uses .Next() instead of .NextDouble()
  {
      ulong ulResult = 0;

      for (int iPower = 0; iPower < 64; iPower++)
          if (_clsRandom.Next(0, 1) == 1)
              ulResult = ulResult | Convert.ToUInt64(Math.Pow(2, iPower));

      return ulResult;
  }

static ulong Method4()
{
    byte[] arr_bt = new byte[8];
    ulong ulResult;

    _clsRandom.NextBytes(arr_bt);
    ulResult = BitConverter.ToUInt64(arr_bt, 0);
    return ulResult;
}

// Next method courtesy of https://mcmap.net/q/63264/-how-to-convert-unsigned-integer-to-signed-integer-without-overflowexception/39107847
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
struct EvilUnion
{
    [System.Runtime.InteropServices.FieldOffset(0)] public int Int32;
    [System.Runtime.InteropServices.FieldOffset(0)] public uint UInt32;
}
static ulong Method5()
{
    var evil = new EvilUnion();
    ulong ulResult = 0;

    evil.Int32 = _clsRandom.Next(int.MinValue, int.MaxValue);
    ulResult = evil.UInt32;
    ulResult = ulResult << 32;
    evil.Int32 = _clsRandom.Next(int.MinValue, int.MaxValue);
    ulResult = ulResult | evil.UInt32;

    return ulResult;
}

}

Tiflis answered 12/11, 2019 at 20:51 Comment(0)
A
1

I'll add my solution for generating random unsigned long integer (random ulong) below max value.

    public static ulong GetRandomUlong(ulong maxValue)
    {
        Random rnd = new Random();
        
        //This algorithm works with inclusive upper bound, but random generators traditionally have exclusive upper bound, so we adjust.
        //Zero is allowed, function will return zero, as well as for 1. Same behavior as System.Random.Next().
        if (maxValue > 0) maxValue--;   
                    
        byte[] maxValueBytes = BitConverter.GetBytes(maxValue); 
        byte[] result = new byte[8];
                    
        int i;
        for(i = 7; i >= 0; i--)
        {
                //senior bytes are either zero (then Random will write in zero without our help), or equal or below that of maxValue
                result[i] = (byte)rnd.Next( maxValueBytes[i] + 1 );         
                
                //If, going high bytes to low bytes, we got ourselves a byte, that is lower than that of MaxValue, then lower bytes may be of any value.
                if ((uint)result[i] < maxValueBytes[i])  break;
        }
                        
        for(i--; i >= 0; i--) // I like this row
        {
                result[i] = (byte)rnd.Next(256);
        }
                
        return BitConverter.ToUInt64(result, 0);
    }
Arlettearley answered 15/3, 2022 at 10:57 Comment(0)
S
-1

You're better off taking the difference between minimum and maximum (if it fits in an int), getting a random between 0 and that, and adding it to the minimum.

Saltire answered 11/7, 2011 at 14:24 Comment(0)
C
-1

Is there anything wrong with using this simple approach?

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

d

Coelho answered 29/6, 2013 at 8:15 Comment(1)
random.Next() will give you an int, so you're not even coming close to max.Atonal
H
-1

My worked solution. Tested for 1000+ times:

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;
}
Handcart answered 9/2, 2016 at 15:3 Comment(0)
U
-1

What's wrong with generating a double to be intended as a factor to be used to calculate the actual long value starting from the max value a long can be?!

long result = (long)Math.Round( random.NextDouble() * maxLongValue );
  • NextDouble generates a random number between [0.0, 0.99999999999999978] (msdn doc)

  • You multiply this random number by your maxLongValue.

  • You Math.Round that result so you can get the chance to get maxLongValue anyway (eg: simulate you got 1.0 from the NextDouble).

  • You cast back to long.
Unsteel answered 27/10, 2016 at 7:41 Comment(5)
The problem here is that Random.NextDouble operates in a 32-bit range, so your sample range is way smaller than you'd think. I was using this initially and noticed that I got a horrible amount of collisions.Atonal
@PhilippSumi 32 bit range is ok as long as generating integers is ok. You should have to prove you get more collisions than in theory to us in order to check you are missing something else.Unsteel
This thread and the solution was posted in the context of long numbers, which are 64 bits. With a 32-bit range, your risk of getting collisions is nearly 100% with only 100K samples. I actually got bit by this just recently. For a probability graph, see also blogs.msdn.microsoft.com/ericlippert/2010/03/22/…Atonal
@PhilippSumi since i'm using the random number as a percentage and i calculate the long number by multiplying that percentage with the max value a long number can be, this solution is all right.Unsteel
When maxLongValue == long.MaxValue this shows that the resolution is limited and this will only generate even numbers.Cinque
F
-1

How about generating bytes and converting to 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);

Sees to work for me (:

Flagellate answered 1/5, 2017 at 9:17 Comment(1)
This approach is already featured in answers from many years earlier; this answer adds nothing new.Archivist

© 2022 - 2024 — McMap. All rights reserved.