What I'm thinking, though, is that the BigDecimal
constructor must then be taking that double and turning it into
a decimal representation with more significant figures than seem
reasonable to me -- I mean, I understand where they come from, but
it seems a little wrong-headed to me to use an exact representation
for something that I think is better thought of as an approximation.
This, I think, is the heart of the problem. You use the word "approximation",
but it's not clear what a value is an approximation /to/. A big decimal,
seeing a double with exact value
0.1000000000000000055511151231257827021181583404541015625
has no way of knowing whether that is an "approximation" to
0.1
or to
0.100000000000000005551115
or, indeed, to
0.100000000000000005551115123125782702118158340454101562500000000001
So what is it going to choose ?
That goes double when you consider that BigDecimal's /job/ is the precise
representation of numerical values -- it would be inappropriate for it to make
information-loosing guesses about what the programmer "really meant". If you
want to convert doubles to BigDecimals using different rules (which is not in
itself unreasonable), then some of the possible rules are pre-packed for you.
For instance, by using Double.toString(double), and the BigDecimal(String)
constructor, you can convert using the
shortest-sequence-of-decimal-digits-which-maps-to-the-same-floating-point-value
rule (as Patricia has mentioned).
I don't really think that the concept of "approximation" is appropriate here.
There is a sense in which floating point computation can be considered to be
"like" precise computation with a certain amount of random noise added, so that
(like real physical measurements), you only ever have an approximate number,
and -- equally importantly -- you don't know what the true number should be.
That picture is fine as an approximation (;-) but it doesn't really reflect the
semantics of floating point arithmetic. The rules for Java FP are precise and
exact, down to the last bit -- there is no approximation, or error involved at
all[*]. If we programmers want to use floating point values to represent
something other than the specific set of rational numbers defined by the IEEE
format, then it is /our/ responsibility to implement whatever mapping we have
decided upon -- that mapping is not, and cannot be, the responsibility of a
fundamental library. (Not to say that pre-packed facilities for common
mappings are not handy -- and in fact Java provides such things, but as
supplements to the fundamental operations, not as replacements for them.)
Incidentally, that's one way of resolving the "puzzle" that the value
0.1000000000000000055511151231257827021181583404541015625
seems to take more bits than are available to represent it. There is a
specific set of slightly less than 2**64 rational numbers which can be
represented as floating point. Each of those is represented /exactly/, whereas
the others cannot be represented /at all/. For instance the number
0.1000000000000000055511151231257827021181583404541015626
cannot be represented in 64-bit IEEE floating point. It doesn't take ~180 bits
to represent a 55-digit decimal value because most of those 10**55 values have
no representation.
-- chris
[*] Actually some slop is allowed in the last bit for some operations under
some conditions, but that doesn't affect the issue here.