Consider, if you need to accumulate 0.1 until the result is one. Groovy does it as expected
0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 1.0
Just because 0.1 is BigDecimal in Groovy.
In Clojure, the example is not that nice:
(+ 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1) results in 0.9999999999999999.
Basically, the problem is solved when you add the M qualifier to each of the numbers in the expression, like
(+ 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M) = 1.0
Or use rational numbers:
(+ 1/10 1/10 1/10 1/10 1/10 1/10 1/10 1/10 1/10 1/10) = 1.0
The hypothetical problem is that, if a number (say, some money amount) is stored in the database, and the calculation is configured by the user in business rules via some DSL, then a user could create a calculation that could lead to a loss of precision. For instance:
(* 100M 1.1) = 110.00000000000001
(class (* 100M 1.1)) = java.lang.Double
Double there is!!!
The same kind calculation gives BigDecimal as a result in Scala:
scala.BigDecimal(1.5) * 1.5
BigDecimal = 2.25
The question is what is the rationale behind such behavior and which result is correct? To me, when writing an application which operates with monetary amounts, it is the Scala which is correct.
5 comments:
Why don't You just add the M qualifier to the numbers in the expression?
Automating this shouldn't be too hard.. :)
Lauri,
this is not hard and it is not a problem at all.
The interesting thing is how the types are converted in the expressions. In Scala and Clojure this is quite different.
I haven't looked at Scala but in Clojure there is the following rule; any numeric operation involving Doubles yields a Double (please read other rules at http://clojure.org/data_structures#toc2).
This is expected because Doubles are interpreted as approximations.
There is also a quite recent conversation about this topic on Clojure user group:
http://groups.google.com/group/clojure/browse_thread/thread/95afe60baa55d4ec
Lauri,
I'm aware about that rule and I know about the discussion on the group because my friend Jevgeni (aka lafy) started that :)
I'm not arguing that it is wrong but I insist that it is *bad* coz when someone is counting money it will eventually become a source of bugs in the software. Not because the language is wrong but because of the human nature :)
The very last suggestion on that google group is the one I like the most. Add params to the Clojure runtime to read all decimals either as double (now) or as ratios (wanted). Shouldn't be so hard to implement, I think.
Post a Comment