I understand random.Float() bring back a float number between 0.0 to 0.999...
but for an unknown reason, almost the same code brings back 2 different answers.
I want to understand why t1 could random 1.0 and t2 can not.
I tried to check for a similar question but could not find out anything similar
Random rand = new Random();
for (int i = 0; i < 1000000000; i++) {
float t1 = 0.9f + rand.nextFloat() * 0.1f;
float t2 = 0.1f + rand.nextFloat() * 0.9f;
if (t1 == 1.0f) {
System.out.println("t1 " + t1);
}
if (t2 == 1.0f) {
System.out.println("t2 " + t2);
}
}
no error messages I just can not understand why t1 bring back sometimes 1.0 number and t2 does not.
Edit: t1 generate maxmium of 0.999... *0.1 which is 0.0999... + 0.9 = 0.9999... t2 generate maxmimum of 0.999... *0.9 which is 0.8999... + 0.1 = 0.9999... Both should be the same no?
The primary cause of the difference is that .9 + x •.1 is larger than .1 + x • .9 for any x < 1, and Random.nextFloat
returns values less than 1. For the largest value it returns, the former expression is so close to 1 that rounding it to float
produces 1, but the latter expression is farther from 1, and rounding it to float
produces the next float
below 1.
The largest value that Random.nextFloat
returns is Random.nextfloat
16777215/16777216. Let M be this maximum, and let d = 1 − M = 1/16777216.
If we calculated t1
using real numbers, its maximum value would be .9 + M •.1. = .9 + (1− d )•.1 = 1−.1• d . Similarly, t2
would be .1 + M •.9 = .1 + (1- d )•.9 = 1-.9• d .
Now we can easily see that the maximum of t1
(if calculated with real numbers) is .1• d away from 1, but t2
is .9• d away from 1.
A reason the largest value Random.nextFloat
returns is 16777215/16777216 is that it is the largest float
less than 1. The precision of the float
format is such that the steps between representable values leading up to 1 are 1/16777216. This means that the two representable values in this neighborhood are 16777215/16777216 and 1, and d is the distance between them. Our calculations above show us the maximum value of t1
is just .1• d away from 1. So, when it is rounded to float
, 1 is the nearest float
.
In contrast, the maximum value of t2
is .9• d away from 1. This means it is just .1• d away from 16777215/16777216. So, when it is rounded to float
, 16777215/16777216 is the nearest float
.
That is using real-number arithmetic. Below, I will show the floating-point arithmetic. It has rounding errors, but these turn out to be small enough not to change the results.
In Java
, the source texts .1f
and .9f
are converted to float
, which yield 0.100000001490116119384765625 and 0.89999997615814208984375. The arithmetic in the expressions is performed using double
, and then the result is rounded to float
for assignment to t1
or t2
.
The largest that t1
can be may be calculated:
nextFloat
yields 0.9f + 16777215./16777216 * 0.1f;
. double
arithmetic yields 0.999999971687793642871611154987476766109466552734375. float
yields 1, because that double
value is between 0.999999940395355224609375 (the next lower float
value) and 1 (the next higher), and it is closer to the latter than to the former. The largest that t2
can be may be calculated:
nextFloat
yields 0.1f + 16777215./16777216 * 0.9f;
. double
arithmetic yields 0.99999992400407933246242464520037174224853515625. float
yields 0.999999940395355224609375.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.