Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Math.random()和精度损失_Java_Math - Fatal编程技术网

Java Math.random()和精度损失

Java Math.random()和精度损失,java,math,Java,Math,以下内容未编译: int result = Math.random() + 1; error: possible loss of precision int result = Math.random() + 1; ^ required: int found: double 但以下不会编译: int result = 0; result += Math.random() + 1; 为什么? 将可编译代

以下内容未编译:

int result = Math.random() + 1;

error: possible loss of precision
    int result = Math.random() + 1;
                               ^
    required: int
    found:    double
但以下不会编译:

int result = 0;
result += Math.random() + 1;
为什么?

将可编译代码放入嵌套循环中,每次迭代的结果都会增加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);
  }
}
公共类数学模型
{
公共静态void main(字符串[]args)
{
int结果=0;
对于(int i=0;i<10;i++)
{
//系统输出打印项次(结果);
对于(int j=0;j<20;j++)
{
//系统输出打印项次(结果);
对于(int k=0;k<300;k++)
{
//系统输出打印项次(结果);
对于(int m=0;m<7000;m++)
{
结果+=Math.random()+1;
}
}
}
}
系统输出打印项次(结果);
}
}
当10*20*300*7000=42000000次迭代时,结果应为42000000次。但事实并非如此!结果各不相同,即42000007对42000006对42000010等

为什么?


顺便说一句……这不是任何地方都在使用的代码,它来自我在时事通讯中收到的一个测验。嵌套循环的原因是,我可以每隔一段时间查看结果的值。

+=
这样的赋值运算符执行隐式转换

注意:在这种情况下,
Math.random()
每次都将四舍五入到0,这是一种严重的精度损失。;)

但是
Math.random()+1
被四舍五入为2的可能性很小。e、 g.1.9999999将四舍五入为1,但1.9999999999999将四舍五入为2(但
double+
运算符而不是转换为
int

印刷品

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

IEEE数学实现的细节指出了双精度/浮点到整数转换的精度损失和不可靠结果。例如,我曾经发现比较浮点数的代码:

int x = 0;
if (a <= b) 
{ 
    x = y; 
}
if (a > b) 
{ 
    x = z; 
}

根据定义
Math.random()
返回从0.0到1.0的
double
结果。操作
Math.random()+1
创建双精度结果,然后将其分配给int变量,从而生成整数结果。每次迭代的结果都是1,除非
Math.random()
精确返回1.0。这种情况发生的可能性很低,但仍然存在。从统计上看,这大约是6000分之一。这就是某些循环迭代向结果中添加2的原因


所以,这里没有失去精确性。一切都是按照规范进行的。

在一般情况下,这个问题已经被反复回答过。为(int i=0;i<42000000;i++)编写
的方法真奇怪。
首先尝试将Math.random()调用强制转换为整数。目前,代码中的“1”字面值被隐式转换为双精度,这意味着精度在某处丢失。是否可能重复@Woot4Moo no?整数的最大值(java)为2147483647。这是4200万的50倍多。非常小的补充:不是Math.random()被截断为0,而是“Math.random()+1”被截断为1。1被提升为double,然后被添加,然后被截断。这并不是说随机数被提前截断了。当我找到
System.out.println(0.9999999999999)时,你回答了这个问题
1.0
+1表示速度快。@SeanOwen,我的观点是有一个错误的假设,因为
Math.random()
总是四舍五入为0,
Math.random()+1
总是四舍五入为1。被四舍五入的不是1.99999999999999。而是1.0D+0.99999999999d=2.0D。事实上,它与+=运算符无关。@jsravn,
+=
正在转换为
int
,如果没有它,程序将无法编译。我已经澄清了进行舍入的操作。铸造到
(int)
总是向下舍入(如数学地板(x))。但是,
double
操作取整到最接近的表示。这个答案是错误的。根据规范,Math.random返回一个双精度值,因此我猜这是因为0是有符号的。(也就是说,浮点系统中同时存在一个“+0”和一个“-0”,这两个数字有不同的表示形式)看看这些数字如何与比较运算符交互是一件很有趣的事情。是的,甚至还有一些方法可以将接近零的轮数调整为零。最初的代码是由一位科学家编写的,所以我必须向他解释IEEE数学是如何违反代数表达式的一些基本租户的。虽然这并不能回答我的两个问题,但它非常有趣和有用!非常感谢。我想让大家了解浮点数学的一般问题。Java隐藏了IEEE数学的许多细节,但没有隐藏结果。
int x = 0;
if (a <= b) 
{ 
    x = y; 
}
if (a > b) 
{ 
    x = z; 
}
int x = 0; 
if (a <= b) 
{ 
    x = y; 
} 
else 
{ 
     x = z; 
}