Math & Numbers
BigDecimal Introduction
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