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

To Add an ES6 Compatible Way to ToString double #16471

Open
shmao opened this issue Feb 25, 2016 · 13 comments
Open

To Add an ES6 Compatible Way to ToString double #16471

shmao opened this issue Feb 25, 2016 · 13 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Numerics
Milestone

Comments

@shmao
Copy link
Contributor

shmao commented Feb 25, 2016

DataContractJsonSerializer converts a double value to a string by calling,

value.ToString("R", NumberFormatInfo.InvariantInfo)

The string is not compatible with ECMAScript 6 (see the specs). For example,

5E-06 should be converted as 0.000005
-3.3333333333333338E-28 should be converted as -3.3333333333333338e-28
4.94065645841247E-324 should be converted as 5e-324

An ES6 compatible way to ToString double and floats would be useful.

@JamesNK
Copy link
Member

JamesNK commented Feb 25, 2016

This would be useful for Json.NET or any other JavaScript/JSON focused .NET library.

@AlexGhiondea
Copy link
Contributor

We would need a formal API proposal for this.

@tarekgh
Copy link
Member

tarekgh commented Nov 21, 2016

if there is any change in the API surface then it will be good if include the proposal of the changes here.

@cyberphone
Copy link

Although the spec has not yet been published, Microsoft is (as shown in the document below), actively participating in a standardization effort building on ES6-compatible JSON processing:
https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https%3A%2F%2Fraw.githubusercontent.com%2Ferdtman%2FCleartext-JOSE%2Fmaster%2Fdraft-erdtman-jose-cleartext-jws.xml

@cyberphone
Copy link

Now the Microsoft sponsored proposal is published: https://tools.ietf.org/id/draft-erdtman-jose-cleartext-jws-00.html
This scheme already works in Java, Python, and JavaScript.

ToString("ES") could be an alternative if you feel uncomfortable modifying existing formatters.

@tannergooding
Copy link
Member

This is partially resolved by dotnet/coreclr#22040.

-3.3333333333333338E-28 should be converted as -3.3333333333333338e-28

This will now be supported by using ToString("r") (The lowercase R will result in the e being lowercase as well).

4.94065645841247E-324 should be converted as 5e-324

We will now return the "shortest roundtrippable string": 5E-324. As with the above, specifying r will make the e lowercase as well.

5E-06 should be converted as 0.000005

This would require additional changes to the NumberToString function and would require us to consider 0.000005 as more worthwhile than 5E-06 (which is currently the shorter string)

@cyberphone
Copy link

@tannergooding If you feel uncomfortable changing NumberToString to support the serialization required by https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-02 that's OK because I have already solved this by a V8-inspired port to .NET. However, I have just found a better base in the form of "Ryu" (https://github.com/ulfjack/ryu) which shrinks the code to almost nothing and is very fast as well.

@tannergooding
Copy link
Member

If you feel uncomfortable changing NumberToString to support the serialization required by https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-02

I think it is something that is reasonable to expose. Although I am unsure if the right thing is to have a new format specifier, a new API, or if we should just fix the existing NumberToString implementation. This likely requires a more formal proposal and discussion.

My initial thoughts are that just fixing the existing NumberToString implementation is the most desirable.

However, I have just found a better base in the form of "Ryu" (https://github.com/ulfjack/ryu) which shrinks the code to almost nothing and is very fast as well.

https://github.com/dotnet/coreclr/issues/19596 is tracking further investigation into the Ryu algorithm. There was just a concern raised was around the additional size requirements.

  • IIRC, the algorithm is faster than Dragon4, but slower than Grisu3. However, unlike Grisu3 it never hits a failure scenario. Removing Grisu3 would also alleviate some of the concerns around the additional size requirements, as we would be removing some tables we have defined there.

@tannergooding
Copy link
Member

@cyberphone, it might be worth noting that, while steps 6-10 look to be doable (it looks like step 8 is one where we are comparing n against -3, but it wants us to use -6 as the cutoff bounds), step 2 is likely a non-starter.

The ES6 specification looks to specify that If m is +0 or -0, return the String "0". However, this is in direct contradiction to the IEEE 754 specification which specifies that In particular, signs of zeros and infinities are preserved:

The conversions (described in 5.4.2) from supported formats to external character sequences and back that recover the original floating-point representation, shall recover zeros, infinities, and quiet NaNs, as well as non-zero finite numbers. In particular, signs of zeros and infinities are preserved.

@tannergooding
Copy link
Member

CC. @danmosemsft as an FYI to the above request.

A summary is that they would like us to either modify our existing NumberToString implementation (or provide some other mechanism to get the desired functionality) to be compatible with the ES6 specification. This would basically involve just tweaking some of the boundaries we are checking that determines when we print using the scientific notation and when we print using the number notation.

@cyberphone
Copy link

The ES6 spec for JSON number serialization is indeed a bit deviating from the IEEE spec but in a transport format it does in my opinion not make (too) much sense sending "-0", NaN, or Infinity. The latter are BTW illegal in JSON and in my .NET and Java implementations throw exceptions. That is, numbers with the pattern 7ffxxxxxxxxxxxxx cannot be serialized. ES6/JSON serializations like -0.0000033333333333333333 and 999999999999999700000 also defy "normal" rules.

That is, if I were to update ToString I would due to these differences add a new identifier to not have to make sub-optimal compromises.

Java version based on Ryu:
https://github.com/cyberphone/json-canonicalization/blob/master/java/canonicalizer/src/org/webpki/jcs/NumberToJSON.java

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 5.0 milestone Jan 31, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@tannergooding tannergooding added area-System.Numerics and removed area-System.Runtime untriaged New issue has not been triaged by the area owner labels Jun 23, 2020
@ghost
Copy link

ghost commented Jun 23, 2020

Tagging subscribers to this area: @tannergooding
Notify danmosemsft if you want to be subscribed.

@tannergooding tannergooding modified the milestones: 5.0.0, Future Jun 23, 2020
@cyberphone
Copy link

An RFC building on this scheme will be published in the coming weeks:
https://www.rfc-editor.org/authors/rfc8785.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Numerics
Projects
None yet
Development

No branches or pull requests

8 participants