[json-processing-spec users] Re: BigDecimal for equals()/hashCode()
- From: Jonathan Fuerth <
- Cc: Joe Darcy <
- Subject: [json-processing-spec users] Re: BigDecimal for equals()/hashCode()
- Date: Thu, 24 Jan 2013 11:13:05 -0500
That's an entertaining response from Joe, but it's not a response to anything
that has been suggested by either Martin or myself in the conversation so
far. We all came into this understanding that floating point numbers are
increasingly widely spaced as their magnitude increases.
To put a finer point on it:
1. Every Java byte, short, char, int, and float value has an exact double
2. The larger magnitude long values do not have an exact double representation
3. There are an effectively infinite number of BigInteger and BigDecimal
values that have no double representation
4. Every BigDecimal value can be exactly represented by a String, although in
some cases it might take more memory to do so
I take it as a given that everybody involved in this conversation understood
all of the above before we got started, but I guess it helps to articulate
the points for the sake of clarity.
Getting back to the discussion about JsonNumber, here's the context I was
1. The JSON data format is most commonly used to interchange data with web
browsers, where the overwhelmingly common programming environment is
rounded to a nearby double-precision floating point value. I don't think we
can even assume a particular rounding rule (down, up, nearest, other?!).
3. The designer of an application that produces or consumes JSON data must
assume that all numbers in the data structure might be shoe-horned into
doubles, with the attending loss of precision, *unless* they know for certain
that the data structure will never be processed in a web browser. (And how
limiting of an assumption is that, over the lifetime of a system first
designed in 2013?)
In practice, because of the above concerns and the ubiquity of web browsers,
exact numeric values exchanged in JSON data structures (for example, unique
IDs and monetary amounts) are usually transmitted as quoted strings rather
than as numbers.
But even given the inherent dangers and limitations of trusting that a number
you put into a JsonNumber will retain its precision at every stage of
processing, nobody was suggesting that we just throw up our hands and let
JSR353's JsonNumber play fast and loose with numeric precision. We're merely
asking that common expectations and common-case performance constraints be
My suggestion was simply that we should be careful in the specification of
JsonNumber on these points:
1. JsonNumber should explicitly specify that it preserves the full precision
of the value it was constructed from (this is potentially relevant for any
JsonNumber constructed from a long, BigInteger, BigDecimal, or String value,
but especially delicate on data paths like String -> JsonNumber -> BigDecimal
or BigDecimal -> JsonNumber -> String where trailing zeroes are significant)
2. JsonNumber should be specified so that the implementation has the option
to store the value as a String internally. This makes it cheap in both time
and space to pass values through verbatim from one system to another. The
overwhelming majority of JsonNumber instances will either begin their life as
a String (parsed from an input stream) or end their lives as a String
(serialized to an output stream). Additionally, there are plenty of use cases
where the number will be read from an input stream, shuffled around (say, as
a member of a JsonObject or JsonArray) and then written back out without ever
being asked its numeric value.
3. JsonNumber's equals() and hashCode() methods should be specified in a
manner compatible with an internal String representation (the tricky part
here, as raised by Jitu in the original thread, is that we'd need to account
for the rare case that a number uses exponential notation) so a JsonNumber
implementation can correctly compare itself to another JsonNumber without
creating additional objects
a. the promise in point 1 to *retain* precision and scale in JsonNumber; and
b. the common-case performance concerns in points 2 and 3 about tying
JsonNumber to BigDecimal,
I submit that it goes against all reasonable expectations that a JsonNumber
received on the wire as "10" would not compare equal to a JsonNumber received
on the wire as "10.0" or "10.00". Leading and trailing zeroes that don't
contribute to the number's magnitude should be disregarded for the purposes
library constitutes a hidden trap.
So now that we're all (hopefully!) discussing the same topic, I'm keen to
hear your insights.
On 2013-01-24, at 12:07 AM, Jitendra Kotamraju wrote:
> Martin proposed different algorithm for JsonNumber equals()/hashCode() in
> his review . I am including Joe's response on this.
> I am also ccing him, please include him in replies as he is not on the
> users mailing list. His response is as follows:
> In general, it is essentially unpredictable from inspection which decimal
> strings are exactly representable as double floating-point value. Yes,
> there are many cases which are easy, but quick, pick which one of these two
> values is exactly representable as double:
> Need more time? Did you correctly pick the first one?
> Using BigDecimal as the numerical back store removes the concern for this
> and many other numerical anomalies at the cost of the "10.0" is not always
> equivalent to "10" issue. However, the latter problem is manageable
> whereas predicting string to double conversion is much less so.
> The equals / hashCode contracts of BigDecimal and long-standing and should
> by built-upon by the JSON API. You can define an alternative equals /
> hashCode definition (the hashcode in the pdf isn't quite right, the a
> numeric zero needs to be handled separately), but that introduces other
> kinds of anomalies.
>  http://crazyjavahacking.org/jsonProcessingReview.pdf