When calculating money, interest rates, or any value where 0.1 + 0.2 must equal exactly 0.3, floating-point errors are unacceptable. BigDecimal provides arbitrary-precision decimal arithmetic, representing decimal numbers exactly for financial and scientific calculations.

Creating BigDecimal

Create BigDecimal from strings (preferred) or primitive values.

Create.java
// Create BigDecimal

import java.math.BigDecimal;
import java.math.BigInteger;

public class Create {
    public static void main(String[] args) {
        // From string (recommended)
        BigDecimal bd1 = new BigDecimal("10.5");
        System.out.println("From string: " + bd1);

        // From double (avoid - precision issues)
        BigDecimal bd2 = new BigDecimal(10.5);
        System.out.println("From double (shows precision issues): " + bd2);

        // Proper way from double
        BigDecimal bd3 = BigDecimal.valueOf(10.5);
        System.out.println("valueOf(double): " + bd3);

        // From int
        BigDecimal bd4 = new BigDecimal(42);
        System.out.println("From int: " + bd4);

        // From long
        BigDecimal bd5 = BigDecimal.valueOf(123456789L);
        System.out.println("From long: " + bd5);

        // From BigInteger
        BigInteger bi = new BigInteger("12345");
        BigDecimal bd6 = new BigDecimal(bi);
        System.out.println("From BigInteger: " + bd6);

        // With scale
        BigDecimal bd7 = new BigDecimal(bi, 2);  // 123.45
        System.out.println("From BigInteger with scale 2: " + bd7);

        // Constants
        System.out.println("\nConstants:");
        System.out.println("ZERO: " + BigDecimal.ZERO);
        System.out.println("ONE: " + BigDecimal.ONE);
        System.out.println("TEN: " + BigDecimal.TEN);

        // Very precise numbers
        String precise = "3.14159265358979323846264338327950288419716939937510";
        BigDecimal pi = new BigDecimal(precise);
        System.out.println("\nPrecise pi: " + pi);

        // Unscaled value and scale
        System.out.println("\nUnscaled value and scale:");
        BigDecimal num = new BigDecimal("123.45");
        System.out.println("Number: " + num);
        System.out.println("Unscaled value: " + num.unscaledValue());
        System.out.println("Scale: " + num.scale());
        System.out.println("Precision: " + num.precision());

        // Scientific notation
        System.out.println("\nScientific notation:");
        BigDecimal sci1 = new BigDecimal("1.23E+5");
        System.out.println("1.23E+5: " + sci1);
        
        BigDecimal sci2 = new BigDecimal("4.56E-3");
        System.out.println("4.56E-3: " + sci2);

        // Convert to other types
        System.out.println("\nConvert to other types:");
        BigDecimal bd = new BigDecimal("42.75");
        System.out.println("BigDecimal: " + bd);
        System.out.println("intValue: " + bd.intValue());
        System.out.println("longValue: " + bd.longValue());
        System.out.println("floatValue: " + bd.floatValue());
        System.out.println("doubleValue: " + bd.doubleValue());
        System.out.println("toBigInteger: " + bd.toBigInteger());

        // String representations
        System.out.println("\nString representations:");
        BigDecimal num2 = new BigDecimal("1234.5600");
        System.out.println("toString: " + num2.toString());
        System.out.println("toPlainString: " + num2.toPlainString());
        System.out.println("toEngineeringString: " + num2.toEngineeringString());

        // stripTrailingZeros
        System.out.println("\nStrip trailing zeros:");
        BigDecimal withZeros = new BigDecimal("123.4500");
        System.out.println("Original: " + withZeros);
        System.out.println("Stripped: " + withZeros.stripTrailingZeros());

        // Compare double vs BigDecimal precision
        System.out.println("\nDouble vs BigDecimal:");
        double d1 = 0.1;
        double d2 = 0.2;
        System.out.println("Double: 0.1 + 0.2 = " + (d1 + d2));
        
        BigDecimal bd8 = new BigDecimal("0.1");
        BigDecimal bd9 = new BigDecimal("0.2");
        System.out.println("BigDecimal: 0.1 + 0.2 = " + bd8.add(bd9));
    }

    //help h1
    // new BigDecimal(String) - from string (recommended)
    // BigDecimal.valueOf(double) - from double
    // new BigDecimal(int/long) - from integer
    // BigDecimal.ZERO, ONE, TEN - constants
    // .scale() - decimal places
    // .precision() - total digits
    // .unscaledValue() - value without decimal point
    // Always use String constructor for exact values
    //end
}
BigDecimal An immutable class for arbitrary-precision decimal numbers that avoids the rounding errors inherent in float and double.
String constructor Always use new BigDecimal("0.1") instead of new BigDecimal(0.1) to avoid inheriting float/double imprecision.

Arithmetic Operations

Perform calculations with precise decimal arithmetic.

Arithmetic.java
// Arithmetic with MathContext

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class Arithmetic {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("10.5");
        BigDecimal b = new BigDecimal("3.25");
        
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println();

        // Addition
        System.out.println("Addition:");
        BigDecimal sum = a.add(b);
        System.out.println("a + b = " + sum);

        // Subtraction
        System.out.println("\nSubtraction:");
        BigDecimal diff = a.subtract(b);
        System.out.println("a - b = " + diff);

        // Multiplication
        System.out.println("\nMultiplication:");
        BigDecimal product = a.multiply(b);
        System.out.println("a * b = " + product);

        // Division (requires scale and rounding)
        System.out.println("\nDivision:");
        BigDecimal quotient = a.divide(b, 2, RoundingMode.HALF_UP);
        System.out.println("a / b = " + quotient + " (2 decimals, HALF_UP)");

        // Division with MathContext
        MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
        BigDecimal quot2 = a.divide(b, mc);
        System.out.println("a / b = " + quot2 + " (10 sig figs, HALF_UP)");

        // Remainder
        System.out.println("\nRemainder:");
        BigDecimal remainder = a.remainder(b);
        System.out.println("a % b = " + remainder);

        // divideAndRemainder
        System.out.println("\ndivideAndRemainder:");
        BigDecimal[] divResult = a.divideAndRemainder(b);
        System.out.println("Quotient: " + divResult[0]);
        System.out.println("Remainder: " + divResult[1]);

        // Power
        System.out.println("\nPower:");
        BigDecimal base = new BigDecimal("2");
        BigDecimal power = base.pow(10);
        System.out.println("2^10 = " + power);

        // Negate
        System.out.println("\nNegate:");
        BigDecimal neg = a.negate();
        System.out.println("-a = " + neg);

        // Absolute value
        System.out.println("\nAbsolute value:");
        BigDecimal negative = new BigDecimal("-42.5");
        System.out.println("abs(-42.5) = " + negative.abs());

        // Plus (applies MathContext)
        System.out.println("\nPlus (applies MathContext):");
        MathContext mc2 = new MathContext(3, RoundingMode.HALF_UP);
        BigDecimal val = new BigDecimal("12.3456");
        System.out.println("Original: " + val);
        System.out.println("With MC(3): " + val.plus(mc2));

        // Chaining operations
        System.out.println("\nChaining:");
        BigDecimal result = new BigDecimal("5")
            .multiply(new BigDecimal("3"))
            .add(new BigDecimal("10"))
            .subtract(new BigDecimal("2"));
        System.out.println("5 * 3 + 10 - 2 = " + result);

        // Divide with exact division
        System.out.println("\nExact division:");
        try {
            BigDecimal x = new BigDecimal("10");
            BigDecimal y = new BigDecimal("2");
            BigDecimal exactQuot = x.divide(y);  // No rounding needed
            System.out.println("10 / 2 = " + exactQuot);
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide exactly: " + e.getMessage());
        }

        // Non-terminating division requires rounding
        System.out.println("\nNon-terminating division:");
        try {
            BigDecimal x = new BigDecimal("1");
            BigDecimal y = new BigDecimal("3");
            BigDecimal inexact = x.divide(y);  // Will throw exception
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
            BigDecimal x = new BigDecimal("1");
            BigDecimal y = new BigDecimal("3");
            BigDecimal rounded = x.divide(y, 10, RoundingMode.HALF_UP);
            System.out.println("1 / 3 with rounding: " + rounded);
        }

        // MathContext in operations
        System.out.println("\nMathContext in operations:");
        MathContext mc10 = new MathContext(10);
        BigDecimal a2 = new BigDecimal("1.234567890123");
        BigDecimal b2 = new BigDecimal("2.345678901234");
        
        BigDecimal sum2 = a2.add(b2, mc10);
        BigDecimal prod2 = a2.multiply(b2, mc10);
        
        System.out.println("Sum (10 sig figs): " + sum2);
        System.out.println("Product (10 sig figs): " + prod2);

        // Compound interest example
        System.out.println("\nCompound interest:");
        BigDecimal principal = new BigDecimal("1000");
        BigDecimal rate = new BigDecimal("0.05");
        int years = 10;
        
        BigDecimal amount = principal.multiply(
            BigDecimal.ONE.add(rate).pow(years)
        );
        amount = amount.setScale(2, RoundingMode.HALF_UP);
        
        System.out.println("Principal: $" + principal);
        System.out.println("Rate: " + rate.multiply(new BigDecimal("100")) + "%");
        System.out.println("Years: " + years);
        System.out.println("Amount: $" + amount);
        System.out.println("Interest: $" + amount.subtract(principal));
    }

    //help h1
    // .add(other) - addition
    // .subtract(other) - subtraction
    // .multiply(other) - multiplication
    // .divide(other, scale, roundingMode) - division
    // .divide(other, MathContext) - division with context
    // .remainder(other) - modulo
    // .pow(n) - power
    // .negate() - negation
    // .abs() - absolute value
    // Division always requires scale/rounding or MathContext
    // Immutable: operations return new BigDecimal
    //end
}

Scale and Precision

Control the number of decimal places and significant digits.

Scale.java
// Scale and precision

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Scale {
    public static void main(String[] args) {
        // Scale: number of digits to the right of decimal point
        // Precision: total number of significant digits
        
        BigDecimal num1 = new BigDecimal("123.45");
        System.out.println("Number: " + num1);
        System.out.println("Scale: " + num1.scale());
        System.out.println("Precision: " + num1.precision());
        System.out.println();

        BigDecimal num2 = new BigDecimal("0.0012");
        System.out.println("Number: " + num2);
        System.out.println("Scale: " + num2.scale());
        System.out.println("Precision: " + num2.precision());
        System.out.println();

        // setScale
        System.out.println("setScale:");
        String valueText = ;
        BigDecimal value = new BigDecimal(valueText);
        System.out.println("Original: " + value);
        
        BigDecimal rounded2 = value.setScale(2, RoundingMode.HALF_UP);
        System.out.println("2 decimals (HALF_UP): " + rounded2);
        
        BigDecimal rounded0 = value.setScale(0, RoundingMode.HALF_UP);
        System.out.println("0 decimals (HALF_UP): " + rounded0);
        
        BigDecimal rounded4 = value.setScale(4, RoundingMode.HALF_UP);
        System.out.println("4 decimals (HALF_UP): " + rounded4);

        // Increase scale (add trailing zeros)
        System.out.println("\nIncrease scale:");
        BigDecimal val = new BigDecimal("10.5");
        System.out.println("Original: " + val + " (scale: " + val.scale() + ")");
        BigDecimal increased = val.setScale(4, RoundingMode.UNNECESSARY);
        System.out.println("Scale 4: " + increased + " (scale: " + increased.scale() + ")");

        // Decrease scale (requires rounding)
        System.out.println("\nDecrease scale:");
        BigDecimal val2 = new BigDecimal("10.5678");
        System.out.println("Original: " + val2 + " (scale: " + val2.scale() + ")");
        BigDecimal decreased = val2.setScale(2, RoundingMode.HALF_UP);
        System.out.println("Scale 2: " + decreased + " (scale: " + decreased.scale() + ")");

        // stripTrailingZeros
        System.out.println("\nstripTrailingZeros:");
        BigDecimal withZeros = new BigDecimal("123.4500");
        System.out.println("Original: " + withZeros + " (scale: " + withZeros.scale() + ")");
        BigDecimal stripped = withZeros.stripTrailingZeros();
        System.out.println("Stripped: " + stripped + " (scale: " + stripped.scale() + ")");

        // movePointLeft and movePointRight
        System.out.println("\nmovePointLeft and movePointRight:");
        BigDecimal num = new BigDecimal("123.45");
        System.out.println("Original: " + num);
        System.out.println("Move point left 2: " + num.movePointLeft(2));
        System.out.println("Move point right 2: " + num.movePointRight(2));

        // scaleByPowerOfTen
        System.out.println("\nscaleByPowerOfTen:");
        BigDecimal base = new BigDecimal("1.5");
        System.out.println("Original: " + base);
        System.out.println("Scale by 10^2: " + base.scaleByPowerOfTen(2));
        System.out.println("Scale by 10^-2: " + base.scaleByPowerOfTen(-2));

        // Different rounding modes
        System.out.println("\nRounding modes:");
        BigDecimal roundVal = new BigDecimal("2.5");
        System.out.println("Value: " + roundVal);
        
        System.out.println("CEILING: " + roundVal.setScale(0, RoundingMode.CEILING));
        System.out.println("FLOOR: " + roundVal.setScale(0, RoundingMode.FLOOR));
        System.out.println("UP: " + roundVal.setScale(0, RoundingMode.UP));
        System.out.println("DOWN: " + roundVal.setScale(0, RoundingMode.DOWN));
        System.out.println("HALF_UP: " + roundVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_DOWN: " + roundVal.setScale(0, RoundingMode.HALF_DOWN));
        System.out.println("HALF_EVEN: " + roundVal.setScale(0, RoundingMode.HALF_EVEN));

        // Negative values
        System.out.println("\nRounding negative values:");
        BigDecimal negVal = new BigDecimal("-2.5");
        System.out.println("Value: " + negVal);
        System.out.println("HALF_UP: " + negVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_EVEN: " + negVal.setScale(0, RoundingMode.HALF_EVEN));

        // Financial rounding (2 decimals)
        System.out.println("\nFinancial rounding:");
        BigDecimal[] prices = {
            new BigDecimal("19.994"),
            new BigDecimal("19.995"),
            new BigDecimal("19.996")
        };
        
        for (BigDecimal price : prices) {
            BigDecimal rounded = price.setScale(2, RoundingMode.HALF_UP);
            System.out.println("$" + price + " -> $" + rounded);
        }

        // Precision control
        System.out.println("\nPrecision:");
        BigDecimal precise = new BigDecimal("123.456789");
        System.out.println("Original: " + precise);
        System.out.println("Precision: " + precise.precision());
        System.out.println("Scale: " + precise.scale());

        // ulp (unit in last place)
        System.out.println("\nulp:");
        BigDecimal val3 = new BigDecimal("1.5");
        System.out.println("Value: " + val3);
        System.out.println("ulp: " + val3.ulp());
    }

    //help h1
    // .scale() - get decimal places
    // .precision() - get total significant digits
    // .setScale(n, roundingMode) - set decimal places
    // .stripTrailingZeros() - remove trailing zeros
    // .movePointLeft(n), .movePointRight(n)
    // .scaleByPowerOfTen(n) - multiply by 10^n
    // RoundingMode: HALF_UP, HALF_EVEN, CEILING, FLOOR, etc.
    // Use setScale(2, HALF_UP) for currency
    //end
}
// Scale and precision

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Scale {
    public static void main(String[] args) {
        // Scale: number of digits to the right of decimal point
        // Precision: total number of significant digits
        
        BigDecimal num1 = new BigDecimal("123.45");
        System.out.println("Number: " + num1);
        System.out.println("Scale: " + num1.scale());
        System.out.println("Precision: " + num1.precision());
        System.out.println();

        BigDecimal num2 = new BigDecimal("0.0012");
        System.out.println("Number: " + num2);
        System.out.println("Scale: " + num2.scale());
        System.out.println("Precision: " + num2.precision());
        System.out.println();

        // setScale
        System.out.println("setScale:");
        String valueText = ;
        BigDecimal value = new BigDecimal(valueText);
        System.out.println("Original: " + value);
        
        BigDecimal rounded2 = value.setScale(2, RoundingMode.HALF_UP);
        System.out.println("2 decimals (HALF_UP): " + rounded2);
        
        BigDecimal rounded0 = value.setScale(0, RoundingMode.HALF_UP);
        System.out.println("0 decimals (HALF_UP): " + rounded0);
        
        BigDecimal rounded4 = value.setScale(4, RoundingMode.HALF_UP);
        System.out.println("4 decimals (HALF_UP): " + rounded4);

        // Increase scale (add trailing zeros)
        System.out.println("\nIncrease scale:");
        BigDecimal val = new BigDecimal("10.5");
        System.out.println("Original: " + val + " (scale: " + val.scale() + ")");
        BigDecimal increased = val.setScale(4, RoundingMode.UNNECESSARY);
        System.out.println("Scale 4: " + increased + " (scale: " + increased.scale() + ")");

        // Decrease scale (requires rounding)
        System.out.println("\nDecrease scale:");
        BigDecimal val2 = new BigDecimal("10.5678");
        System.out.println("Original: " + val2 + " (scale: " + val2.scale() + ")");
        BigDecimal decreased = val2.setScale(2, RoundingMode.HALF_UP);
        System.out.println("Scale 2: " + decreased + " (scale: " + decreased.scale() + ")");

        // stripTrailingZeros
        System.out.println("\nstripTrailingZeros:");
        BigDecimal withZeros = new BigDecimal("123.4500");
        System.out.println("Original: " + withZeros + " (scale: " + withZeros.scale() + ")");
        BigDecimal stripped = withZeros.stripTrailingZeros();
        System.out.println("Stripped: " + stripped + " (scale: " + stripped.scale() + ")");

        // movePointLeft and movePointRight
        System.out.println("\nmovePointLeft and movePointRight:");
        BigDecimal num = new BigDecimal("123.45");
        System.out.println("Original: " + num);
        System.out.println("Move point left 2: " + num.movePointLeft(2));
        System.out.println("Move point right 2: " + num.movePointRight(2));

        // scaleByPowerOfTen
        System.out.println("\nscaleByPowerOfTen:");
        BigDecimal base = new BigDecimal("1.5");
        System.out.println("Original: " + base);
        System.out.println("Scale by 10^2: " + base.scaleByPowerOfTen(2));
        System.out.println("Scale by 10^-2: " + base.scaleByPowerOfTen(-2));

        // Different rounding modes
        System.out.println("\nRounding modes:");
        BigDecimal roundVal = new BigDecimal("2.5");
        System.out.println("Value: " + roundVal);
        
        System.out.println("CEILING: " + roundVal.setScale(0, RoundingMode.CEILING));
        System.out.println("FLOOR: " + roundVal.setScale(0, RoundingMode.FLOOR));
        System.out.println("UP: " + roundVal.setScale(0, RoundingMode.UP));
        System.out.println("DOWN: " + roundVal.setScale(0, RoundingMode.DOWN));
        System.out.println("HALF_UP: " + roundVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_DOWN: " + roundVal.setScale(0, RoundingMode.HALF_DOWN));
        System.out.println("HALF_EVEN: " + roundVal.setScale(0, RoundingMode.HALF_EVEN));

        // Negative values
        System.out.println("\nRounding negative values:");
        BigDecimal negVal = new BigDecimal("-2.5");
        System.out.println("Value: " + negVal);
        System.out.println("HALF_UP: " + negVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_EVEN: " + negVal.setScale(0, RoundingMode.HALF_EVEN));

        // Financial rounding (2 decimals)
        System.out.println("\nFinancial rounding:");
        BigDecimal[] prices = {
            new BigDecimal("19.994"),
            new BigDecimal("19.995"),
            new BigDecimal("19.996")
        };
        
        for (BigDecimal price : prices) {
            BigDecimal rounded = price.setScale(2, RoundingMode.HALF_UP);
            System.out.println("$" + price + " -> $" + rounded);
        }

        // Precision control
        System.out.println("\nPrecision:");
        BigDecimal precise = new BigDecimal("123.456789");
        System.out.println("Original: " + precise);
        System.out.println("Precision: " + precise.precision());
        System.out.println("Scale: " + precise.scale());

        // ulp (unit in last place)
        System.out.println("\nulp:");
        BigDecimal val3 = new BigDecimal("1.5");
        System.out.println("Value: " + val3);
        System.out.println("ulp: " + val3.ulp());
    }

    //help h1
    // .scale() - get decimal places
    // .precision() - get total significant digits
    // .setScale(n, roundingMode) - set decimal places
    // .stripTrailingZeros() - remove trailing zeros
    // .movePointLeft(n), .movePointRight(n)
    // .scaleByPowerOfTen(n) - multiply by 10^n
    // RoundingMode: HALF_UP, HALF_EVEN, CEILING, FLOOR, etc.
    // Use setScale(2, HALF_UP) for currency
    //end
}
// Scale and precision

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Scale {
    public static void main(String[] args) {
        // Scale: number of digits to the right of decimal point
        // Precision: total number of significant digits
        
        BigDecimal num1 = new BigDecimal("123.45");
        System.out.println("Number: " + num1);
        System.out.println("Scale: " + num1.scale());
        System.out.println("Precision: " + num1.precision());
        System.out.println();

        BigDecimal num2 = new BigDecimal("0.0012");
        System.out.println("Number: " + num2);
        System.out.println("Scale: " + num2.scale());
        System.out.println("Precision: " + num2.precision());
        System.out.println();

        // setScale
        System.out.println("setScale:");
        String valueText = ;
        BigDecimal value = new BigDecimal(valueText);
        System.out.println("Original: " + value);
        
        BigDecimal rounded2 = value.setScale(2, RoundingMode.HALF_UP);
        System.out.println("2 decimals (HALF_UP): " + rounded2);
        
        BigDecimal rounded0 = value.setScale(0, RoundingMode.HALF_UP);
        System.out.println("0 decimals (HALF_UP): " + rounded0);
        
        BigDecimal rounded4 = value.setScale(4, RoundingMode.HALF_UP);
        System.out.println("4 decimals (HALF_UP): " + rounded4);

        // Increase scale (add trailing zeros)
        System.out.println("\nIncrease scale:");
        BigDecimal val = new BigDecimal("10.5");
        System.out.println("Original: " + val + " (scale: " + val.scale() + ")");
        BigDecimal increased = val.setScale(4, RoundingMode.UNNECESSARY);
        System.out.println("Scale 4: " + increased + " (scale: " + increased.scale() + ")");

        // Decrease scale (requires rounding)
        System.out.println("\nDecrease scale:");
        BigDecimal val2 = new BigDecimal("10.5678");
        System.out.println("Original: " + val2 + " (scale: " + val2.scale() + ")");
        BigDecimal decreased = val2.setScale(2, RoundingMode.HALF_UP);
        System.out.println("Scale 2: " + decreased + " (scale: " + decreased.scale() + ")");

        // stripTrailingZeros
        System.out.println("\nstripTrailingZeros:");
        BigDecimal withZeros = new BigDecimal("123.4500");
        System.out.println("Original: " + withZeros + " (scale: " + withZeros.scale() + ")");
        BigDecimal stripped = withZeros.stripTrailingZeros();
        System.out.println("Stripped: " + stripped + " (scale: " + stripped.scale() + ")");

        // movePointLeft and movePointRight
        System.out.println("\nmovePointLeft and movePointRight:");
        BigDecimal num = new BigDecimal("123.45");
        System.out.println("Original: " + num);
        System.out.println("Move point left 2: " + num.movePointLeft(2));
        System.out.println("Move point right 2: " + num.movePointRight(2));

        // scaleByPowerOfTen
        System.out.println("\nscaleByPowerOfTen:");
        BigDecimal base = new BigDecimal("1.5");
        System.out.println("Original: " + base);
        System.out.println("Scale by 10^2: " + base.scaleByPowerOfTen(2));
        System.out.println("Scale by 10^-2: " + base.scaleByPowerOfTen(-2));

        // Different rounding modes
        System.out.println("\nRounding modes:");
        BigDecimal roundVal = new BigDecimal("2.5");
        System.out.println("Value: " + roundVal);
        
        System.out.println("CEILING: " + roundVal.setScale(0, RoundingMode.CEILING));
        System.out.println("FLOOR: " + roundVal.setScale(0, RoundingMode.FLOOR));
        System.out.println("UP: " + roundVal.setScale(0, RoundingMode.UP));
        System.out.println("DOWN: " + roundVal.setScale(0, RoundingMode.DOWN));
        System.out.println("HALF_UP: " + roundVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_DOWN: " + roundVal.setScale(0, RoundingMode.HALF_DOWN));
        System.out.println("HALF_EVEN: " + roundVal.setScale(0, RoundingMode.HALF_EVEN));

        // Negative values
        System.out.println("\nRounding negative values:");
        BigDecimal negVal = new BigDecimal("-2.5");
        System.out.println("Value: " + negVal);
        System.out.println("HALF_UP: " + negVal.setScale(0, RoundingMode.HALF_UP));
        System.out.println("HALF_EVEN: " + negVal.setScale(0, RoundingMode.HALF_EVEN));

        // Financial rounding (2 decimals)
        System.out.println("\nFinancial rounding:");
        BigDecimal[] prices = {
            new BigDecimal("19.994"),
            new BigDecimal("19.995"),
            new BigDecimal("19.996")
        };
        
        for (BigDecimal price : prices) {
            BigDecimal rounded = price.setScale(2, RoundingMode.HALF_UP);
            System.out.println("$" + price + " -> $" + rounded);
        }

        // Precision control
        System.out.println("\nPrecision:");
        BigDecimal precise = new BigDecimal("123.456789");
        System.out.println("Original: " + precise);
        System.out.println("Precision: " + precise.precision());
        System.out.println("Scale: " + precise.scale());

        // ulp (unit in last place)
        System.out.println("\nulp:");
        BigDecimal val3 = new BigDecimal("1.5");
        System.out.println("Value: " + val3);
        System.out.println("ulp: " + val3.ulp());
    }

    //help h1
    // .scale() - get decimal places
    // .precision() - get total significant digits
    // .setScale(n, roundingMode) - set decimal places
    // .stripTrailingZeros() - remove trailing zeros
    // .movePointLeft(n), .movePointRight(n)
    // .scaleByPowerOfTen(n) - multiply by 10^n
    // RoundingMode: HALF_UP, HALF_EVEN, CEILING, FLOOR, etc.
    // Use setScale(2, HALF_UP) for currency
    //end
}
Scale The number of digits to the right of the decimal point. Use setScale() with a RoundingMode to control precision.

Comparison Operations

Compare BigDecimal values properly.

Comparison.java
// Comparison operations

import java.math.BigDecimal;

public class Comparison {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("10.5");
        BigDecimal b = new BigDecimal("20.3");
        BigDecimal c = new BigDecimal("10.5");
        
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("c = " + c);
        System.out.println();

        // compareTo
        System.out.println("compareTo:");
        System.out.println("a.compareTo(b): " + a.compareTo(b));  // -1
        System.out.println("b.compareTo(a): " + b.compareTo(a));  // 1
        System.out.println("a.compareTo(c): " + a.compareTo(c));  // 0

        // Comparison helpers
        System.out.println("\nComparison helpers:");
        System.out.println("a < b: " + (a.compareTo(b) < 0));
        System.out.println("a <= b: " + (a.compareTo(b) <= 0));
        System.out.println("a > b: " + (a.compareTo(b) > 0));
        System.out.println("a >= b: " + (a.compareTo(b) >= 0));
        System.out.println("a == c: " + (a.compareTo(c) == 0));

        // equals vs compareTo
        System.out.println("\nequals vs compareTo:");
        BigDecimal d1 = new BigDecimal("1.0");
        BigDecimal d2 = new BigDecimal("1.00");
        
        System.out.println("d1 = " + d1 + " (scale: " + d1.scale() + ")");
        System.out.println("d2 = " + d2 + " (scale: " + d2.scale() + ")");
        System.out.println("d1.equals(d2): " + d1.equals(d2));  // false (different scale)
        System.out.println("d1.compareTo(d2): " + d1.compareTo(d2));  // 0 (same value)

        // max and min
        System.out.println("\nmax and min:");
        System.out.println("max(a, b): " + a.max(b));
        System.out.println("min(a, b): " + a.min(b));

        // signum
        System.out.println("\nsignum:");
        BigDecimal pos = new BigDecimal("10.5");
        BigDecimal neg = new BigDecimal("-10.5");
        BigDecimal zero = BigDecimal.ZERO;
        
        System.out.println("signum(10.5): " + pos.signum());     // 1
        System.out.println("signum(-10.5): " + neg.signum());    // -1
        System.out.println("signum(0): " + zero.signum());       // 0

        // Find max in array
        System.out.println("\nFind max in array:");
        BigDecimal[] numbers = {
            new BigDecimal("12.5"),
            new BigDecimal("98.7"),
            new BigDecimal("45.2"),
            new BigDecimal("23.8")
        };
        
        BigDecimal max = findMax(numbers);
        BigDecimal min = findMin(numbers);
        System.out.println("Max: " + max);
        System.out.println("Min: " + min);

        // Sort array
        System.out.println("\nSort array:");
        java.util.Arrays.sort(numbers);
        System.out.println("Sorted: " + java.util.Arrays.toString(numbers));

        // Range check
        System.out.println("\nRange check:");
        BigDecimal value = new BigDecimal("15.5");
        BigDecimal lower = new BigDecimal("10.0");
        BigDecimal upper = new BigDecimal("20.0");
        
        boolean inRange = value.compareTo(lower) >= 0 && value.compareTo(upper) <= 0;
        System.out.println(value + " in [" + lower + ", " + upper + "]: " + inRange);

        // Zero check
        System.out.println("\nZero check:");
        BigDecimal val1 = new BigDecimal("0");
        BigDecimal val2 = new BigDecimal("0.00");
        
        System.out.println(val1 + " is zero: " + (val1.compareTo(BigDecimal.ZERO) == 0));
        System.out.println(val2 + " is zero: " + (val2.compareTo(BigDecimal.ZERO) == 0));
        System.out.println("val1.equals(ZERO): " + val1.equals(BigDecimal.ZERO));
        System.out.println("val2.equals(ZERO): " + val2.equals(BigDecimal.ZERO));  // false (different scale)

        // Sign check
        System.out.println("\nSign check:");
        System.out.println("pos > 0: " + (pos.signum() > 0));
        System.out.println("neg < 0: " + (neg.signum() < 0));
        System.out.println("zero == 0: " + (zero.signum() == 0));

        // Tolerance comparison
        System.out.println("\nTolerance comparison:");
        BigDecimal v1 = new BigDecimal("10.001");
        BigDecimal v2 = new BigDecimal("10.002");
        BigDecimal tolerance = new BigDecimal("0.01");
        
        boolean approxEqual = v1.subtract(v2).abs().compareTo(tolerance) <= 0;
        System.out.println(v1 + " ≈ " + v2 + " (tolerance " + tolerance + "): " + approxEqual);
    }
    public static BigDecimal findMax(BigDecimal[] arr) {
        BigDecimal max = arr[0];
        for (BigDecimal val : arr) {
            max = max.max(val);
        }
        return max;
    }
    public static BigDecimal findMin(BigDecimal[] arr) {
        BigDecimal min = arr[0];
        for (BigDecimal val : arr) {
            min = min.min(val);
        }
        return min;
    }

    //help h1
    // .compareTo(other) - returns -1, 0, or 1
    // .equals(other) - considers scale (use compareTo for value equality)
    // .max(other), .min(other)
    // .signum() - sign (-1, 0, or 1)
    // Use compareTo for value comparison
    // Use equals only when scale matters
    // For approximate equality, use tolerance
    //end
}
compareTo vs equals Use compareTo() for numeric equality (2.0 equals 2.00) and equals() only when scale must also match.

MathContext

Control precision and rounding behavior for operations.

Mathcontext.java
// MathContext usage

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class Mathcontext {
    public static void main(String[] args) {
        // MathContext: precision and rounding mode
        System.out.println("MathContext:");
        
        // Predefined contexts
        System.out.println("UNLIMITED: prec=" + MathContext.UNLIMITED.getPrecision() + 
                          ", rounding=" + MathContext.UNLIMITED.getRoundingMode());
        System.out.println("DECIMAL32: prec=" + MathContext.DECIMAL32.getPrecision() + 
                          ", rounding=" + MathContext.DECIMAL32.getRoundingMode());
        System.out.println("DECIMAL64: prec=" + MathContext.DECIMAL64.getPrecision() + 
                          ", rounding=" + MathContext.DECIMAL64.getRoundingMode());
        System.out.println("DECIMAL128: prec=" + MathContext.DECIMAL128.getPrecision() + 
                          ", rounding=" + MathContext.DECIMAL128.getRoundingMode());

        // Custom MathContext
        System.out.println("\nCustom MathContext:");
        MathContext mc10 = new MathContext(10, RoundingMode.HALF_UP);
        System.out.println("Custom: prec=" + mc10.getPrecision() + 
                          ", rounding=" + mc10.getRoundingMode());

        // Using MathContext in division
        System.out.println("\nDivision with different precision:");
        BigDecimal a = new BigDecimal("1");
        BigDecimal b = new BigDecimal("3");
        
        System.out.println("1/3 with DECIMAL32: " + a.divide(b, MathContext.DECIMAL32));
        System.out.println("1/3 with DECIMAL64: " + a.divide(b, MathContext.DECIMAL64));
        System.out.println("1/3 with DECIMAL128: " + a.divide(b, MathContext.DECIMAL128));
        System.out.println("1/3 with MC(10): " + a.divide(b, mc10));

        // Using MathContext in operations
        System.out.println("\nOperations with MathContext:");
        MathContext mc5 = new MathContext(5);
        
        BigDecimal x = new BigDecimal("1.234567890");
        BigDecimal y = new BigDecimal("2.345678901");
        
        System.out.println("x = " + x);
        System.out.println("y = " + y);
        System.out.println();
        
        System.out.println("add (MC5): " + x.add(y, mc5));
        System.out.println("subtract (MC5): " + x.subtract(y, mc5));
        System.out.println("multiply (MC5): " + x.multiply(y, mc5));
        System.out.println("divide (MC5): " + x.divide(y, mc5));

        // plus, minus (apply MathContext)
        System.out.println("\nplus and minus:");
        BigDecimal val = new BigDecimal("12.3456789");
        System.out.println("Original: " + val);
        System.out.println("plus(MC5): " + val.plus(mc5));
        System.out.println("minus(MC5): " + val.negate().plus(mc5));

        // Round method
        System.out.println("\nround method:");
        BigDecimal toRound = new BigDecimal("123.456789");
        System.out.println("Original: " + toRound);
        System.out.println("round(MC5): " + toRound.round(mc5));
        
        MathContext mc3 = new MathContext(3);
        System.out.println("round(MC3): " + toRound.round(mc3));

        // Different rounding modes in MathContext
        System.out.println("\nDifferent rounding modes:");
        BigDecimal value = new BigDecimal("2.5");
        
        MathContext mcUp = new MathContext(1, RoundingMode.UP);
        MathContext mcDown = new MathContext(1, RoundingMode.DOWN);
        MathContext mcHalfUp = new MathContext(1, RoundingMode.HALF_UP);
        MathContext mcHalfEven = new MathContext(1, RoundingMode.HALF_EVEN);
        
        System.out.println("Value: " + value);
        System.out.println("UP: " + value.round(mcUp));
        System.out.println("DOWN: " + value.round(mcDown));
        System.out.println("HALF_UP: " + value.round(mcHalfUp));
        System.out.println("HALF_EVEN: " + value.round(mcHalfEven));

        // Practical: financial calculation
        System.out.println("\nFinancial calculation:");
        MathContext financial = new MathContext(10, RoundingMode.HALF_UP);
        
        BigDecimal price = new BigDecimal("19.99");
        BigDecimal taxRate = new BigDecimal("0.08");
        BigDecimal quantity = new BigDecimal("3");
        
        BigDecimal subtotal = price.multiply(quantity);
        BigDecimal tax = subtotal.multiply(taxRate, financial)
                                 .setScale(2, RoundingMode.HALF_UP);
        BigDecimal total = subtotal.add(tax);
        
        System.out.println("Price: $" + price);
        System.out.println("Tax rate: " + taxRate.multiply(new BigDecimal("100")) + "%");
        System.out.println("Quantity: " + quantity);
        System.out.println("Subtotal: $" + subtotal);
        System.out.println("Tax: $" + tax);
        System.out.println("Total: $" + total.setScale(2, RoundingMode.HALF_UP));

        // Scientific calculation with high precision
        System.out.println("\nScientific calculation:");
        MathContext mc50 = new MathContext(50, RoundingMode.HALF_UP);
        
        // Calculate pi using Machin's formula (simplified)
        // π/4 = 4 * arctan(1/5) - arctan(1/239)
        // Using series: arctan(x) = x - x³/3 + x⁵/5 - x⁷/7 + ...
        
        BigDecimal pi = calculatePi(20, mc50);
        System.out.println("π (20 terms, 50 precision): " + pi);

        // Compound interest with high precision
        System.out.println("\nCompound interest (high precision):");
        MathContext mc20 = new MathContext(20, RoundingMode.HALF_UP);
        
        BigDecimal principal = new BigDecimal("10000");
        BigDecimal rate = new BigDecimal("0.05");
        int years = 30;
        
        BigDecimal amount = principal;
        for (int i = 0; i < years; i++) {
            amount = amount.multiply(BigDecimal.ONE.add(rate), mc20);
        }
        
        System.out.println("Principal: $" + principal);
        System.out.println("Rate: " + rate.multiply(new BigDecimal("100")) + "%");
        System.out.println("Years: " + years);
        System.out.println("Amount: $" + amount.setScale(2, RoundingMode.HALF_UP));
    }
    public static BigDecimal calculatePi(int terms, MathContext mc) {
        BigDecimal sum = BigDecimal.ZERO;
        for (int i = 0; i < terms; i++) {
            BigDecimal term = BigDecimal.ONE.divide(
                new BigDecimal(2 * i + 1), mc
            );
            if (i % 2 == 0) {
                sum = sum.add(term, mc);
            } else {
                sum = sum.subtract(term, mc);
            }
        }
        return sum.multiply(new BigDecimal("4"), mc);
    }

    //help h1
    // MathContext(precision, roundingMode)
    // MathContext.DECIMAL32/64/128 - predefined
    // .divide(other, mc) - use MathContext
    // .add/subtract/multiply(other, mc)
    // .round(mc) - apply precision
    // .plus(mc) - apply to current value
    // Use for consistent precision in calculations
    // Financial: MC(10-15, HALF_UP)
    // Scientific: MC(50-100, HALF_UP)
    //end
}

@seealso biginteger_intro, math_functions

Exercise: Practical.java

Calculate compound interest and split a bill evenly among friends