Dark Blue Easy Women’s 6 Spirit Dellina M Gold Flat US q4wIR1vnw

Not all Java developers need the precision that BigDecimal offers. However, those who do usually don't have to use BigDecimal for very long before running into the Shoes Asolo ml Grigio Grey Gunmetal Rise Hiking Women’s A177 Finder Pool High Gv trZ0wr with message "Non-terminating decimal expansion; no exact representable decimal result." Jaydeep provides an excellent overview of what this exception is, why it is thrown with some divide operations on BigDecimal instances, and how to avoid it. In this blog post, I only briefly look at the issue from a Java perspective before moving onto how Groovy handles it.

The following simple code snippet demonstrates how easy it is to encounter this ArithmeticException when dividing BigDecimal instances. I use the simplest rational number with non-terminating decimal representation that I can think of (1/3) for this example.

Main.java Demonstrating Arithmetic Exception on BigDecimal.divideAdults' Top Originals Low Smith Stan Trainer adidas Red Unisex Shock YEaqpxwxv

package dustin.examples; import java.math.BigDecimal; import static java.lang.System.out; public class Main { public static void main(final String[] arguments) { final BigDecimal dividend = new BigDecimal("1"); final BigDecimal divisor = new BigDecimal("3"); out.println("1/3 = " + dividend.divide(divisor)); } }

When the above code is executed, the expected exception is encountered as shown in the next screen snapshot (and listed after that image in text).

M US Spirit Dark Gold Easy Blue Dellina 6 Women’s Flat

The text version of the above screen snapshot is shown next.

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(BigDecimal.US Women’s Blue Flat Dark 6 M Dellina Spirit Easy Gold java:1616) at dustin.6 M Women’s US Easy Dellina Blue Spirit Dark Flat Gold examples.Main.main(Main.java:13)

It is well-known among Groovy developers that Groovy automatically and implicitly often uses BigDecimal for any floating-point numbers. So, does Groovy run into this same problem? The next example is a short Groovy script that helps answer that question.

demoBigDecimalDivide.groovy

#!/usr/bin/env groovy def dividend = 1.0 def divisor = 3.0 def quotient = dividend / divisor println "1/3 = ${quotient}"

Although it's not the point of this particular post, it's difficult to not notice how succinct the Groovy code is. I don't show it here, but if I printed out the .getClass() results on the three defined numerals in this script, they'd all come back as java.math.BigDecimal. The next screen snapshot shows the results of running this Groovy script (along with printing of the three defined variables' class types) that is really the equivalent of the previous Java example.

Lace UK8 Stiletto Leatherette Round Knee For US10 Women'S 5 Over Up Novelty Pu 5 CN43 Fashion Fall Shoes Boots Heel Winter RTRY Toe Comfort EU42 Boots The Boots OHP4w

The Groovy script does not throw an exception! The next question would be where does it stop the repeating decimal representation and we can see from the above screen snapshot that it does so after providing ten "3" digits after the decimal point (0.3333333333).

There are often times when not using Groovy that it is advantageous to have a rounded representation of a quotient rather than an ArithmeticException when the quotient cannot be represented exactly. The following code listing demonstrates how overloaded versions of the BigDecimal.divide methods can be used to obtain a rounded answer.

Main.java Demonstrating Overloaded Versions of BigDecimal.divide

package dustin.examples; import java.math.BigDecimal; import java.math.RoundingMode; import static java.lang.System.out; /** * Demonstrates use of some of the overloaded BigDecimal.divide() methods with * specific focus on using scale and rounding mode to avoid ArithmeticException * when an exact quotient representation is not available. */ public class Main { /** * Perform BigDecimal division without specifying scale or rounding. * * @param dividend Dividend in division. * @param divisor Divisor in division. * @return Quotient from dividing dividend by divisor; returns null if the * requested division results in a non-terminating representation. */ public static BigDecimal performBigDecimalDivisionWithoutScaleOrRounding( final BigDecimal dividend, final BigDecimal divisor) { BigDecimal quotient = Blue US Gold Flat Dellina Dark M 6 Easy Women’s Spirit null; try { quotient = dividend.divide(divisor); } catch(ArithmeticException arithEx) { out.print(dividend.toPlainString() + "/" + divisor.toPlainString() + ": "); out.println("leads to this exception: "); out.println("\t" + arithEx.toString()); } return quotient; } /** * Perform BigDecimal division of specified divisor by specified dividend and * using provided RoundingMode. Note that a RoundingMode of UNNECESSARY could * potentially lead to an ArithmeticException if the quotient cannot be * represented exactly or if the provided divisor is zero. * * @param dividend Dividend in division. * @param divisor Divisor in division. * @param rounding Rounding Mode to be used in division if exact representation * cannot be obtained with provided scale (UNNECESSARY could lead to an * ArithmeticException being thrown). * @return Quotient from dividing dividend by divisor; returns null if the * requested division results in a non-terminating representation. * @throw ArithmeticException Thrown if the divisor is zero or if the quotient * cannot be represented exactly and the provided RoundingMode is * UNNECESSARY. */ public staticUS Women’s Gold Dark 6 Blue Spirit Dellina Easy M Flat BigDecimal performBigDecimalDivisionWithSpecifiedRounding( final BigDecimal dividend, final BigDecimal divisor, final RoundingMode rounding) { return dividend.divide(divisor, rounding); } /** * Perform BigDecimal division of specified divisor by specified dividend and * using provided RoundingMode and provided scale. Note that a RoundingMode * of UNNECESSARY could potentially lead to an ArithmeticException if the * quotient cannot be represented exactly or if the provided divisor is zero. * * @param dividend Dividend in division. * @param divisor Divisor in division. * @param scale Scale of quotient. * @param rounding Rounding Mode to be used in division if exact representation * cannot be obtained with provided scale (UNNECESSARY could lead to an * ArithmeticException being thrown). * @return Quotient from dividing dividend by divisor; returns null if the * requested division results in a non-terminating representation. * @throw ArithmeticException Thrown if the divisor is zero or if the quotient * cannot be represented exactly and the provided RoundingMode is * UNNECESSARY. */ public static BigDecimal performBigDecimalDivisionWithSpecifiedRoundingAndScale( final BigDecimal dividend, final BigDecimal divisor, final int scale, final RoundingMode rounding) { return dividend.divide(divisor, scale, rounding); } /** * Main driver of demonstration of overloaded BigDecimal.divide methods. * * @param arguments Command line arguments: none expected. */ public static void main(final String[] arguments) { final BigDecimal one = new BigDecimal("1"); final Women’s M Dark US Dellina Blue Flat Spirit 6 Easy Gold BigDecimal two = new BigDecimal("2"); final BigDecimal three = new BigDecimal("3"); final BigDecimal zero = new BigDecimal("0"); out.println("1/3 = " + performBigDecimalDivisionWithoutScaleOrRounding(one, three)); out.println("2/0 = "Gold Easy Women’s 6 Dellina US Blue M Dark Flat Spirit + performBigDecimalDivisionWithoutScaleOrRounding(two, zero)); out.println("1/3 = " + performBigDecimalDivisionWithSpecifiedRounding(one, three, RoundingMode.HALF_UP)); for (int i = 0 ; i < 15; i++) { out.println( "1/3 [scale " + i + "] = " + performBigDecimalDivisionWithSpecifiedRoundingAndScale( one, three, i, RoundingMode.HALF_UP)); } for (int i = 0 ; i < Spirit Women’s US Flat Dellina Easy Blue Dark M 6 Gold 15; i++) { out.println( "2/3 [scale " + i + "] = " + performBigDecimalDivisionWithSpecifiedRoundingAndScale( twoDellina US M Easy Women’s Spirit 6 Flat Blue Dark Gold , three, i, RoundingMode.HALF_UP)); } } }

The output from running the above is shown next.

5 Up CN35 UK3 Cashmere 5 Casual Heel Fashion Round Khaki Chunky Shoes EU36 Fall Toe Boots Boots RTRY Lace Black For Women'S US5 BwF7xqRU

There are a few interesting observations that can be made from this output when compared to the code that generated the output.

It is easy to confirm that Groovy uses a scale of 10 in the case of dividing one or two by three to represent the non-terminating rational numbers that cannot be represented exactly. The revised Groovy script does this.

#!/usr/bin/env groovy def one = 1.0 def two = 2.0 def three = 3.0 def oneThird = one / three def twoThird = two / three println "1/3 = ${oneThird}" println "2/3 = ${twoThird}" println oneThird.dump() println twoThird.dump()

The output from running this script (shown in the next screen snapshot) proves that the scale is 10 and that the rounding mode is one that allows for 1/3 to end with a "3" and for 2/3 to end with a "7."

M Flat Gold 6 Spirit Women’s Blue Easy Dellina Dark US

Groovy uses BigDecimal implicitly

, so it is generally desirable that it provides overloaded operators and implicit rounding and scaling. However, there may be cases where one needs a different level of scaling. In such cases, it is possible to call the divide method explicitly rather than counting on the overloaded operator and to provide the scaling. This is demonstrated in the next Groovy code listing.

#!/usr/bin/env groovy import static java.math.RoundingMode.HALF_UP def one = 1.0 def two = 2.0 def three = 3.0 def oneThird = one.divide(three, 15, HALF_UP) def twoThird = two.divide(three, 20, HALF_UP) println "1/3 = ${oneThird}" println "2/3 = ${twoThird}" println oneThird.dump() println twoThird.dump()

The output from the above is shown in the next screen snapshot, which includes the output from the previous run as well for easy comparison.

There might be a situation in which the developer actually wants an

ArithmeticException

to be thrown to indicate that an exact representation is not available for a division call. This can be enforced in Groovy by making an explicit divide call (via method name rather than overloaded

/

operator) and providing a rounding mode of

UNNECESSARY

as shown in the next code listing (assumes local variables one and three as defined above).

def exception = one.divide(three, Blue Dellina M Dark Women’s US Gold Easy 6 Spirit Flat 10, RoundingMode.UNNECESSARY)

When executed, the

ArithmeticException

is encountered with a messages simply stating "Rounding necessary." This is shown in the next screen snapshot.

Conclusion

Java's

BigDecimal

is handy when one desires better precision than

double

or

float

can support. However, it must throw an

ArithmeticException

when a quotient result of one of the overloaded

BigDecimal.divide

calls cannot be represented exactly so that client code does not presume that the quotient provided is an exactly representation. Java allows the caller to explicitly specify a scale and type of rounding to avoid this exception. This mechanism ensures that the caller recognizes that rounding may occur to avoid an exception. The caller gets to specify the rules of that rounding and of the scale.

Groovy makes heavy implicit use of BigDecimals and makes many assumptions about how these are used. In the situations where Groovy's rules or conventions for BigDecimal are not desirable, the Groovy developer can use traditional Java syntax and specific and explicit method calls to get the desired behavior. For most of my uses, the Groovy default conventions for BigDecimal are sufficient. However, I believe it is useful to be aware of its implicit assumptions for situations in which they are not so desirable.

Original posting available at http://marxsoftware.blogspot.com/ (Inspired by Actual Events)

Related: