Monday, November 1, 2021

Java Tutorial: BigDecimal Class

Chapters

BigDecimal Class

BigDecimal Class is immutable, arbitrary-precision signed decimal numbers that consists of two parts: unscaled value and a scale. Unscaled value is simply an arbitrary precision integer. Scale refers to the number of fractional part of a decimal number. For example, 1.234, unscaled value of this decimal is 1234 and this decimal has a scale of 3.

Common usage of BigDecimal is to operate on financial-related computations that require high-precision arithmetic like currency computations.

BigDecimal Constructors

BigInteger has lots of constructors. Although, I'm only gonna demonstrate some of them that are easy to understand and implement. Other constructors can be seen in the documentation.
import java.math.BigDecimal;
import java.math.BigInteger;

public class SampleClass{

  public static void main(String[] args){
  
    char[] chars = {'2','3','.','1','2','3','4'};
    
    //This constructor accepts char array,
    //convert to string then convert to
    //decimal. NumberFormatException will be
    //thrown if the string can't be converted
    //to decimal
    BigDecimal bd = new BigDecimal(chars);
    System.out.println("output1: " + bd.toString());
    
    //This constructor translates double value
    //int BigDecimal. Throws NumberFormatException
    //if the argument is infinite or NaN.
    bd = new BigDecimal(20.335679088);
    System.out.println("output2: " + bd.toString());
    
    //This constructor translates String value into
    //BigDecimal. Throws NumberFormatException
    //if the string can't be translated to decimal
    bd = new BigDecimal("15.660098237");
    System.out.println("output3: " + bd.toString());
    
    //This constructor translates BigInteger into
    //BigDecimal unscaled value with scale of 3.
    bd = new BigDecimal(new BigInteger("123456"), 3);
    System.out.println("output4: " + bd.toString());
  }
}

Result
output1: 23.1234
output2: 20.33567908799... //too long
output3: 15.66098237
output4: 123.456

BigDecimal Operations

Standard operators like "+" don't work with BigDecimal. However, BigDecimal has methods that are analogous to standard operators. I'm gonna demonstrate some of them here.
import java.math.BigDecimal;

public class SampleClass{

  public static void main(String[] args){
  
    BigDecimal bd1 = new BigDecimal("3.209384756");
    BigDecimal bd2 = new BigDecimal("0.223948576");
    BigDecimal result = null;
    
    //add() method adds two BigDecimal
    result = bd1.add(bd2);
    System.out.println(bd1.toString() + " + " + bd2.toString() +
                       " = " + result);
    
    //subtract() method substract two BigDecimal
    result = bd1.subtract(bd2);
    System.out.println(bd1.toString() + " - " + bd2.toString() +
                       " = " + result);
    
    //multiply() method multiplies two BigDecimal
    result = bd1.multiply(bd2);
    System.out.println(bd1.toString() + " * " + bd2.toString() +
                       " = " + result);
    
    //divide() method divides two BigDecimal
    result = bd1.divide(bd2);
    System.out.println(bd1.toString() + " / " + bd2.toString() +
                       " = " + result);
  }
}

Result
3.209384756 + 0.223948576 = 3.433333332
3.209384756 - 0.223948576 = 2.985436180
3.209384756 - 0.223948576 = 0.718737145942307456
Exception in thread "main" java.lang.ArithmeticException:
Non-terminating decimal expansion.
The exception above means that the result of divide() method is an infinite repetition. We can avoid that by using another form of divide() method with MathContext parameter.
import java.math.BigDecimal;
import java.math.MathContext;

public class SampleClass{

  public static void main(String[] args){
  
    BigDecimal bd1 = new BigDecimal("3.209384756");
    BigDecimal bd2 = new BigDecimal("0.223948576");
    BigDecimal result = null;
    
    //This form of divide() method takes a MathContext
    //argument that limit the digits in the returned
    //value by 6
    result = bd1.divide(bd2,new MathContext(6));
    System.out.println(bd1.toString() + " / " + bd2.toString() +
                       " = " + result);
  }
}

Result
3.209384756 + 0.223948576 = 14.3309
MathContext has constants that we can use to specify the precision(number of digits) of our BigDecimal. These are the constants:
DECIMAL128
DECIMAL32
DECIMAL64
UNLIMITED
Read their descrptions in this documentation. This example demonstrates one of the constants above.
import java.math.BigDecimal;
import java.math.MathContext;

public class SampleClass{

  public static void main(String[] args){
  
    BigDecimal bd1 = new BigDecimal("3.209384756");
    BigDecimal bd2 = new BigDecimal("0.223948576");
    BigDecimal result = null;
    
    //DECIMAL32 constant has precision setting matching
    //the precision of the IEEE 754-2019 decimal32 format,
    //7 digits, and a rounding mode of HALF_EVEN.
    result = bd1.divide(bd2,MathContext.DECIMAL32);
    System.out.println(bd1.toString() + " / " + bd2.toString() +
                       " = " + result);
  }
}

Result
3.209384756 + 0.223948576 = 14.33090

Rounding-off BigDecimal Value

To round-off BigDecimal value, we need to specify the RoundingMode that we want in our BigDecimal object. RoundingMode can be specified in some constructors and methods.
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class SampleClass{

  public static void main(String[] args){
    
    BigDecimal bd = new BigDecimal("3.54");
    System.out.println("Exact Value: " + bd.toString());
    
    bd = new BigDecimal("3.54",
                    new MathContext(2, RoundingMode.CEILING));
    System.out.println("Ceiling Round-Off: " + bd.toString());
    
  }
}

Result
Exact Value: 3.54
Ceiling Round-Off: 3.6
Now, let's try specifying rounding mode in methods.
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class SampleClass{

  public static void main(String[] args){
    
    BigDecimal bd1 = new BigDecimal("3.55");
    BigDecimal bd2 = new BigDecimal("0.2");
    BigDecimal result = null;
    
    //This MathContext(int precision) constructor
    //uses RoundingMode.HALF_UP as its default
    //rounding mode
    result = bd1.add(bd2, new MathContext(2));
    System.out.println("HALF_UP RoundMode: " + result);
  }
}

Result:
HALF_UP RoundMode: 3.8
Converting BigDecimal Value to Primitive Type

BigDecimal value can be converted into primitive type. However, typecasting principles are still applied during conversion.
import java.math.BigDecimal;

public class SampleClass{

  public static void main(String[] args){
  
    BigDecimal bd = new BigDecimal("253.3353");
    
    //doubleValue() converts BigDecimal value
    //into double primitive
    double doubleVal = bd.doubleValue();
    
    //intValue() converts BigDecimal value
    //into int primitive
    int intVal = bd.intValue();
    
    System.out.println("double: " + doubleVal);
    System.out.println("int: " + intVal);
  }
}

Result
double: 253.3353
int: 253
negate() Method

negate() method flips BigDecimal sign from positive to negative and vice-versa.
import java.math.BigDecimal;

public class SampleClass{

  public static void main(String[] args){
    BigDecimal bd1 = new BigDecimal("-22.22");
    BigDecimal bd2 = new BigDecimal("34.43");
    
    System.out.println("bd1 negate: " + bd1.negate());
    System.out.println("bd2 negate: " + bd2.negate());
    
  }
}

Result
bd1 negate: 22.22
bd2 negate: -34.43

No comments:

Post a Comment