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

Status of float roundtrips? (noticing deviations stemming from parsing) #604

Closed
bluenote10 opened this issue Jan 18, 2020 · 3 comments
Closed

Comments

@bluenote10
Copy link

I have JSON data generated by JavaScript (node). Thus, all containing float values should be valid IEEE 754 double precision literals. However, a parse + write roundtrip through serde_json leads to modified data.

#128 has been closed with the info that there will be a follow-up issue to track, but I couldn't find it, and the conversation is locked. I'm wondering what is the current status of float roundtrips. I'm noticing surprising effects:

// To verify that 117.63331139400017 is a literal that can be fully represented.
let x_val = 117.63331139400017;
let x_str = x_val.to_string();
println!("{} == {}", x_val, x_str);

// serialization => deserialization roundtrip
let x_parsed: f64 = serde_json::from_str(&json!(x_val).to_string()).unwrap();
println!("{} == {}", x_val, x_parsed);

// It looks like it is actually the deserialization:
println!("117.63331139400017 == {:?}", serde_json::from_str::<f64>("117.63331139400017").unwrap());

Output:

117.63331139400017 == 117.63331139400017
117.63331139400017 == 117.63331139400016
117.63331139400017 == 117.63331139400016

Tested with latest version (1.0.44) of serde_json.

@dtolnay
Copy link
Member

dtolnay commented Jan 19, 2020

This is tracked in #536.

@dtolnay dtolnay closed this as completed Jan 19, 2020
@dtolnay
Copy link
Member

dtolnay commented Jan 19, 2020

If you need parse + write roundtrip to preserve full precision, consider enabling the arbitrary_precision feature and using serde_json::Number instead of f64.

serde_json = { version = "1.0", features = ["arbitrary_precision"] }

@bluenote10
Copy link
Author

Thanks, that helps a lot!

I noticed that this doesn't work in general though, in particular the example I gave above also fails with arbitrary_precision feature flag enabled. The reason seems to be that parsing behaves differently when going straight to f64 compared to taking a detour through Value, which could lead to tricky bugs:

println!("117.63331139400017 == {:?}", 
    serde_json::from_str::<f64>("117.63331139400017").unwrap());
println!("117.63331139400017 == {:?}", 
    serde_json::from_str::<serde_json::Value>("117.63331139400017").unwrap());

Output:

117.63331139400017 == 117.63331139400016
117.63331139400017 == Number(117.63331139400017)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants