-
Notifications
You must be signed in to change notification settings - Fork 18
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
Remove jsonwire.ParseFloat fast path #139
Conversation
Thanks. |
// | ||
// If the number overflows the finite representation of a float, | ||
// then we return MaxFloat since any finite value will always be infinitely | ||
// more accurate at representing another finite value than an infinite value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment still stands as a valid argument. This is especially more relevant in v2 since we do provide opt-in support for actual infinity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, reverted most changes.
we do provide opt-in support for actual infinity
Sorry, but I don't understand this. I see the only option related to overflow is removed at #130 .
I don't want this behavior because (almost) all others just return infinity, including Go strconv
. I think they have good reason for that. For example, if I get this json:
{
"total": 1e1000
"used": 1e500
}
I definitely don't want total - used
to be 0
. Infinite value is inaccurate, but it records the inaccuracy, e.g. "1e1000 - 1e500" should be NaN
.
And for Token.Float()
, we don't return error, so we even can't know we got overflow.
But we can defer this discussing to another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing out that example.
Unfortunately, I don't believe there are any good answers here.
With regard to Javascript and Python. While they are both consistent with each other in that they parse 1e1000
as Infinity
without error, they are inconsistent with round trip serialization:
- JavaScript:
JSON.stringify(JSON.parse("1e1000"))
returnsnull
. - Python:
json.dumps(json.loads("1e1000"))
returnsInfinity
(which isn't even valid JSON).
Neither of them report an error and also inconsistent with each other for roundtrip serialization. In my opinion, this is the worst position to take since it leads to silent data loss.
In Go, we have decided that a float overflow is an error. This is arguably the most significant divergence from JS and Python, and whether we still return Inf
and or MaxFloat
is a minor detail.
- The reason for using max float is to ensure the JSON kind does not abruptly change due to a round trip. Thus, unmarshaling
1e1000
and marshaling it should still resulting a JSON number (e.g.,1.7976931348623157e+308
), not a JSON string (e.g.,"Inf"
). - I can see how
total - use
becoming0
could be a bug, but I should note that we are still reporting a Go error for the overflow. Thus, in order for this to be a logical bug, it would have to be after an error that was ignored.
fv, err := strconv.ParseFloat(string(b), bits) | ||
if math.IsInf(fv, 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep this behavior.
Calling strconv.ParseFloat() does not allocate now, so the necessity of fast path is reduced. This fast path actually slows down the process when it fails.
1b19926
to
e9fc080
Compare
Thank you for the cleanup! We can continue to discuss whether |
Calling
strconv.ParseFloat()
does not allocate now, so the necessity of fast path is reduced. This fast path actually slows down the process when it fails.If overflows, return infinity as all other libs, don't give surprise to user. Since we now always treat overflow as error, this may not be very important, but still a breaking change.
Simple benchmark for your reference
before
after
Float overflow behavior of other libs:
python3
Chrome