geejay
geejay

Reputation: 5618

Scala and Java BigDecimal

I want to switch from Java to a scripting language for the Math based modules in my app. This is due to the readability, and functional limitations of mathy Java.

For e.g, in Java I have this:

BigDecimal x = new BigDecimal("1.1");
BigDecimal y = new BigDecimal("1.1");
BigDecimal z = x.multiply(y.exp(new BigDecimal("2"));

As you can see, without BigDecimal operator overloading, simple formulas get complicated real quick.

With doubles, this looks fine, but I need the precision.

I was hoping in Scala I could do this:

var x = 1.1;
var y = 0.1;
print(x + y);

And by default I would get decimal-like behaviour, alas Scala doesn't use decimal calculation by default.

Then I do this in Scala:

var x = BigDecimal(1.1);
var y = BigDecimal(0.1);
println(x + y);

And I still get an imprecise result.

Is there something I am not doing right in Scala?

Maybe I should use Groovy to maximise readability (it uses decimals by default)?

Upvotes: 31

Views: 36647

Answers (6)

overthink
overthink

Reputation: 24443

I know this question is old and answered, but another option, if you're open to different languages (as the OP seemed to be), would be to use Clojure. Clojure has, IMO, some of the simplest syntax for BigDecimal math (note the trailing Ms -- that indicates BigDecimal):

user=> (def x 1.1M)
#'user/x
user=> (def y 1.1M)
#'user/y
user=> (def z (* x (.pow y 2)))
#'user/z
user=> z
1.331M
user=> (type z)
java.math.BigDecimal

I like Clojure for math since it defaults to precision in many cases, e.g. its use of Ratio:

user=> (/ 60 14)
30/7
user=> (type (/ 60 14))
clojure.lang.Ratio

Upvotes: 2

Alexander Azarov
Alexander Azarov

Reputation: 13221

You can store values as Integer/String (without precision) internally and use scale (this is a transcript from Scala REPL):

scala> val Scale = 2
Scale: Int = 2

scala> val x = BigDecimal(110, Scale)
x: scala.math.BigDecimal = 1.10

scala> val y = BigDecimal(303, Scale)
y: scala.math.BigDecimal = 3.03

scala> (x+y, (x+y).scale)
res0: (scala.math.BigDecimal, Int) = (4.13,2)

scala> (x*2, (x*2).scale)
res1: (scala.math.BigDecimal, Int) = (2.20,2)

Or if you want to parse a string, you can control rounding:

scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.FLOOR)      
z: scala.math.BigDecimal = 8.93

scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.CEILING)
z: scala.math.BigDecimal = 8.94

Upvotes: 7

Kevin Wright
Kevin Wright

Reputation: 49695

Scala is most definitely the same as Java in this respect.

As per Joachim's answer, writing val x = BigDecimal(1.1)

is equivalent to writing

val d : Double = 1.1
val x = BigDecimal(d)

The problem, of course, is that the Double d ALREADY has the rounding error, so you're initialising x with bad data.

Use the constructor that accepts a string instead, and all will be fine.

Given your example, you'd also be better off using vals instead of vars, and you can safely leave the semicolons off in Scala as well.

Upvotes: 13

Eastsun
Eastsun

Reputation: 18859

scala> implicit def str2tbd(str: String) = new {
     |     def toBD = BigDecimal(str)
     | }
str2tbd: (str: String)java.lang.Object{def toBD: scala.math.BigDecimal}

scala> var x = "1.1".toBD
x: scala.math.BigDecimal = 1.1

scala> var y = "0.1".toBD
y: scala.math.BigDecimal = 0.1

scala> x + y
res0: scala.math.BigDecimal = 1.2

scala> implicit def str2bd(str: String) = BigDecimal(str)
str2bd: (str: String)scala.math.BigDecimal

scala> x + y + "1.2345566"
res1: scala.math.BigDecimal = 2.4345566

scala>

Upvotes: 6

Jesper
Jesper

Reputation: 206776

Change your Scala code to this:

var x = BigDecimal("1.1");   // note the double quotes
var y = BigDecimal("0.1");
println(x + y);

and it will work just like it does in Java.

Upvotes: 36

Joachim Sauer
Joachim Sauer

Reputation: 308001

I don't know Scala, but in Java new BigDecimal(1.1) initializes the BigDecimal with a double value and thus it is not exactly equal to 1.1. In Java you have to use new BigDecimal("1.1") instead. Maybe that will help in Scala as well.

Upvotes: 40

Related Questions