Math.random()和精度损失的好奇心

Pat*_*ner 4 java math

以下内容无法编译:

int result = Math.random() + 1;

error: possible loss of precision
    int result = Math.random() + 1;
                               ^
    required: int
    found:    double
Run Code Online (Sandbox Code Playgroud)

但下面不会编译:

int result = 0;
result += Math.random() + 1;
Run Code Online (Sandbox Code Playgroud)

为什么?

将可编译代码放入嵌套循环中,可以预期每次迭代时结果都会递增1,因为Math.random()总是返回一个小于1的double,当加到整数时,小数部分会因为精确损失.运行以下代码并查看意外结果:

public class MathRandomCuriosity
{
  public static void main(String[] args)
  {
    int result = 0;
    for (int i = 0; i < 10; i++)
    {
      // System.out.println(result);
      for (int j = 0; j < 20; j++)
      {
        // System.out.println(result);
        for (int k = 0; k < 300; k++)
        {
          // System.out.println(result);
          for (int m = 0; m < 7000; m++)
          {
            result += Math.random() + 1;
          }
        }
      }
    }
    System.out.println(result);
  }
}
Run Code Online (Sandbox Code Playgroud)

使用10*20*300*7000 = 42,000,000次迭代,结果应为42,000,000.但事实并非如此!结果有所不同,即42,000,007 vs. 42,000,006 vs. 42,000,010等.

为什么?

顺便说一句......这不是在任何地方使用的代码,而是来自我在简报中收到的测验.嵌套循环的原因是我可以间隔查看结果的值.

Pet*_*rey 12

分配的运算符就像+=隐式转换一样.

注意:在这种情况Math.random()下,每次都会向下舍入为0,这会严重损失精度.;)

但是Math.random() + 1有一个非常小的机会被舍入到2.例如1.999999将四舍五入为1但是1.9999999999999999将四舍五入为2(但是double +运算符而不是转换为int).

long l = Double.doubleToLongBits(1.0);
double d0_999etc = Double.longBitsToDouble(l -1);
System.out.println("The value before 1 is " +d0_999etc+" cast to (int) is "+ (int) d0_999etc);
System.out.println("The value before 1, plus 1 is " +(1+d0_999etc)+" cast to (int) is "+(int)(1 +d0_999etc));
Run Code Online (Sandbox Code Playgroud)

版画

The value before 1 is 0.9999999999999999 cast to (int) is 0
The value before 1, plus 1 is 2.0 cast to (int) is 2
Run Code Online (Sandbox Code Playgroud)

  • 非常小编:这不是那么的Math.random()被截断为0,但"的Math.random()+ 1"被截断为1.1提升到两倍,然后加入,然后截断.这不是预先截断随机数. (2认同)