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)?
BigDecimal represents decimal floating-point numbers of arbitrary precision. By default, the precision approximately matches that of IEEE 128-bit floating point numbers (34 decimal digits, HALF_EVEN rounding mode).
A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale.
BigDecimal. compareTo(BigDecimal val) compares the BigDecimal Object with the specified BigDecimal value. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method.
add(BigDecimal val) is used to calculate the Arithmetic sum of two BigDecimals. This method is used to find arithmetic addition of large numbers of range much greater than the range of largest data type double of Java without compromising with the precision of the result.
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.
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.
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 val
s instead of var
s, and you can safely leave the semicolons off in Scala as well.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With