我理解random.Float()会带来一个介于0.0到0.999之间的浮点数...
但是由于未知的原因,几乎相同的代码会带回2个不同的答案。
我想了解为什么t1可以随机1.0,而t2不能随机。
我试图检查类似的问题,但找不到类似的东西
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);
}
}
没有错误消息,我只是不明白为什么t1有时会带回1.0数字而t2没有。
修改: t1产生的最大值为0.999 ... * 0.1,即0.0999 ... + 0.9 = 0.9999 ... t2产生的最大值为0.999 ... * 0.9,即0.8999 ... + 0.1 = 0.9999 ... 两者应该相同吗?
答案 0 :(得分:3)
造成这种差异的主要原因是,对于任何 x 9>,<。em> x •.1都大于.1 + x •.9。 em> <1,并且Random.nextFloat
返回小于1的值。对于返回的最大值,前一个表达式非常接近1,因此将其舍入到float
会产生1,但是后一个表达式则更远从1取整,然后将其四舍五入到float
会产生低于1的下一个float
。
The largest value that Random.nextFloat
returns is Random.nextfloat
16777215/16777216.令 M 为该最大值,并令 d = 1- M = 1/16777216。
如果我们使用实数计算t1
,则其最大值将为.9 + M •.1。 = .9 +(1− d )•.1 = 1−.1• d 。同样,t2
将是.1 + M •.9 = .1 +(1- d )•.9 = 1-.9• d 。
现在,我们可以很容易地看到t1
的最大值(如果以实数计算)与.1相距.1• d ,而t2
为.9• d 远离1。
Random.nextFloat
返回的最大值是16777215/16777216的原因是它是最大的float
小于1。float
格式的精度使得可表示之间的步长前导值为1的值为1/16777216。这意味着该邻域中的两个可表示值分别是16777215/16777216和1,而 d 是它们之间的距离。上面的计算结果显示,t1
的最大值距1仅为.1• d 。因此,将其四舍五入为float
时,1是最接近的{{ 1}}。
相反,float
的最大值与1的距离为.9• d 。这意味着与16777215的距离仅为.1• d 。 / 16777216。因此,当将其舍入为t2
时,16777215/16777216是最接近的float
。
那是使用实数算法。下面,我将展示浮点算法。它具有舍入误差,但事实证明这些误差很小,不会改变结果。
在float
中,源文本Java
和.1f
转换为.9f
,其结果为0.100000001490116119384765625和0.89999997615814208984375。表达式中的算术是使用float
执行的,然后将结果舍入到double
以分配给float
或t1
。
可以计算出t2
可以达到的最大值:
t1
产生nextFloat
。0.9f + 16777215./16777216 * 0.1f;
算术运算得出0.999999971687793642871611154987476766109466552734375。double
会产生1,因为float
的值介于0.999999940395355355224609375(下一个较低的double
值)和1(下一个较高的值)之间,并且更接近后者比前者更重要。可以计算出float
可以达到的最大值:
t2
产生nextFloat
。0.1f + 16777215./16777216 * 0.9f;
算术运算得出0.99999992400407933246242464520037174224853515625。double
会得到0.999999940395355224609375。