Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference in output printing a pre-initialized Java double vs. inline

While upgrading a build from Java 1.6 to 1.7 our unit tests started failing because of a difference between how the 2 versions handle the printing of trailing zeros on doubles.

This can be reproduced with this example:

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

Java 1.6 will output:

pre-init: 0.0010
  inline: 0.0010

Java 1.7 will output:

pre-init: 0.001
  inline: 0.0010

I have 2 questions:

  1. Why is the printing of an inline concatenation different than the same concatenation with a pre-initialized value?
  2. What change between Java 1.6 and 1.7 is causing the difference in output from version to version?
like image 239
accresse Avatar asked Jul 10 '14 21:07

accresse


1 Answers

For part 1, it turns out the difference is in how the compiler optimizes the code.

The inline case decompiles to:

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

Operation 3 indicates that it is already pushing the String constant "inline: 0.0010" to the stack.

Compare to the pre-initialized case:

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

Operation 11 pushes the label "pre-init: " to the stack and then the following operation use a StringBuilder to append the double value.

I think the Java bug that @PM77-1 mentioned was fixed in the Java Double class but not in the compiler.

like image 80
accresse Avatar answered Nov 05 '22 09:11

accresse