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

Recommend user to use "G17" for round-trip converting for double numbers. #2919

Closed
mazong1123 opened this issue Aug 16, 2017 · 4 comments
Closed
Assignees
Labels
doc-enhancement Improve the current content [org][type][category]

Comments

@mazong1123
Copy link

mazong1123 commented Aug 16, 2017

Today we're suggesting user to use "R" for round-trip converting for double numbers.

https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings (See The Round-trip ("R") Format Specifier)
https://msdn.microsoft.com/en-us/library/kfsatb94(v=vs.110).aspx

However, double.ToString("R") will introduce a bug caused by its design: https://stackoverflow.com/questions/24299692/why-is-a-round-trip-conversion-via-a-string-not-safe-for-a-double

Generally speaking, "R" specifier tries to convert double to string in 15 digits precision first. If the precision is not enough for round tripping, it goes to convert in 17 digits precision. However, for some numbers (e.g. 0.84551240822557006) it would wrongly pick 15 digits precision (we should pick 17 digits), which cannot guarantee round-trip.

The documents listed above have warnings for users and suggest users to use "G17" if the code compiled using /platform:x64 or /platform:anycpu. This is less useful for real-world users. Because users are almost going to use "R" at first time. Later when they find a bug on production they would be frustrated.

After discussed in dotnet/coreclr#13140 , considering the comparability, we decide to not change the current behavior of "R" specifier, but we need to update the document to RECOMMEND user to use "G17" for round-tripping instead of using "R".

@mazong1123 mazong1123 changed the title Recommend user use "G17" for round tripping double numbers. Recommend user to use "G17" for round tripping double numbers. Aug 16, 2017
@mazong1123 mazong1123 changed the title Recommend user to use "G17" for round tripping double numbers. Recommend user to use "G17" for round tripping converting for double numbers. Aug 16, 2017
@mazong1123 mazong1123 changed the title Recommend user to use "G17" for round tripping converting for double numbers. Recommend user to use "G17" for round-trip converting for double numbers. Aug 16, 2017
@rpetrusha rpetrusha self-assigned this Aug 16, 2017
@rpetrusha rpetrusha added this to the August 2017 milestone Aug 16, 2017
@abelbraaksma
Copy link

I'm not opposing your suggestion, in fact, I highly welcome adding this detail, knowing that I have, on different occasions, fallen for the trap of using only "R".

However, I would like to suggest adding a note, or even a code example, that shows how to get the minimal exact representation. That is, try 15 digits precision, test roundtrip, if fail, try 16 digits precision, if fail, try 17 digits precision (always succeeds).

It may also be worth mentioning that there is no built-in way to get a minimal roundtrippable representation in scientific notation (both "R" and "G" only switch to scientific if they have to). The above solution can be used to find a similar value with the "E" format specifier.

As an example, the number in your post, 0.84551240822557006, is roundtrippable with 16 digits of precision: 0.8455124082255701, which you will get with "R16" or "E15" (the latter is one lower, as it the number 15 here indicates the number of digits after the decimal point). An example that is only roundtrippable with 17 digits of precision is 1.0000000000000002.

It may be worthwhile to include such numbers as examples.

@mazong1123
Copy link
Author

mazong1123 commented Aug 24, 2017

try 15 digits precision, test roundtrip, if fail, try 16 digits precision, if fail, try 17 digits precision (always succeeds).

Do we have a real world scenario that needs to find the exactly minimal round-trippable precision for a specific number?

An example that is only roundtrippable with 17 digits of precision is 1.0000000000000002.
It may be worthwhile to include such numbers as examples.

Yes. It would be good to describe the reason why G17 specifier can guarantee the roundtrip.

cc @rpetrusha who is working on this issue.

@abelbraaksma
Copy link

abelbraaksma commented Aug 24, 2017

Do we have a real world scenario that needs to find the exactly minimal round-trippable precision for a specific number?

@mazong1123, I can think of at least two. My own real-world scenario, writing compilers. Some language specifications require this (in my case XSLT/XPath). The other one being that it is often required to show a number in the shortest form possible. This is also reflected by the need for specifiers like "G" in the first place (which returns a scientific notation or decimal notation, whichever is shorter).

A third one is, obviously, educational: showing users how this works or can work also shows users how they can implement this for other precisions.

Personally, I have never understood why there is no format specifier that can do this, or why "R" skips from 15 to 17, not testing 16 digits precision. After all, the sum of all numbers requiring 17 digits is exponentially smaller than the sum of all numbers requiring 16 digits. We should not strive to default to the exceptional case, but strive to default to the common case.

Finally, this argument is the same for whether you would return "1.220" or "1.22": the "R" specifier already returns the shortest form in all scenarios, except for 15-17 digits numbers. So adding such an example is basically filling the gap left by a less-than-optimally working "R" format specifier.

Anybody who does not care about "shortest form", but only about roundtrippability, does not need "R" to begin with, they can just use "E50" or something (though obviously, "E16", returning 17 digits precision, is enough).

@rpetrusha rpetrusha modified the milestones: August 2017, September 2017 Aug 31, 2017
@mairaw mairaw added Area - .NET Guide doc-enhancement Improve the current content [org][type][category] labels Sep 9, 2017
@rpetrusha
Copy link
Contributor

I've opened PR #3101 to change the recommended format string for round-tripping from "R" to "G17".

Determining the minimal exact representation is outside the scope of the Standard Numeric Format Strings topic, @abelbraaksma. If you feel strongly that you'd like one to be published, please open a separate issue. And if you'd be interested in writing it yourself, contributions are certainly welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc-enhancement Improve the current content [org][type][category]
Projects
None yet
Development

No branches or pull requests

4 participants