3

Creating a random number generator in Java - looking at num1 and num2, in which instances would I use either of these methods for creating a random number between 1 and 8? Is one more efficient than the other, any other benefits?

import java.util.*;

public class Chpt3 {
  public static void main(String[] args) {
    Random rand = new Random();
    int num1 = Math.abs(rand.nextInt()) % 8 + 1;
    int num2 = rand.nextInt(8) + 1;
    System.out.println(num1);
    System.out.println(num2);

  }
}
RancheroBeans
  • 500
  • 1
  • 6
  • 15
  • Since you want an Integer in range [1, 9], you should use rand.nextInt since it better describes your intent. Unless you know otherwise, internal implementations of more specific functions tend to be better than composing them out of existing functions. That said, Java is a compiled language and takes advantage of static analysis to make much of these decisions irrelevant by canonicalizing the two patterns Math.abs(Math.random), and random.nextInt into pretty much the same expression. – Dmytro Aug 27 '16 at 00:40

3 Answers3

6

nextInt(n) returns between 0 and n-1.

So to get between 1 to 8,

int num2 = rand.nextInt(8) + 1;

Which means your second one is the one you need.


Update:

Math.abs(Integer.MIN_VALUE) returns negative value.

According to this answer on SO:

Integer.MIN_VALUE is -2147483648, but the highest value a 32 bit integer can contain is +2147483647. Attempting to represent +2147483648 in a 32 bit int will effectively "roll over" to -2147483648. This is because, when using signed integers, the two's complement binary representations of +2147483648 and -2147483648 are identical. This is not a problem, however, as +2147483648 is considered out of range.

For a little more reading on this matter, you might want to check out the Wikipedia article on Two's complement.

First method just contains a rare corner case. That's why it's better to use second one as it's safe.

Community
  • 1
  • 1
  • Can you add an explanation as you why not the first option which appears to do the same thing? – Peter Lawrey Aug 27 '16 at 00:10
  • 2
    He didn't say `Math.abs(Integer.MIN_VALUE)` returning negative is a bug. He said `Math.abs(rand.nextInt()) % 8 + 1` has a bug because `Math.abs(Integer.MIN_VALUE)` can (correctly) return negative. – shmosel Aug 27 '16 at 00:25
  • @shmosel my bad. I'm not a native english speaker. –  Aug 27 '16 at 00:30
5

Math.abs(rand.nextInt()) % 8 + 1;

This has a subtle bug. Math.abs(Integer.MIN_VALUE) returns MIN_VALUE which is a negative number. A simpler solution is

(rand.nextInt() & 7) + 1;

This will always be non-negative and be slightly faster.

rand.nextInt(8) + 1

This is both faster, but more importantly, clearer as to what you are trying to achieve. For the later reason, rather than speed alone, it is the better choice.

Note: You could use abs if you really wanted to like this. However this is not as clean as the nextInt call.

Math.abs(rand.nextInt() % 8) + 1;
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

Here is the problem:

int num1 = Math.abs(rand.nextInt()) % 8 + 1;

means that you will first choose a number from "All 2^32 possible int values are produced with (approximately) equal probability" and then afterwards you will mod the answer by 8. Since, we are using Math.abs(), one problem is that it might return a negative number.

 int num2 = rand.nextInt(8) + 1;

However, this version will not return a negative number and will return a number from 0 to 8.

Both code are suitable in achieving what you want to do. However, the second line of code will be better for memory, in the first version the worst case is that you have to remember a number 2^32. However, you do not have to for the second version. Another thing is that because we have to use less method and less calculation overall the 2nd method will be a lot faster. All in all, both methods work but the 2nd version is the best version since it takes up less memory and is faster overall.