56

I'm having trouble with Javas Random class, if i do this:

Random rng = new Random(seed) // seed == 29 in this example

String ss = "";
        for(int i = 0; i < 10; i++)
        {
            int s = rng.nextInt();
            ss += Integer.toString(s);
            ss +="\n";
        }

This is what i get back:

-1169335537
-2076183625
1478047223
1914482305
722089687
2094672350
-1234724057
-1614953544
-321574001
1000360613

From what I have read this should only be returning positive numbers for a start?

This may be a bit far fetched but it couldnt have anything to do with running a 64 bit machine on Windows 7 64 bit?

Any help at all would be awesome need to get this finished for an assignment hand in today!

2
  • only believe what you read in the javadocs. And (of course) read the javadocs. Commented Apr 29, 2011 at 4:07
  • 4
    Note Math.abs wont work one time in 2<sup>32</sup>. (And good luck testing that. Hint: Don't use a static mutable object.) Commented Apr 29, 2011 at 9:53

9 Answers 9

85

From the Java docs for nextInt():

All 232 possible int values are produced with (approximately) equal probability.

One approach is to use the following transform:

s =  rng.nextInt() & Integer.MAX_VALUE; // zero out the sign bit

The reason something like this is needed (as opposed to using absolute value or negation) is that Integer.MIN_VALUE is too large in absolute value to be turned into a positive integer. That is, due to overflow, Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE and Integer.MIN_VALUE == -Integer.MIN_VALUE. The above transformation preserves the approximately uniform distribution property: if you wrote a generate-and-test loop that just threw away Integer.MIN_VALUE and returned the absolute value of everything else, then the positive integers would be twice as likely as zero. By mapping Integer.MIN_VALUE to zero, that brings the probability of zero into line with the positive integers.

Here is another approach, which may actually be a tiny bit faster (although I haven't benchmarked it):

int s = rng.next(Integer.SIZE - 1); // Integer.SIZE == 32

This will generate an integer with 31 random low-order bits (and 0 as the 32nd bit, guaranteeing a non-negative value). However (as pointed out in the comment by jjb), since next(int) is a protected method of Random, you'll have to subclass Random to expose the method (or to provide a suitable proxy for the method):

public class MyRandom extends Random {
    public MyRandom() {}
    public MyRandom(int seed) { super(seed); }

    public int nextNonNegative() {
        return next(Integer.SIZE - 1);
    }
}

Another approach is to use a ByteBuffer that wraps a 4-byte array. You can then generate a random four bytes (by calling nextBytes(byte[])), zero out the sign bit, and then read the value as an int. I don't believe this offers any advantage over the above, but I thought I'd just throw it out there. It's basically the same as my first solution (that masks with Integer.MAX_VALUE).

In an earlier version of this answer, I suggested using:

int s = rng.nextInt(Integer.MAX_VALUE);

However, according to the docs this will generate integers in the range 0 (inclusive) to Integer.MAX_VALUE (exclusive). In other words, it won't generate the value Integer.MAX_VALUE. In addition, it turns out that next(int) is always going to be faster than nextInt(int).

Sign up to request clarification or add additional context in comments.

9 Comments

Random.next() is protected, though, so you can't call it directly. You can subclass Random and expose something like nextPositiveInt() which returns next(31) pretty easily.
Integer.SIZE - 1 would be slightly nicer.
@CiroSantilli六四事件法轮功纳米比亚胡海峰 - Yes, that would make it clearer where the value came from. I'll update my answer accordingly.
Isn't (-1) >>> 1 just Integer.MAX_VALUE? I could just use rng.nextInt() & Integer.MAX_VALUE, or am I missing something?
@aldok - Correct. As I explained in my answer, this is a good thing because it will mean that 0 will occur (roughly) as often as any positive integer value. (This is true whether using secure random or java.util.Random.)
|
20

Since there is an equal chance of positive or negative numbers why not just:

Math.abs(rand.nextInt())

Nice and easy!

2 Comments

This won't work. From the docs for Math.abs(int): "Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative."
Then they should have called the method Math.absExceptIfTheArgumentIsEqualToIntegerMinValueInWhichCaseGoodBloodyLuckToYou(int);
11

Negative numbers are allowed - maybe you've read of the similar Random method nextInt( int ) which does limit the returned values to be zero or greater.

1 Comment

As mentioned by Ted, nextInt(Integer.MAXVALUE) leaves out Integer.MAXVALUE, so it is somewhat as good as the obvious Math.abs which gets one value wrong (Integer.MAXVALUE).
1

Check out the documentation for java.util.Random:

http://download.oracle.com/javase/6/docs/api/java/util/Random.html

Are you you trying to get random numbers from 0 to 28? If so, you need to use nextInt(int) as mentioned previously. The seed has no bearing on the range of possible outputs or their relative likelihoods.

Comments

0

Per the documentation http://download.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt():

Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. The general contract of nextInt is that one int value is pseudorandomly generated and returned. All 2^32 possible int values are produced with (approximately) equal probability.

Just multiply by -1 if the value is negative

1 Comment

Multiplying by -1 is not a good idea. First, it doesn't work: the negation of Integer.MIN_VALUE is Integer.MIN_VALUE again (due to overflow), so you can't get rid of all negative numbers that way. Even if it did work, the result would be a non-uniform distribution: zero would have half the probability of any positive integer.
0

You also can use Math.random() which returns values between 0 and 1

Comments

0
int randomNumber = new Random().newInt(10);

This will return a random number between 0 and 9.

Comments

0

If you happen to work with numbers that have the possibility of having a negative value you can turn it into a positive value using a conditional declaration automatically by multiplying the value to a negative one. You can also turn a positive into a negative value using this same method.

The examples are below.

int a = -5;
a = a < 0? ( a == -2147483648? 0 : -a ) 
           : a;

int b = -2147483648;
b = b < 0? ( b == -2147483648? 0 : -b ) 
           : b;

int c = 12345;
c = c < 0? ( c == -2147483648? 0 : -c ) 
           : c;

5 Comments

Unfortunately, this doesn't work for Integer.MIN_VALUE because Integer.MIN_VALUE == -Integer.MIN_VALUE due to overflow.
To fix the integer min value problem or max value problem, if you do not mind the number being one number off you can do this, b = b < 0? b == Integer.MIN_VALUE? (b + 1) * -1 : b * -1 : b;
If you need the number to be precise, you need a second line to correctly correct the overflow problem. The solution above is only for when you working with a random number and do not mind if the number can be one digit different.
For OP's case (where 0 is also an allowed value along with all positive integers) the best way to deal with this is to map Integer.MIN_VALUE to 0 and to negate all other negative numbers. That way, all non-negative numbers have equal probability of being generated (assuming the underlying generator generates all integers with equal probability). Every positive value can be generated in two ways: either by being produced directly by the PRNG or as the negation of a negative number other than Integer.MIN_VALUE. Zero can also be generated two ways: directly and from Integer.MIN_VALUE.
I do agree with Ted Hopp comment from above, instead of (b + 1) * -1 just change that to 0.
0
int s = rng.nextInt(bound); //bound 29 in this case

This will have a bound of 0 to 29.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.