Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it safe to use comparison operators on BigDecimal in groovy/grails?

The Java way to compare two BigDecimals is to use the compareTo() method, and check if the result is -1, 0 or 1.

BigDecimal a = new BigDecimal("1.23")
BigDecimal b = new BigDecimal("3.45")
if (a.compareTo(b) > 0)) { }

I have seen that some people are using this format in grails:

 if (a > b) {  }

Does this work correctly? I.e. will it get the decimals correct, or is it converting to float or similar and comparing that?

How about using "==" vs using equals()?

What is the consequence of something like this:

BigDecimal a = new BigDecimal("1.00")
BigDecimal b = new BigDecimal("1")
assert (a==b)

It seems to work, but we have had it so engrained in Java not to do this kind of thing.

How about +=? e.g.

a+=b?

Would this be the same as

a = a.add(b)

Where does one find this kind of thing out? I have two groovy books, and unfortunately neither mention BigDecimal comparison or arithmetic, only the conversion/declaration.

like image 850
John Little Avatar asked Sep 28 '22 00:09

John Little


1 Answers

Groovy allows overloading of operators. When a type implements certain methods then you can use a corresponding operator on that type.

For + the method to implement is plus, not add.

For greater than or less than comparisons, Groovy looks for a compareTo method on the object, and for == it looks for a method named equals. (If you want to compare references as if using == in Java, you have to use is.)

Here's a table of common math operators and the method used to overload them:

Operator     Method
a + b        a.plus(b)
a - b        a.minus(b)
a * b        a.multiply(b)
a / b        a.divide(b)
a++ or ++a   a.next()
a-- or --a   a.previous()
a << b       a.leftShift(b)

You can see that BigDecimal overloads some of these methods (you get operator overloading for plus, minus, multiply, and divide, but not for next, previous, or leftShift):

groovy:000> BigDecimal.methods*.name
===> [equals, hashCode, toString, intValue, longValue, floatValue, doubleValue,
byteValue, shortValue, add, add, subtract, subtract, multiply, multiply, divide,
 divide, divide, divide, divide, divide, remainder, remainder, divideAndRemainde
r, divideAndRemainder, divideToIntegralValue, divideToIntegralValue, abs, abs, m
ax, min, negate, negate, plus, plus, byteValueExact, shortValueExact, intValueEx
act, longValueExact, toBigIntegerExact, toBigInteger, compareTo, precision, scal
e, signum, ulp, unscaledValue, pow, pow, movePointLeft, movePointRight, scaleByP
owerOfTen, setScale, setScale, setScale, stripTrailingZeros, toEngineeringString
, toPlainString, round, compareTo, getClass, notify, notifyAll, wait, wait, wait
, valueOf, valueOf, valueOf]

You get ==, >, <, >=, and <= based on how your object implements equals and compareTo.

So the operator is causing methods declared already in BigDecimal, or added to BigDecimal by groovy, to get called. It is definitely not doing any kind of conversion to a primitive type like float in order to be able to use the operators on primitives.

The table is taken from this developerworks article by Andrew Glover and Scott Davis, which has more details and includes example code.

like image 187
Nathan Hughes Avatar answered Oct 05 '22 07:10

Nathan Hughes