-4

How do I safely generate a random integer value in a specific range?

I know many people have asked this before, this post for example, but the method doesn't seem to be safe. Let me explain:

The 'Math' library has Math.random() which generates a random value in the range [0, 1). Using that, one can construct an algorithm like

int randomInteger = Math.floor(Math.random() * (Integer.MAX_VALUE - Integer.MIN_VALUE + 1) + Integer.MIN_VALUE)

to generate a random number between Integer.MAX_VALUE and Integer.MIN_VALUE. However, Integer.MAX_VALUE - Integer.MIN_VALUE will overflow.

The goal is not to merely generate random numbers but to generate them evenly, meaning 1 has the same probability to appear as Integer.MAX_VALUE. I know there are work-arounds to this, such as casting large values to long but then the problem again is how to generate a long integer value from Long.MIN_VALUE to Long.MAX_VALUE.

I'm also not sure about other pre-written algorithms as they can overflow too and cause the probability distribution to change. So my question is whether there is a mathematical equation that uses only integers (no casting to long anywhere) and Math.random() to generate random numbers from Integer.MIN_VALUE to Integer.MAX_VALUE. Or if anyone know any random generators that don't get overflow internally?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
157 239n
  • 349
  • 3
  • 15
  • The answers to the question you yourself linked address this question as well, including, some of them, the case where the upper bound of the desired range is `Integer.MAX_VALUE`. – John Bollinger Jun 01 '18 at 16:14
  • Do you suggest that there are fewer `double` numbers between 0 and 1 than `long` numbers in their range? Indeed, they both use 64 bits, but the float uses two sign bits (in mantissa and exponent), and they both would be constant (0 and 1), so if you extend the 0..1 `double` range to the `long` range by multiplication, you will have gaps. Your best bet is likely to find an integer-only implementation with characteristics that you need, and either use its implementation or implement it yourself. – 9000 Jun 01 '18 at 16:16
  • It has nothing to do with number of bits in the double. – mentallurg Jun 01 '18 at 16:28

3 Answers3

3

The 'Math' library have Math.random() which generates a random value in [0, 1) range.

So don't use Math.random() - use this:

Random r = new Random();
int i = r.nextInt();

The docs for nextInt say:

nextInt() - Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. All 2^32 possible int values are produced with (approximately) equal probability.

It appears I misread the question slightly, and you need long not int - luckily the contract is the same.

long l = r.nextLong()

This will quite literally take two ints and jam them together to make a long.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • Isn't the range of `int` much smaller that the range of `long`, asked for by the question? – 9000 Jun 01 '18 at 16:26
  • You haven't read the question. The number are needed in the particular range, not just any integer. – mentallurg Jun 01 '18 at 16:27
  • 1
    @9000 Yeah, oops - it appeared he asked for `Integer.MIN_VALUE` to `Integer.MAX_VALUE` - but either way, it's pretty simple to just use `nextLong` instead which has the same contract. – corsiKa Jun 01 '18 at 16:47
  • @mentallurg I did read the question, I just used `int` instead of `long` - OP wants them with equal probability over the entire range of the datatype, not just a particular range. Literally, he needs any long, and I used any integer. Still, this pointed him in the direction he needed. – corsiKa Jun 01 '18 at 16:48
1

Still better might be to use java.security.SecureRandom which is a cryptographically strong random number generator (RNG).

Salix alba
  • 7,536
  • 2
  • 32
  • 38
0

Random x = new Random(1000); // code running and generate values 1000 int i = x.nextInt();