33

How can I generate random Int64 and UInt64 values using the Random class in C#?

Noldorin
  • 144,213
  • 56
  • 264
  • 302
SyncMaster
  • 9,754
  • 34
  • 94
  • 137

10 Answers10

76

This should do the trick. (It's an extension method so that you can call it just as you call the normal Next or NextDouble methods on a Random object).

public static Int64 NextInt64(this Random rnd)
{
    var buffer = new byte[sizeof(Int64)];
    rnd.NextBytes(buffer);
    return BitConverter.ToInt64(buffer, 0);
}

Just replace Int64 with UInt64 everywhere if you want unsigned integers instead and all should work fine.

Note: Since no context was provided regarding security or the desired randomness of the generated numbers (in fact the OP specifically mentioned the Random class), my example simply deals with the Random class, which is the preferred solution when randomness (often quantified as information entropy) is not an issue. As a matter of interest, see the other answers that mention RNGCryptoServiceProvider (the RNG provided in the System.Security namespace), which can be used almost identically.

Noctis
  • 11,507
  • 3
  • 43
  • 82
Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 1
    +1 for giving the OP what they asked for as well as mentioning the limitations of using Random and offering an alternative if the limitations of Random are too restrictive for the intended use. – JeffH Mar 26 '09 at 15:01
  • 5
    Note that this approach also returns negative numbers and Int64.MaxValue, while System.Random.Next() is constrained to positive numbers including 0 but without Int32.MaxValue. – Christoph Rüegg Apr 18 '09 at 09:50
  • @Christoph: Yeah, well observed. You could however modify my method quite easily to only produce positive values by ignoring the MSB (most significant bit) of the buffer. – Noldorin Apr 18 '09 at 11:40
  • I tried implementing this solution but found that the results weren't satisfactorily random. After generating thousands of numbers, I found that the vast majority of the numbers had 19 digits, the occasional number had 18 digits, and the very rare number had 17 digits. Out of the thousands of numbers I generated, I never saw any number with 16 digits or less. How could this solution be modified to fix this? – kd7iwp Sep 12 '12 at 22:45
  • 1
    @kd7iwp: I fear you have a slightly befuddled perception of "random" here. The key here is the distribution of the generated values. Are the integers distributed uniformly? Yes, of course, since their bits are independent and uniform random variables. Now observe that there are ~10 times as many numbers with (n + 1) digits as there are with n digits, and it should be clear enough to you. – Noldorin Sep 13 '12 at 00:43
  • @Noldorin: How can we ignore MSB? Can you share? – Görkem Öğüt Jan 29 '13 at 22:49
29

Use Random.NextBytes() and BitConverter.ToInt64 / BitConverter.ToUInt64.

// Assume rng refers to an instance of System.Random
byte[] bytes = new byte[8];
rng.NextBytes(bytes);
long int64 = BitConverter.ToInt64(bytes, 0);
ulong uint64 = BitConverter.ToUInt64(bytes, 0);

Note that using Random.Next() twice, shifting one value and then ORing/adding doesn't work. Random.Next() only produces non-negative integers, i.e. it generates 31 bits, not 32, so the result of two calls only produces 62 random bits instead of the 64 bits required to cover the complete range of Int64/UInt64. (Guffa's answer shows how to do it with three calls to Random.Next() though.)

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Oh, good catch (comment) - I'm deleting mine, as the BitConverter etc is already well covered... – Marc Gravell Mar 24 '09 at 13:35
  • Okay - I put that in my answer rather than just a comment so that it would be more visible. I'm going to leave it in now anyway as a warning for the future (as otherwise it's an obvious alternative). – Jon Skeet Mar 24 '09 at 13:37
  • Due to the fact that majority of lcm PRNG are less random in the low order bits, generating 2 numbers and joining them together may introduce subtle biases... – Mitch Wheat Mar 24 '09 at 14:21
  • @JonSkeet `Random` values are distributed uniformly. I'm not sure that we'll get uniformly disrtibuted value with following method, especially if we are dropping MSB. And we also can get a value from 2 randoms, if the second call will be `random.Next(int.MinValue, int.MaxValue)` so all bytes will be filled. – Alex Zhukovskiy Feb 08 '16 at 07:03
  • @AlexZhukovskiy: With which method? And where do you believe I'm dropping an MSB? – Jon Skeet Feb 08 '16 at 07:06
  • @JonSkeet standard `Random` generates positive-only numbers by default. See @Noldorin's comments – Alex Zhukovskiy Feb 08 '16 at 07:07
  • @AlexZhukovskiy: I'm still not sure what code you're referring to. Bear in mind that my code doesn't ask `Random` to produce full integers - just bytes. I'm then using `BitConverter` to convert those bytes. Both the `int64` and `uint64` variables in my answer could have *any* value within their respective ranges. Are you suggesting that `NextBytes` never populates the MSB of any array element? If so, that's just wrong. – Jon Skeet Feb 08 '16 at 07:09
  • @JonSkeet they are, but there is a big question if there are disributed correctly (according to central limit theorem) – Alex Zhukovskiy Feb 08 '16 at 07:11
  • @AlexZhukovskiy: To be honest, there's no question in my mind. We're taking a random sequence of bits, and converting them into integers in an obvious way. Every possible value has the same chance of occurring. I don't see any evidence that there's a problem here. If you think there is, I suggest you give a more concrete argument. – Jon Skeet Feb 08 '16 at 07:12
  • With those bytes we get a distribution `Z = X0 + X1*256 + X2*256*256 + ...` with independed random generated `X0`, `X1`... `X7`, so in general case `Z` won't be a uniformly distributed variable. `Z` can be any value within the range, but not all values are equiprobable. – Alex Zhukovskiy Feb 08 '16 at 07:17
  • @AlexZhukovskiy: Yes, they are. Every value is the result of exactly one 64-bit bit pattern, right? So are you suggesting that the bit patterns themselves aren't uniformly distributed? Which bit pattern do you think is more likely than any other bit pattern? Each bit within `bytes` is uniformly distributed, independently of the other bits... so every bit pattern is as likely as every other. If we were converting the values to `double`, that would be a different matter. – Jon Skeet Feb 08 '16 at 07:20
  • @JonSkeet well, I agree. It will be exactly uniformly distributed. CLT is not applicable here because there is no intersections between bytes (it's obvious for us, but isn't for mathematics), so `Z = X0 + X1*256 + X2*256*256 + ...` is a bit incorrect here. Finally, we could generate a value with 4 (or 3 for positive-only) `rand.Next()` calls, by just specifying bottom bound `int.MaxValue`. It's better than 8 calls (because `Random.NextBytes` calls `InternalSample` for each byte) – Alex Zhukovskiy Feb 08 '16 at 08:17
  • 1
    @AlexZhukovskiy: That's changing your objection entirely, and is based on an implementation detail. You can do it with 3 calls to `Random.Next` even if you want the full range, given that each call generates 31 bits of random data and we only need 64 in total. – Jon Skeet Feb 08 '16 at 08:26
10

Here you go, this uses the crytpo services (not the Random class), which is (theoretically) a better RNG then the Random class. You could easily make this an extension of Random or make your own Random class where the RNGCryptoServiceProvider is a class-level object.

using System.Security.Cryptography;
public static Int64 NextInt64()
{
   var bytes = new byte[sizeof(Int64)];    
   RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
   Gen.GetBytes(bytes);    
   return BitConverter.ToInt64(bytes , 0);        
}
Ðаn
  • 10,934
  • 11
  • 59
  • 95
Muad'Dib
  • 28,542
  • 5
  • 55
  • 68
  • This is definitely worthwhile noting, although judging by the question the OP doesn't seem to care too greatly about the randomness of the generated numbers. Also it's important to realise that RNGCryptoServiceProvider is *much* slower than Random (though performance may or may not matter here). – Noldorin Mar 24 '09 at 16:18
6

You can use bit shift to put together a 64 bit random number from 31 bit random numbers, but you have to use three 31 bit numbers to get enough bits:

long r = rnd.Next();
r <<= 31;
r |= rnd.Next();
r <<= 31;
r |= rnd.Next();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
5

I always use this to get my random seed (error checking removed for brevity):

m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
Random rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));

random.org uses atmospheric noise to generate the randomness and is apparently used for lotteries and such.

sipsorcery
  • 30,273
  • 24
  • 104
  • 155
3

You don't say how you're going to use these random numbers...keep in mind that values returned by Random are not "cryptographically secure" and they shouldn't be used for things involving (big) secrets or (lots of) money.

Ðаn
  • 10,934
  • 11
  • 59
  • 95
  • -1 for not mentioning the .Net Crypto RNG. http://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.aspx – Samuel Mar 24 '09 at 13:45
  • Why is that relevant? Dan alludes to the fact that a PC can't generate a cryptographically secure random number. The RNGCryptoServiceProvider class doesn't fix that. – sipsorcery Mar 24 '09 at 13:52
  • No, he said the Random class can't do it, he said nothing about computers not being able to. – Samuel Mar 24 '09 at 13:54
  • 1
    And RNGCryptoServiceProvider generates cryptographically secure random numbers and satisfies that condition of his answer. – Samuel Mar 24 '09 at 13:56
  • 1
    John Von Neumann: "Anyone who considers arithmetic methods of producing random digits is, of course, in a state of sin." – sipsorcery Mar 24 '09 at 14:06
  • While he makes a good point, if he had just spent a minute more he would have found RNGCryptoServiceProvider and his answer would be much more valuable. – Samuel Mar 24 '09 at 14:07
  • 4
    The asker did not mention he required a secure random number, but it is nice you pointed out that the Random class does not produce secure numbers, but you really should mention an alternative instead of leaving a dead end. – Samuel Mar 24 '09 at 15:01
2

You could create a byte array, fill it with random data and then convert it to long (Int64) or ulong (UInt64).

byte[] buffer = new byte[sizeof(Int64)];
Random random = new Random();

random.NextBytes(buffer);
long signed = BitConverter.ToInt64(buffer, 0);

random.NextBytes(buffer);
long unsigned = BitConverter.ToUInt64(buffer, 0);
Ðаn
  • 10,934
  • 11
  • 59
  • 95
Samuel
  • 37,778
  • 11
  • 85
  • 87
0

Another answer with RNGCryptoServiceProvider instead of Random. Here you can see how to remove the MSB so the result is always positive.

public static Int64 NextInt64()
{
    var buffer = new byte[8];
    new RNGCryptoServiceProvider().GetBytes(buffer);
    return BitConverter.ToInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF;
}
sventevit
  • 4,766
  • 10
  • 57
  • 89
0

As of .NET 6, the Random class has a method for generating a random long.

var r = new Random();
long randomLong = r.NextInt64();
Fidel
  • 7,027
  • 11
  • 57
  • 81
-3
Random r=new Random();
int j=r.next(1,23);
Console.WriteLine(j);
thkala
  • 84,049
  • 23
  • 157
  • 201
  • the random class is used to randomly select the values.random class give a well environment to the user to do so –  Mar 27 '09 at 17:32