0

I'm trying to generate a random floating point number between but not including it's lower and upper bounds (lower, upper). I've seen a lot of questions about generating a number from, and including it's lower bound up to, but not including it's upper bound [lower, upper), but that's not what I'm after.

I've come up with two "solutions" to the problem, but am not really satisfied by either.

First "solution"

double myvalue;
do { myvalue = myrandom.nextDouble() * (upper - lower) + lower; } while (myvalue == lower);

While this will almost everytime give a valid result on the first try it seems inconsistent and clunky, and on the off-chance that the RNG returns zero a lot, it's inefficient as well.

Second "solution"

double myvalue = 
0.5 * (1.0 + myrandom.nextDouble() - myrandom.nextDouble()) * (upper - lower) + lower;

While this will guarantee me a valid number on the first try, I don't believe the distribution is uniform in this case.

Thanks

  • 3
    I don't think you mean to have `while (myvalue != lower)`. Unless you want `myvalue` to end up equal to `lower`. – khelwood Sep 19 '16 at 14:10
  • 1
    You should go with the first approach. In practice it will work very well. The general technique to discard undesired output from an RNG is often used. – Marko Topolnik Sep 19 '16 at 14:25

2 Answers2

1

Your first code is quite correct.

double myvalue;
do { 
    myvalue = myrandom.nextDouble() * (upper - lower) + lower; 
} while (myvalue == lower);  // Replace != with ==

Simply replace != with ==. It is not true that this is not efficient.


A look to efficiency of the code.

Taking a look on the code of nextDouble you can see that it is calculated generating a random long value.

It means that basically you will have 1 possibility to repeat the loop over 2 * 9,223,372,036,854,775,807 (the range of long values minus 1).

Additional Note: because you are using double and not a BigDecimal you can obtain a myvalue that is close to the lower bound, but lower than it, so it is better to change the code to exclude also values lower than lower. It doesn't change the efficiency of your code.

double myvalue;
do { 
    myvalue = myrandom.nextDouble() * (upper - lower) + lower; 
} while (myvalue <= lower);  // Replace != with <=
Davide Lorenzo MARINO
  • 26,420
  • 4
  • 39
  • 56
  • OP never claimed it was incorrect, but that it was _clunky_ because it has a loop which has no strict upper bound on the number of iterations. – Marko Topolnik Sep 19 '16 at 14:20
  • @MarkoTopolnik you are right is was not saing that it was uncorrect. But it was. You need to exit when you find any value that is different from lower. And you need to continue to search a value if myvalue is equals to lower. So the condition must be changed. – Davide Lorenzo MARINO Sep 19 '16 at 14:23
  • Sure, but that's not OP's question, and it's already covered in the comment under the question. – Marko Topolnik Sep 19 '16 at 14:24
  • @MarkoTopolnik replacing != with == not only change the code from not working to a working code, but also change it from an inefficient code to a very efficient code. Infact you will never (or close to never) retry the while. Instead if you have != you will ever retry the while loop until you find exactly the lower bound (many billions of times to return an invalid value) – Davide Lorenzo MARINO Sep 19 '16 at 14:27
  • You think it matters that the incorrect code was also inefficient at producing its incorrect result? :) – Marko Topolnik Sep 19 '16 at 14:30
  • @MarkoTopolnik I added some efficiency note on the answer. Yes the probability is exactly the opposed if the sign of the test is incorrect. – Davide Lorenzo MARINO Sep 19 '16 at 14:45
  • Thank you for your answer! This helped me alot to achieve more insight into how to deal with random numbers. When you say that this expression can return values lower than `lower`, does this also mean that it can return values equal to or greater than `upper`? And what does `BigDecimal` do different to avoid this problem? – Fredrik Bakke Sep 19 '16 at 17:32
  • In the special case of a very narrow range, with only a few doubles in it, list the acceptable doubles and use a random int as index into the list. That is the only case in which a correctly functioning random number generator will hit the lower bound frequently. – Patricia Shanahan Sep 19 '16 at 18:16
-1

Try ThreadLocalRandom.current().nextDouble(origin + 1, bound). Per the javadoc, min is inclusive and max is exclusive by default

jseashell
  • 745
  • 9
  • 19