Share via


Random Int64\Long Generation Within Range

Question

Thursday, March 27, 2008 1:20 PM

What is the best way to generate a "random" long value?

 

e.g

Code Snippet

long value = RandomNumber.NextLong(-1231312313123, 1314235234124)

 

 

 

Thanks,

Ben.

All replies (7)

Thursday, March 27, 2008 11:16 PM ✅Answered

Code Snippet

Random r  = new Random();

long value = (long)((r.NextDouble() * 2.0 - 1.0) * long.MaxValue);

That should span the entire range since (r.NextDouble() * 2.0 - 1.0) will give you a random double in the range [ -1.0, 1.0 ). Then multiplying by the long max will span the entire + / - range.


Thursday, March 27, 2008 11:38 PM ✅Answered

The system random number generator should never be relied upon for any sort of security or statistical randomness (if used for numerical simulations).  Using the RNGCryptoServiceProvider, however, can be counted on.

Code Snippet

public class RandomGenerator
{
    RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();

    public RandomGenerator() { }

    public int GetNextInt32()
    { return GetNextInt32(int.MinValue, int.MaxValue); }

    public int GetNextInt32(int low, int hi)
    { return (int)GetNextInt64(low, hi); }

    public long GetNextInt64()
    { return GetNextInt64(long.MinValue, long.MaxValue); }

    public long GetNextInt64(long low, long hi)
    {
        if (low >= hi)
            throw new ArgumentException("low must be < hi");
        byte[] buf = new byte[8];
        double num;

        //Generate a random double
        _rng.GetBytes(buf);
        num = Math.Abs(BitConverter.ToDouble(buf, 0));

        //We only use the decimal portion
        num = num - Math.Truncate(num);

        //Return a number within range
        return (long)(num * ((double)hi - (double)low) + low);
    }

    public double GetNextDouble()
    { return GetNextDouble(double.MinValue, double.MaxValue); }

    public double GetNextDouble(double low, double hi)
    {
        if (low >= hi)
            throw new ArgumentException("low must be < hi");
        byte[] buf = new byte[8];
        double num;

        //Generate a random double
        _rng.GetBytes(buf);
        num = Math.Abs(BitConverter.ToDouble(buf, 0));

        //We only use the decimal portion
        num = num - Math.Truncate(num);

        //Return a number within range
        return num * (hi - low) + low;
    }
}

 


Thursday, March 27, 2008 1:54 PM

Quick thought:

 

Code Snippet

Random r  = new Random();

long value = (r.NextDouble - 0.5d) * long.MaxValue;

 

 

Will only give give you half the long range, though...


Monday, August 17, 2009 9:20 AM

I realise this thread is over a year old. However, I just thought I would post a thought just in case anyone else comes across this.  While Chuck the Code Monkey is correct, the crypto random generator is not correct.  The GetNextInt64(long,long) method has a bug.  The return statement at the end is casting "hi" and "low" to a double, which will result in something like 0.0 || 1 in all cases I believe.  It should cast to a long/Int64.

Hope this helps.


Tuesday, August 18, 2009 7:35 PM

There are all kinds of problems with this conversion technique.  Truncating a double value far out of the range of the long results in a 0.  Not sure what is going on with the "range fix":  return num * (hi - low) + low;, but I have not been able to figure out how this equation is supposed to take any (and often very large) number and make it fit between an upperbound/lowerbound.

say we have num = 100, hi = 5, low = 0...

100 * (5 - 0) + 0....100 * (5) + 0....500 + 0...returns 500.

Its a bad idea to take all these primitives and convert them to smaller primitives.  There's a reason explicit conversions exist in C#.  I'm working on a random generator that uses RNGCryptoServiceProvider, but I am not sure its going to be better than the Random class (which essentially makes it worthless).

If anyone has a good Randomizer that does not require Service oriented architecture please share some code snippets.


おろ?


Monday, January 4, 2010 4:59 PM | 1 vote

Code Snippet

Random r  = new Random();

long value = (long)((r.NextDouble() * 2.0 - 1.0) * long.MaxValue);

 

That should span the entire range since (r.NextDouble() * 2.0 - 1.0) will give you a random double in the range [ -1.0, 1.0 ). Then multiplying by the long max will span the entire + / - range.

Actually this isn't precise since the number of significant digits in the long data type is bigger than it is in the double data type. See the following link for correct ways to do it: http://stackoverflow.com/questions/2000311/generation-of-pseudo-random-constrained-values-of-uint64-and-decimal


Wednesday, March 23, 2011 3:01 PM

I have tried your code (as I had a similar problem to solve) and I noted the following:

In the GetNextInt64() method you are better off with using BitConverter.ToLong() as otherwise you will get nasty behaviour when getting a new long.