for testing a specific math function I implemented I need to generate a lot of doubles in the full range of doubles > 0. So the random generated value should be between 2^−52 × 2^−1022 and (2−(2^−52)) × 2^1023. I tried using
ThreadLocalRandom.current().nextDouble(origin, bound)
but it only gives values close to 1e300.
I tested it with
public void testRandomDouble() {
double current;
for (int j = 0; j < 10; j ) {
double min = Double.POSITIVE_INFINITY;
for (int i = 0; i < 100_000_000; i ) {
current = ThreadLocalRandom.current().nextDouble();
if (current < min) {
min = current;
}
}
System.out.println(min);
}
}
generating the output
1.2100736287390257E300
1.2292284466505449E300
1.4318629398915128E299
6.922983256724938E299
1.3927453080775622E300
4.8454315085367987E300
1.4899199386555683E299
3.7592835763389994E299
2.0561053862668256E300
1.6268118313101214E299
Even when recompiling and rerunning the test (so the local thread has a different seed) results in approx. the same output. I didn't find anything about this behavior online. What am I missing?
CodePudding user response:
There are ten times as many values in the range 1e300 as 1e299, and ten times as many values in the range 1e299 as in 298. This shouldn't necessarily be surprising! You should expect 90% of your values to be e300, 99% to be e299 or e300, etc. If you want a uniform distribution over the values that can possibly be held in a double, not a uniform distribution over the number line, you will need a very different algorithm. That would probably look something like
double d;
do {
d = Double.longBitsToDouble(random.nextLong());
} while (Double.isNaN(d) || Double.isInfinite(d) || d <= 0);
return d;