Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Canonical representation of a BigDecimal

What is the simplest way to reduce a Java BigDecimal containing an arbitrary value to a canonical form so that two BigDecimal's representing the same number will compare equal using the equals() method?

I am parsing my numbers from arbitrary strings using code like this:

BigDecimal x = new BigDecimal(string1, MathContext.DECIMAL64);
BigDecimal y = new BigDecimal(string2, MathContext.DECIMAL64);

Since (string1, string2) are arbitrary, they could be, e.g., ("1", "1.0000") or ("-32.5", "1981")...

What I'm looking for is the simplest (shortest/cleanest code) implementation of the method canonicalize for which the above assertion

assert x.compareTo(y) != 0 ||
    (canonicalize(x).equals(canonicalize(y)) && 
     x.compareTo(canonicalize(x)) == 0 && y.compareTo(canonicalize(y)) == 0);

will succeed...:

public static BigDecimal canonicalize(BigDecimal b) {
    // TODO:
}
like image 527
0xbe5077ed Avatar asked Oct 13 '14 20:10

0xbe5077ed


People also ask

What is the value of the number represented by The BigDecimal?

The value of the number represented by the BigDecimal is therefore (unscaledValue × 10 -scale). The BigDecimal class provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion. The toString() method provides a canonical representation of a BigDecimal.

What are the parameters of BigDecimal method?

Parameters: The method accepts a single parameter val of Double data type and refers to the value that needs to be translated into a BigDecimal value. Return value: The method returns a BigDecimal value which is equal to or approximately equal to Double val.

What is The BigDecimal class used for?

The BigDecimal class provides operations on double numbers for arithmetic, scale handling, rounding, comparison, format conversion and hashing.

How do I round a BigDecimal in engineering notation?

The toEngineeringString () method may be used for presenting numbers with exponents in engineering notation, and the setScale method may be used for rounding a BigDecimal so it has a known number of digits after the decimal point. The digit-to-character mapping provided by Character.forDigit is used. string representation of this BigDecimal.


2 Answers

If you want to know if two BigDecimals are equal regardless of scale, just use .compareTo()

public static boolean bigDecimalEquals(BigDecimal b1, BigDecimal b2) {
    return b1.compareTo(b1) == 0;
}

It specifically recommends this in the Javadoc

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. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=).


If you actually want to convert the BigDecimal so that .equals() will work, just use the setScale method.

like image 165
durron597 Avatar answered Sep 25 '22 22:09

durron597


Use stripTrailingZeros(). This returns an equivalent BigDecimal with the scale minimized and is the simplest way to get a canonical representation. It's better than setScale() because it avoids any issues with rounding.

like image 45
Sam Avatar answered Sep 22 '22 22:09

Sam