Comparing Fixed Decimals and BigDecimals

The BigDecimal compareTo() method can be used in the same way as the BigInteger compareTo() method.

Detailed information on how this can be used is available in the section on Integers, but in summary, when comparing two decimal fields x and y, instead of using

x <relational_operator> y

you must use

x.compareTo(y) <relational_operator> 0

This will return the value that you expect the first expression to return. For example, if you want to use the expression

x <= y

you should write

x.compareTo(y) <= 0

As with all divide operations, care should be taken to ensure that the divisor is not zero, otherwise an exception will be generated. If there is a problem with the script so that there are no planets in the list, then the planetCount variable will be 0, and our divide operation will cause an exception. Therefore, scripts should be programmed defensively to protect against such things. The following example here is a version of the script that checks that the planetCount is greater than or equal to one using the BigDecimal compareTo() method:

var totalKgs    = ScriptUtil.createBigDecimal("0.0");
var planetCount = ScriptUtil.createBigDecimal ("0");
var one         = ScriptUtil.createBigDecimal ("1");
for (var iterator=planets.planetList.listIterator(); iterator.hasNext(); )
{
     var planet  = iterator.next();
     totalKgs    = totalKgs.add(planet.weightKgs);
     planetCount = planetCount.add(one);
}
if (planetCount.compareTo(one) >= 0)
{
     // 30 significant digits, rounding 0.5 up
     planets.averageWeight = totalKgs.divide(planetCount,30,RoundingMode.HALF_UP);
}	
else
{
     planets.averageWeight = ScriptUtil.createBigDecimal("0.0");
}

When creating BigDecimal objects with the ScriptUtil.createBigDecimal() method, the number to create can be passed as a String or a Numeric type. It is important to be aware that the JavaScript numeric type is only accurate to about 16 significant figures, so when initializing BigDecimal types, if great accuracy is required, the value should be passed as a String. If the value is not passed in a String, the value entered in the script will first be converted to a Numeric type, which may introduce some rounding errors, even for values that you would not expect it to. For example, the value 0.1 may not be stored exactly in a Numeric type, as it results in a recurring sequence of binary digits when expressed in binary: 0.00011001100110011001100110011...

When rounding BigDecimal variables, you need to be aware of how BigDecimal values are stored. They are stored as two integer values: unscaled value and scale. For example, if the number 123.456789 is stored as a BigDecimal value, it will have an unscaled value of 123456789 and a scale of 6. The value of a BigDecimal is:

(unscaled_value) * 10-scale

The setScale() method is used to round values. If the setScale() method is called with a scale of 10, then the scale would become 10 and the unscaled value would be changed to 1234567890000 so that the number still has the same numerical value. However, it would actually represent 123.4567890000. When reducing the number of decimal places, for example, to 3, rounding must take place often. You must tell setScale() how you want to round the value, otherwise an exception will be generated at runtime. To convert to 3 decimals using the HALF_UP rounding strategy, write:

roundDecimal = decimal.setScale(3, RoundingMode.HALF_UP);

This converts, in our example, 123.4567890000 to 123.457.

For more information on BigDecimal, see Fixed Point Decimal (BigDecimal) Methods, or the Java Documentation, available at the following web site:

http://download.oracle.com/javase/6/docs/api/java/math/BigDecimal.html