打印预初始化的 Java double 与 inline 的输出差异

Posted

技术标签:

【中文标题】打印预初始化的 Java double 与 inline 的输出差异【英文标题】:Difference in output printing a pre-initialized Java double vs. inline 【发布时间】:2014-07-10 21:52:55 【问题描述】:

在将构建从 Java 1.6 升级到 1.7 时,我们的单元测试开始失败,因为 2 个版本在处理双精度后尾零打印的方式不同。

这个例子可以重现:

double preInit = 0.0010d;
System.out.println("pre-init: " + preInit);
System.out.println("  inline: " + 0.0010d);

Java 1.6 将输出:

pre-init: 0.0010
  inline: 0.0010

Java 1.7 将输出:

pre-init: 0.001
  inline: 0.0010

我有两个问题:

    为什么内联串联的打印与具有预初始化值的相同串联不同? Java 1.6 和 1.7 之间的哪些变化导致不同版本的输出存在差异?

【问题讨论】:

这个SO post 应该有帮助。 @PM77-1 我会说它是重复的。您是否有任何理由不投票以重复关闭该问题? 我认为@PM77-1 肯定回答了我问题的第 2 部分 - Java 中有一个错误已在 1.7 中修复。我仍然对第 1 部分感到好奇。 @PascalCuoq 它有相关原因的事实并不会使这个问题成为骗局。该问题询问版本之间的行为变化,该问题注意到同一版本中行为之间的差异。有趣的问题! @JoelBerger 啊,是的,你是对的,System.out.println("pre-init: " + preInit); 在 Java 1.7 上的行为仍然令人费解。我投票支持这个问题保持开放。 【参考方案1】:

对于第 1 部分,事实证明不同之处在于编译器优化代码的方式。

内联案例反编译为:

0:   getstatic       #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3:   ldc     #22; //String   inline: 0.0010
5:   invokevirtual   #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8:   return

操作 3 表示它已经将字符串常量“inline: 0.0010”压入堆栈。

与预初始化的情况比较:

0:   ldc2_w  #16; //double 0.0010d
3:   dstore_1
4:   getstatic       #18; //Field java/lang/System.out:Ljava/io/PrintStream;
7:   new     #24; //class java/lang/StringBuilder
10:  dup
11:  ldc     #26; //String pre-init:
13:  invokespecial   #28; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
16:  dload_1
17:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(D)Ljava/lang/StringBuilder;
20:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
23:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
26:  return

操作 11 将标签“pre-init:”压入堆栈,然后以下操作使用 StringBuilder 附加双精度值。

我认为@PM77-1 提到的 Java 错误已在 Java Double 类中修复,但未在编译器中修复。

【讨论】:

显然 1.7 编译器是用 Java 1.6 编译的。应该自举:) en.wikipedia.org/wiki/Bootstrapping#Compilers 您在探索哪个版本的 Java 7 编译器? java 版本 "1.7.0_55"/Java(TM) SE Runtime Environment (build 1.7.0_55-b13)/Java HotSpot(TM) 64-Bit Server VM (build 24.55-b03, 混合模式)

以上是关于打印预初始化的 Java double 与 inline 的输出差异的主要内容,如果未能解决你的问题,请参考以下文章

#私藏项目实操分享# Java实战系列「技术盲区」Double与Float的坑与解决办法以及BigDecimal的取而代之!

7月24号 JAVA数组 初始化

初始化正在影响与初始化无关的代码

double java默认初值

怎么将double类型后面的.0(点零)去掉

Java盲点攻克「数值浮点数精度系列」Double与Float的坑与解决办法以及BigDecimal的取而代之!