1
\$\begingroup\$

I made this class to handle any min max integer value and return a random number in the entered parameter range. I tested it to work with all combinations(I think). But is this totally wrong or written with unnecessary amounts of code? Are there obvious Java convention violations or obvious redundancy in this?

I was wondering if it was possible to do the same without instantiating Random, since I have read that object instantiation is more resource demanding than method invoking, like invoking Math.random(). I just couldn't make that work, unfortunately, as I didn't save the strange non-working code that that ended with.

I tried the solution here. However, I don't understand what the rand() part is, which is too bad since it seemed really simple with just one line of code.

abstract class RandomInteger {
     static int randomNumber;

     public static int returnRandomIntRange(int start, int end){

         if(end < start){
             throw new IllegalArgumentException("Start cannot exceed End.");
         } else if(end == 0 && start == 0){
             throw new IllegalArgumentException("Start and End can't both be 0.");
         } else if(end == start){
             throw new IllegalArgumentException("Start and End can't be the same.");

         } else if(end >= 0 && start <= 0){
             Random random=new Random();
             int range;                      
             range = end - start + 1;            
             System.out.println("aEnd > 0 && aStart < 0. 1range is: " + range);
             randomNumber=(random.nextInt(range))+(start);
             System.out.println("aEnd > 0 && aStart >= 0. invoked. 1randomNumber is: " + randomNumber);

         } else if(end > 0 && start > 0){
             Random randomGenerator=new Random();
             int range;         
             range = end - start + 1;
             System.out.println("aEnd > 0 && aStart >= 0. invoked. 2range is: " + range);
             randomNumber = randomGenerator.nextInt(range) + start;
             System.out.println("aEnd > 0 && aStart >= 0. invoked. 2randomNumber is: " + randomNumber);

         } else if(end < 0 && start < 0){
             Random randomGenerator=new Random();
             int range;
             range = (start - end -1) * -1;                         
             System.out.println("aEnd <= 0 && aStart < 0. invoked. 3range is: " + range);
             randomNumber = ((randomGenerator.nextInt(range)+ start));
             System.out.println("aEnd <= 0 && aStart < 0. invoked. 3randomNumber is: " + randomNumber);
         }

         return randomNumber;
     }

}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ The rand() is for a different programming language, C++. \$\endgroup\$
    – Nick
    Mar 13, 2013 at 22:00
  • \$\begingroup\$ stackoverflow.com/questions/2444019/… \$\endgroup\$
    – kan
    Mar 13, 2013 at 22:03
  • \$\begingroup\$ Your end == 0 && start == 0 case is included in your end == start case. \$\endgroup\$
    – luiscubal
    Mar 18, 2013 at 13:02

4 Answers 4

5
\$\begingroup\$

That does look a little confusing. The example you looked at is for C, not Java. I would do this:

int random = (int) Math.floor(Math.random() * (max - min + 1) ) + min;

It works like this: Math.random() returns a double between 0 and 1 (although never actually equal to 1). The full range of values you want is (max - min + 1) (the +1 is because you probably want max to min inclusive), so this will scale the number over the correct number of integer values. We floor it (round down) because we want an int, and finally shift it upwards by adding min to put the numbers in the correct range. We also cast to an int since we don't want it as a double.

EDIT: On further inspection, this is better; no casting and rounding of doubles:

Random rand = new Random();
int random = rand.nextInt(max - min + 1) + min;
\$\endgroup\$
7
  • 1
    \$\begingroup\$ This solution works except in the case where min = 0 and max = int.maxValue. In that case, you end up with overflow problems and you need slightly different logic. Other than that... +1 \$\endgroup\$
    – Jesse Webb
    Mar 13, 2013 at 22:06
  • \$\begingroup\$ Thanks! that seems very simple and clever solutions, Im gonna go for that! This doesn't take into account if max being less than min, but that could perhaps just be done by using an if check and throwing and exception? \$\endgroup\$
    – user1949930
    Mar 13, 2013 at 22:16
  • \$\begingroup\$ @jazzbassrob in your edit you instantiate Random, will it we more perfomance cost? \$\endgroup\$
    – user1949930
    Mar 13, 2013 at 22:20
  • \$\begingroup\$ I should have written in first post that it's for shooting rectangles around the screen making them land at random x,y offset ranges. Using Random object should only be instantiated once, but maybe Random object could be created once in the main update method and be passed as parameter into the random-method every time a new random number is needed \$\endgroup\$
    – user1949930
    Mar 13, 2013 at 22:32
  • 2
    \$\begingroup\$ It is important to reuse the Random object because when it is created it uses the current time as the seed. If you create two Random objects within a millisecond (or 10ms, depending on the clock resolution) they will produce the same "random" values. \$\endgroup\$
    – Joni
    Mar 14, 2013 at 6:06
0
\$\begingroup\$

You can try something like the following, which will also work if start is less than end or when either number is negative:

abstract class RandomInteger {
    public static int returnRandomIntRange(int start, int end) {
        int range = Math.abs(end - start);
        if (range == 0) {
            return start; // Or throw your illegal argument exception
        }
        return Math.min(start, end) + new Random().nextInt(range + 1);
    }
}
\$\endgroup\$
0
0
\$\begingroup\$

Instead of

if(end < start){
  throw new IllegalArgumentException("Start cannot exceed End.");

I would

if(end < start){
  return returnRandomIntRange(end, start);

This would make your method more robust.

\$\endgroup\$
1
  • \$\begingroup\$ That kind of robustness might be undesirable. Frankly, I consider the IllegalArgumentException solution to be perfectly acceptable. \$\endgroup\$
    – luiscubal
    Mar 18, 2013 at 13:00
0
\$\begingroup\$

BTW Is it true that not using a Random object improves perfomance?

No (not in your case). Math.random() just creates an instance of Random:

//from java.lang.Math
public static double random() {
    Random rnd = randomNumberGenerator;
    if (rnd == null) rnd = initRNG();
    return rnd.nextDouble();
}

private static synchronized Random initRNG() {
    Random rnd = randomNumberGenerator;
    return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
}

If you create some random numbers, just create a ThreadLocalRandom instance and use it. If you have speed problems, I am quite sure, it is not related to the random number generator. If you think so, profile it.

A good way to implement the required functionality is already shown by jazzbassrob.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.