(* BigDecimal double) should result in BigDecimal, not in Double, isn't it?

91 views
Skip to first unread message

Jevgeni Holodkov

unread,
Jan 16, 2010, 5:13:59 PM1/16/10
to Clojure
Currently, if the result of the multiplication is too small, then the
type will be double, despite the fact that one of the parameter was
BigDecimal:

Clojure 1.1.0
user=> (* 100M 1.1)
110.00000000000001
user=> (class (* 100M 1.1))
java.lang.Double

Such thing are really hard to find and this can be easily produced by
non-technical person, if he is using some kind of DSL which is based
on Clojure. Shoudn't it be BigDecimal instead?

Wbr,
Jevgeni

B Smith-Mannschott

unread,
Jan 17, 2010, 12:47:00 PM1/17/10
to clo...@googlegroups.com

IMO: No it should not.

(Maybe someone else can explain this more succinctly, I feel like I'm
muddling the point I'm trying to make.)

The whole point of using BigDecimal is to avoid the non-intuitive
funkyness that will result from using binary floating point (Double,
Float) while expecting decimal behavior. Furthermore, BigDecimal can
be arbitrarily precise, while Double has limited precision. Returning
a BigDecimal from a (* 100M 1.1) would be pretending that the
calculation is more precise than it actually is.

Your example is well chosen for my line of argument. Are you aware
that 0.1 can't be represented exactly as a Double? (It has a
non-terminating representation in binary, just as 1/3 =
0.33333333333333... does in decimal.) 0.1M, however can be represented
exactly as a BigDecimal. People can be awfully picky about predictable
arithmetic behavior when it comes to Money, which is what BigDecimal
is often used for.

(From a DSL standpoint, it might have been better if Clojure had
chosen 1.1 as the syntax for BigDecimal and 1.1D (or similar) for
Double, but there's no fixing that now.)

// Ben

Lauri Oherd

unread,
Jan 18, 2010, 3:02:12 AM1/18/10
to clo...@googlegroups.com
On page http://clojure.org/data_structures#toc2 there is written: "Any
numeric operation involving Doubles yields a Double."

Hope this helps,
Lauri

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
>

Jevgeni Holodkov

unread,
Jan 17, 2010, 5:13:10 PM1/17/10
to Clojure
Hi Ben, thanks for the answer. Yes, I understand the problems with
representing float-point numbers using iee7654 and now I understand
that returing BigDecimal would not solve the actual problem. However,
we don't talk about 0.33333(3) in my example, which is non-terminating
decimal. Entered 0.1 is actually a very precise number and the fact
that it gets imprecise somewhere internally should now affect, IMHO,
the result of multiplying two very precise numbers. What's the point
of having a possibility to build a very high-level language on top of
Clojure, when you still need to know the internals? Yes, having 1.1D
for doubles and fractions or bigdecimal for 1.1 probably would be the
best solution.. I don't know, if this is achievable now? Will there be
a impact on the perfomance or on a backward compatibility?

If is this is never to be fixed by some reason (which one can it be?),
then let me ask another question. I wonder, if there is a requirement
for user to write custom business rules himself (lets say he wants to
increase the price on 10%) and he uses 1.1, can I solve this issue
with Clojure core without using external parsers/preprocessors?
Something like replacing the 1.1 with 1.1M or 11/10 before evaluating
the code?

Wbr,
Jevgeni

On Jan 17, 7:47 pm, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:
> On Sat, Jan 16, 2010 at 23:13, Jevgeni Holodkov
>

Konrad Hinsen

unread,
Jan 18, 2010, 8:42:44 AM1/18/10
to clo...@googlegroups.com
On 17.01.2010, at 23:13, Jevgeni Holodkov wrote:

> decimal. Entered 0.1 is actually a very precise number and the fact
> that it gets imprecise somewhere internally should now affect, IMHO,
> the result of multiplying two very precise numbers. What's the point

There is no such thing as a "precise" or "imprecise" number as far as
the computer is concerned. What differs is the interpretation that
humans (programmers and users) make of the data items. The rules of
floating-point arithmetic (in Clojure and pretty much anywhere else)
are designed with the expectation that floats will be interpreted as
approximations. So as soon as you use a single float in some
expression, the whole expression becomes something to be considered
approximate, and therefore it will be of float type.

Unlike most languages, Clojure has a way to express precise non-
integer numbers: ratios. Just use 11/10 instead of 1.1 (or (+ 1 1/10)
if you prefer), and you won't see any floating-point result. In fact,
what you are complaining about is simply that the input string 1.1 is
interpreted as a float rather than as a ratio. Obviously it can't mean
both, so some choice has to be made.

> If is this is never to be fixed by some reason (which one can it be?),
> then let me ask another question. I wonder, if there is a requirement
> for user to write custom business rules himself (lets say he wants to
> increase the price on 10%) and he uses 1.1, can I solve this issue
> with Clojure core without using external parsers/preprocessors?
> Something like replacing the 1.1 with 1.1M or 11/10 before evaluating
> the code?

I don't think so. The very first step of Clojure's expression
processing system, the reader, already interprets 1.1 as a floating-
point constant. You would need your own reader to give a different
meaning to the input string 1.1. However, the good news is that you
would only need a different reader, you could then plug its results
into the standard evaluation system.

Konrad.

Richard Newman

unread,
Jan 18, 2010, 1:03:53 PM1/18/10
to clo...@googlegroups.com
>> Something like replacing the 1.1 with 1.1M or 11/10 before evaluating
>> the code?
>
> I don't think so. The very first step of Clojure's expression
> processing system, the reader, already interprets 1.1 as a floating-
> point constant. You would need your own reader to give a different
> meaning to the input string 1.1. However, the good news is that you
> would only need a different reader, you could then plug its results
> into the standard evaluation system.

Or, if you're taking a string from the user as your very first step,
you could (*choke*) apply regular expressions to append "M" to every
piece of floating-point syntax.

However, if those floating-point numbers come from some piece of
software other than a keyboard driver -- for example, they're read as
the value of a slider control -- then be careful of falsely assigning
decimal status to a string representation of a float...

Hacking Clojure's reader to replace the floating-point reader
shouldn't be too hard. Indeed, this might be something that can be
parameterized a la Common Lisp's radix/base settings.

Reply all
Reply to author
Forward
0 new messages