0

How do I implement a function getRandomDouble(min,max) which is able to handle +-Double.MAX_VALUEas parameter?

Online Research:

Most answers to this question are:

public Double getRandomDouble(double min, double max) {
    return min + (max-min)*Random.nextDouble(); 
}

This works fine if min and max are not +-Double.MAX_VALUE. If so, max-min is out of range or infinity. Changing the parameters to BigDecimal solves this issue, but the result is always a double with 50 zeros and no decimals. This is the result of a very large number (2*MAX_VALUE) multiplied a double between [0,1] with only a view decimals.

So, I found a solution for +-MAX_VALUE like this:

public double getRandomDouble() {
    while(true) {
        double d = Double.longBitsToDouble(Random.nextLong());
        if (d < Double.POSITIVE_INFINITY && d > Double.NEGATIVE_INFINITY)
            return d;
    }
}

This works fine, but does not consider other bounds.

How can I combine both approaches to get random double in a given range that's maybe +-MAX_VALUE?

Thanthla
  • 526
  • 1
  • 8
  • 29
  • 5
    Genuine question: what on earth are you doing where it is important that the input values straddle the very edges of the Double type? – Mike 'Pomax' Kamermans Aug 15 '19 at 19:45
  • Neuro-quantum physics... just kidding. In our application the default values are `+-MAX_VALUE` if no bounds have been specified. And NO, changing the default values is not an option. This may solve my problem temporary, but I would like to have a solution which still works if in one month a colleague switches back the settings :-) – Thanthla Aug 15 '19 at 19:52
  • 1
    That doesn't explain what these numbers are used for, and so doesn't explain why you need Double's full fidelity when typically Math.random() yields a number between 0 and 1 that is already vastly higher fidelity than you can invent use cases to toggle. Wanting reliable RNG over the full Double range can make sense, but _almost never does_ so anyone who's ever had to maintain code will probably want to know why you need these rather than writing overly inefficient code for dealing with the edge case. – Mike 'Pomax' Kamermans Aug 15 '19 at 20:04

2 Answers2

0

If it's not working only with the max values, I think I have a solution.

Mathematically it should be the same:

You produce 2 random numbers and sum them up. Each number should be between -maxValue / 2 and +maxValue / 2. That way the sum will be a random number between -maxValue and +maxValue.

public Double getRandomDouble(double min, double max) {
    double halfMin = min/2;
    double halfMax = max/2;
    double sum = halfMin + (halfMax-halfMin)*Random.nextDouble(); 
    return sum + (halfMin + (halfMax-halfMin)*Random.nextDouble());
}
Omri Attiya
  • 3,917
  • 3
  • 19
  • 35
  • Does this approach result in a bias towards the "middle"? Sounds like the board game "Catan". – Progman Aug 15 '19 at 20:06
  • This solves has the same issues like the simple one. It can get an overflow (result > MAX_VALUE) and will have also always 50 zeros and no decimals. Ok, maybe 49 zeros because of the /2. – Thanthla Aug 15 '19 at 20:09
  • @Progman No I don't think so, because if it's a random number you can get both numbers as `-maxValue/2` and the sum of them would be `-maxValue`. Same goes for `+maxValue` and every other value between `-maxValue` and `+maxValue` – Omri Attiya Aug 15 '19 at 20:09
  • 1
    @Thanthla it won't get overflow because in this case `halfMax-halfMin` will be `+maxValue` (no overflow), and result can be like you described in the question – Omri Attiya Aug 15 '19 at 20:11
  • @Thanthla and in this solution you don't need to use `BigDecimal` so you don't have to deal with the 50 zeros – Omri Attiya Aug 15 '19 at 20:14
  • @OmriAttiya I think, there is a bias. As an example there are way more combinations on how to get to zero (-1+1,-1.4+1.4,+3.9-3.9,...), but there is only one combination on how to get to `MIN_VALUE` (`MIN_VALUE/2`+`MIN_VALUE/2`). – Progman Aug 15 '19 at 20:15
  • You are right, it has no overflow. But the zeros are still there. As I said, it is not a problem of `BigDecimal`but of multiplying `MAX_VALUE` with a number, which has not so many decimals. This solution will never generate a number like 0.1. – Thanthla Aug 15 '19 at 20:18
  • @Progman I agree that there are more combinations to create zero value, but since it's a **random** value, there should not be a bias. – Omri Attiya Aug 15 '19 at 20:18
  • @Thanthla in order to solve your decimal places problem, you can use [this](https://stackoverflow.com/a/153785/3729184) solution – Omri Attiya Aug 15 '19 at 20:31
0

You can do this by drawing two double random numbers. The first one is used to decide if you want a negative value or a positive value. The second one is used for the actual value from the negative part or the positive part. The approach will be like this:

Calculate the quotient between the range from zero to upper bound and the range from zero to lower bound. This will get you the information like "40% the value is positive, 60% the value is negative". Use the first random number to check which it is.

Then when you know if it is negative or positive use the normal approach to get a random number between zero and the lower/upper bound. This value can only be between 0 and MAX_VALUE (or MIN_VALUE), so there will be no "overflow".

However, I don't know about the combined probability in this case, if it is the same random probability when drawing only one random double value. If you have a negative/positive split of about 5% and 95%, then the second random number will be hit a value inside the 5% or the 95%. Not sure if it still "random" or if it even creates unwanted bias.

Progman
  • 16,827
  • 6
  • 33
  • 48