简体   繁体   English

浮点的奇怪行为

[英]Strange behavior of float point

I understand random.Float() bring back a float number between 0.0 to 0.999... 我了解random.Float()带回介于0.0到0.999之间的浮点数...

but for an unknown reason, almost the same code brings back 2 different answers. 但是由于未知的原因,几乎相同的代码会带回2个不同的答案。

I want to understand why t1 could random 1.0 and t2 can not. 我想了解为什么t1可以随机1.0,而t2不能随机。

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. 没有错误消息,我只是不明白为什么t1有时会带回1.0号而t2没有。

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? 编辑:t1生成最大值为0.999 ... * 0.1,即0.0999 ... + 0.9 = 0.9999 ... t2生成最大值为0.999 ... * 0.9,即0.8999 ... + 0.1 = 0.9999 ...两者都应一样吗?

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. 造成这种差异的主要原因是,对于任何x <1,.9 + x •.1大于.1 + x •.9,并且Random.nextFloat返回的值小于1。对于返回的最大值,前者表达式非常接近1以至于将其四舍五入为float会产生1,但后者的表达式离1更远,而将其四舍五入为float会产生下一个小于1的float

The largest value that Random.nextFloat returns is Random.nextfloat 16777215/16777216. Random.nextFloat返回的Random.nextfloatRandom.nextfloat 16777215/16777216。 Let M be this maximum, and let d = 1 − M = 1/16777216. M为该最大值,令d = 1 − M = 1/16777216。

If we calculated t1 using real numbers, its maximum value would be .9 + M •.1. 如果我们使用实数计算t1 ,则其最大值将为.9 + M •.1。 = .9 + (1− d )•.1 = 1−.1• d . = .9 +(1- d )•.1 = 1-.1• d Similarly, t2 would be .1 + M •.9 = .1 + (1- d )•.9 = 1-.9• d . 同样, t2将为.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. 现在,我们可以很容易地看到,最大的t1 (如果与实数计算)为0.1•d远离1,但t2有0.9•从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. Random.nextFloat返回的最大值是16777215/16777216的原因是它是小于1的最大floatfloat格式的精度是导致可表示的值之间的步长为1/16777216。 This means that the two representable values in this neighborhood are 16777215/16777216 and 1, and d is the distance between them. 这意味着此邻域中的两个可表示值分别是16777215/16777216和1, d是它们之间的距离。 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 . 上面的计算显示t1的最大值与t1仅相差0.1• d 。因此,将其四舍五入为float ,1是最近的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. 相比之下,最大值t20.9•d离1。这意味着它仅仅是0.1•从一千六百七十七万七千二百十六分之一千六百七十七万七千二百十五ð路程。 So, when it is rounded to float , 16777215/16777216 is the nearest float . 因此,将其四舍五入为float ,16777215/16777216是最近的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. Java ,源文本.1f.9f转换为float ,其结果为0.100000001490116119384765625和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 . 表达式中的算术是使用double执行的,然后将结果舍入为float以分配给t1t2

The largest that t1 can be may be calculated: 可以计算出t1的最大值:

  • Substituting the largest return value of nextFloat yields 0.9f + 16777215./16777216 * 0.1f; 替换nextFloat的最大返回值将产生0.9f + 16777215./16777216 * 0.1f; .
  • Evaluating in double arithmetic yields 0.999999971687793642871611154987476766109466552734375. double算术评估得出0.999999971687793642871611154987476766109109466552734375。
  • Converting to 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. 转换为float产生1,因为该double float值介于0.999999940395355355224609375(下一个较低的float值)和1(下一个较高的float值)之间,并且比前者更接近后者。

The largest that t2 can be may be calculated: 可以计算出t2的最大值:

  • Substituting the largest return value of nextFloat yields 0.1f + 16777215./16777216 * 0.9f; 用最大的nextFloat返回值替换为0.1f + 16777215./16777216 * 0.9f; .
  • Evaluating in double arithmetic yields 0.99999992400407933246242464520037174224853515625. double算术评估得出0.99999992400407933246242464520037174224853515625。
  • Converting to float yields 0.999999940395355224609375. 转换为float产生0.999999940395355224609375。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM