浮点的奇怪行为

时间:2019-07-27 12:19:21

标签: java floating-point

我理解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 ... 两者应该相同吗?

1 个答案:

答案 0 :(得分:3)

造成这种差异的主要原因是,对于任何 x ,<。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以分配给floatt1

可以计算出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。