Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: in correct rounding to two digits #83

Open
ulfjack opened this issue Dec 27, 2018 · 6 comments
Open

Java: in correct rounding to two digits #83

ulfjack opened this issue Dec 27, 2018 · 6 comments
Labels
bug Something isn't working Java Affects the Java implementation in src/main/java.

Comments

@ulfjack
Copy link
Owner

ulfjack commented Dec 27, 2018

The Java implementation sometimes doesn't output the closest two-digit representation of a number, but instead rounds to one digit (correctly), and then appends a '0'.

Known examples:
1.0E-323 should be 9.9E-324
1.0E-322 should be 9.9E-323

@ulfjack ulfjack added bug Something isn't working Java Affects the Java implementation in src/main/java. labels Dec 27, 2018
@LeeTibbert
Copy link

LeeTibbert commented Feb 25, 2019

@ulfjack

I just tried to replicate this issue as part of my efforts to port RYU to Scala Native. Please pardon
any lack of understanding or stupidity on my part, When I use https://repl.it/languages/java to run the java code

class Main {
  public static void main(String[] args) {
    System.out.println(Double.toString(1.0E-323));
    System.out.println(Double.toString(9.9E-324));
  }
}

I get the same output 1.0E-323 for both 1.0E-323 and 9.9E-324.
That is the output reported as incorrect/buggy in this issue. Seems
like Java did not get the memo.

Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
1.0E-323
1.0E-323

Using the web site avoids an peculiarities on my local machine but uses
an old version of Java 8.

I get the same results when I run the same code on my local 64 bit machine running
'openjdk 11.0.1 2018-10-16'

Does RYU truely have a bug here or am I not seeing something, either subtle or obvious?

Thank you,

Lee

PS: The rest of the RYU port to Scala Native seems to be running just fine. Thank you for RYU.

@ulfjack
Copy link
Owner Author

ulfjack commented Feb 27, 2019

Well, whether the current output is correct or not depends on what exactly the specification for Double.toString says. Unfortunately, it's not very precise in a mathematical sense, and this is a rather esoteric corner case. The spec basically says that we should print (a) the shortest number, with (b) at least two digits, that (c) parses back to the original number and (d) is closest to the exact value.

Ignoring (b), the shortest number would clearly be 1e-323. The crux of the matter is the requirement (b).

Should we compute the shortest number, and then print two digits? Then it should be 1.0e-323.

Should we compute the two-digit number that is closest to the original input? Then it should be 9.9e-324.

Clearly, we have to pick one of these interpretations. In my opinion, the second interpretation is slightly preferable, that is, I prefer the printed number to be slightly closer to the exact value. We have two digits, so why not use them? There was a brief discussion of this on one of the OpenJDK mailing lists, and there was no strong argument against this interpretation.

And yes, that implies that the current OpenJDK implementation of Double.toString is incorrect. There are actually more cases where it is incorrect, and more clearly so - there are some cases where it prints too many digits (which is certainly better than too few!).

@LeeTibbert
Copy link

@ulfjack Thank you for the additional description.

Java does not have as long a history as C but it still has 25 or so years
of use "in the wild". To some/most, "long standing existing practice"
is a useful decision rule for situations where any (probably post-hoc)
specification is unclear. I did not go all the way back to the earliest
Java release, but I suspect that it the round trip of 1e-323 would
yield 1.0E-323.

I suspect that I an not the only developer who would evaluate Ryu
for correctness by running (many) test cases of "matched pairs"
comparing Ryu and Java output. I would find Ryu printing out
9.9E-324 somewhere between mildly astounding and regrettable.

I would have to implement a workaround to avoid spending the
rest of my professional life explaining the difference to the more
sharp-eyed of my user base.

With full support for your efforts, I say "Your field, your rules" but
urge you to consider what I suspect is long standing Java practice.

@LeeTibbert
Copy link

LeeTibbert commented Feb 28, 2019

Some say that Java is defined by its abundant implementation "quirks".
Many have grumbled that any attempt to match Java results by a
rational means or specification is doomed. I for one have plenty
of scars on my hide from Java quirks.

If the goal is to have Ryu follow a spec more closely (a laudable goal),
perhaps a solution would be to paste on a big label saying "RyuDouble.java
is not Java", similar to the wordplay beloved in some circles "Xinu is not unix"
and such? Perhaps that is what you are saying already and did not twig
to it?

I am probably going to have to take the "Java-like, not one-to-one Java" approach
myself.

ulfjack added a commit that referenced this issue Feb 28, 2019
@ulfjack
Copy link
Owner Author

ulfjack commented Feb 28, 2019

The discussion thread in upstream is about merging a new implementation that returns 9.9E-324 in this case, as well as a more mathematically precise specification. I tested Ryu against the new implementation and discovered that Ryu returns 1.0E-323 in this case (but otherwise found no differences in output). I don't know if or when upstream will merge a new implementation and whether it will be the one that was discussed.

In any case, I can clarify in the README that the current behavior differs from Double.toString in some cases.

@ulfjack
Copy link
Owner Author

ulfjack commented Feb 28, 2019

There aren't a lot of one-digit and two-digit numbers across all possible double values, so I could check all of them against OpenJDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Java Affects the Java implementation in src/main/java.
Projects
None yet
Development

No branches or pull requests

3 participants
@ulfjack @LeeTibbert and others