从double转换为int并不总是只丢弃小数部分

pgr*_*ras 11 java

我正在试验我在这里找到的Java专家通讯中的代码.

public class MeaningOfLife {
  public static String findOutWhatLifeIsAllAbout() {
  int meaning = 0;
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 20; j++) {
      for (int k = 0; k < 300; k++) {
        for (int m = 0; m < 7000; m++) {
          meaning += Math.random() + 1;
        }
      }
    }
  }
  return String.valueOf(meaning).replaceAll("0*$", "");
  }

public static void main(String[] args) {
  System.out.println(findOutWhatLifeIsAllAbout());
}
}
Run Code Online (Sandbox Code Playgroud)

一旦我意识到存在使用复合赋值运算符 + = 的隐式转换,问题"它打印什么"的答案似乎很明显.

但它打印的内容如下:420000006或420000007,而不是(预期的)420000000(或"42",删除尾随零后).

所以这表明从double转换为int并不总是只删除double中的小数部分,如下所示:如何在Java中将double转换为int?

所以我做了一些试验,这是我发现的一个例子:

System.out.println((int)  (131070.99999999999)); // -> 131070
System.out.println((int)  (131071.99999999999)); // -> 131071
System.out.println((int)  (131072.99999999999)); // -> 131073 !!!
System.out.println((int)  (131073.99999999999)); // -> 131074 !!!


System.out.println((int)  (16382.999999999999)); // -> 16382
System.out.println((int)  (16383.999999999999)); // -> 16383
System.out.println((int)  (16384.999999999999)); // -> 16385 !!!
System.out.println((int)  (16385.999999999999)); // -> 16386 !!!
Run Code Online (Sandbox Code Playgroud)

...所以现在我正在寻找这种行为的解释???

Too*_*mai 9

许多十进制值不可能是双值.在使用它们之前,首先必须将它们挤压到最接近的双值.

示例:16384.999999999999没有精确的双重表示.两个最接近的值是16384.9999999999963620211929082870483398437516385.0.压缩导致差异大约0.000000000003,而挤压导致差异0.000000000001- 上升导致更接近的值,所以这就是它的解释.


Hur*_*rda 8

也许你会对这个事实感到惊讶

System.out.println(131072.99999999999); // -> 131073 !!!
Run Code Online (Sandbox Code Playgroud)

你没有把事件转换成int.

在Java(以及其他语言)中存在双重表示的问题.系统不像人类那样使用"十进制"部分.

这里详细解释:http: //en.wikipedia.org/wiki/Floating_point

但是,简而言之,双重值是存储为最终结果的几个部分(图像类似于-1.23*10 ^ -15).而且每个给定的数字只有有限的空间.因此,最终您无法准确表示Double.MAX_VALUE和Double.MIN_VALUE之间的每个数字.


Jon*_*ust 6

您可以根据需要编写包含任意double数字的文字,但这并不意味着double值可以表示您编写的文字.

摆脱int演员,以更仔细地看到double你的文字的表现形式将在它被铸造之前int:

System.out.println(16383.999999999999);
System.out.println(16383.999868686868686999999999);
System.out.println(16384.999999999999);
System.out.println(16385.999999999999);
Run Code Online (Sandbox Code Playgroud)

输出:

16383.999999999998
16383.99986868687
16385.0
16386.0
Run Code Online (Sandbox Code Playgroud)

将这些转换为int,你会看到:

16383
16383
16385
16386
Run Code Online (Sandbox Code Playgroud)