Практические примеры использования BigInteger и BigDecimal
1. Банковская система
1.1 Управление счетами
public class BankAccount {
private String accountNumber;
private BigDecimal balance;
private static final int MONEY_SCALE = 2;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN;
public BankAccount(String accountNumber, BigDecimal initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance.setScale(MONEY_SCALE, ROUNDING_MODE);
}
public synchronized void deposit(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Deposit amount must be positive");
}
balance = balance.add(amount).setScale(MONEY_SCALE, ROUNDING_MODE);
}
public synchronized void withdraw(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Withdrawal amount must be positive");
}
if (balance.compareTo(amount) < 0) {
throw new InsufficientFundsException("Insufficient funds");
}
balance = balance.subtract(amount).setScale(MONEY_SCALE, ROUNDING_MODE);
}
public BigDecimal getBalance() {
return balance;
}
}
1.2 Расчёт кредитов
public class LoanCalculator {
private static final int CALCULATION_SCALE = 10;
private static final int DISPLAY_SCALE = 2;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN;
public LoanSchedule calculateMortgage(BigDecimal principal,
BigDecimal annualRate,
int years) {
// Месячная процентная ставка
BigDecimal monthlyRate = annualRate
.divide(BigDecimal.valueOf(100), CALCULATION_SCALE, ROUNDING_MODE)
.divide(BigDecimal.valueOf(12), CALCULATION_SCALE, ROUNDING_MODE);
int totalPayments = years * 12;
// Расчёт ежемесячного платежа
BigDecimal monthlyPayment = calculateMonthlyPayment(
principal, monthlyRate, totalPayments);
List<PaymentPeriod> schedule = new ArrayList<>();
BigDecimal remainingPrincipal = principal;
for (int month = 1; month <= totalPayments; month++) {
// Расчёт процентов за период
BigDecimal interest = remainingPrincipal
.multiply(monthlyRate)
.setScale(CALCULATION_SCALE, ROUNDING_MODE);
// Расчёт основного долга за период
BigDecimal principalPaid = monthlyPayment.subtract(interest);
// Обновление остатка
remainingPrincipal = remainingPrincipal
.subtract(principalPaid)
.setScale(CALCULATION_SCALE, ROUNDING_MODE);
schedule.add(new PaymentPeriod(
month,
monthlyPayment.setScale(DISPLAY_SCALE, ROUNDING_MODE),
principalPaid.setScale(DISPLAY_SCALE, ROUNDING_MODE),
interest.setScale(DISPLAY_SCALE, ROUNDING_MODE),
remainingPrincipal.setScale(DISPLAY_SCALE, ROUNDING_MODE)
));
}
return new LoanSchedule(schedule);
}
private BigDecimal calculateMonthlyPayment(
BigDecimal principal,
BigDecimal monthlyRate,
int totalPayments) {
BigDecimal onePlusRate = BigDecimal.ONE.add(monthlyRate);
BigDecimal rateFactors = onePlusRate.pow(totalPayments);
return principal
.multiply(monthlyRate)
.multiply(rateFactors)
.divide(rateFactors.subtract(BigDecimal.ONE),
CALCULATION_SCALE, ROUNDING_MODE);
}
}
2. Система электронной коммерции
2.1 Расчёт скидок и налогов
public class PriceCalculator {
private static final int PRICE_SCALE = 2;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN;
public OrderTotal calculateOrderTotal(List<OrderItem> items,
BigDecimal taxRate,
List<Discount> discounts) {
// Подсчёт суммы заказа
BigDecimal subtotal = items.stream()
.map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(PRICE_SCALE, ROUNDING_MODE);
// Применение скидок
BigDecimal discountAmount = discounts.stream()
.map(discount -> calculateDiscount(subtotal, discount))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(PRICE_SCALE, ROUNDING_MODE);
BigDecimal discountedTotal = subtotal.subtract(discountAmount);
// Расчёт налога
BigDecimal tax = discountedTotal
.multiply(taxRate)
.divide(BigDecimal.valueOf(100), ROUNDING_MODE)
.setScale(PRICE_SCALE, ROUNDING_MODE);
// Итоговая сумма
BigDecimal total = discountedTotal.add(tax);
return new OrderTotal(subtotal, discountAmount, tax, total);
}
private BigDecimal calculateDiscount(BigDecimal amount, Discount discount) {
switch (discount.getType()) {
case PERCENTAGE:
return amount
.multiply(discount.getValue()
.divide(BigDecimal.valueOf(100), ROUNDING_MODE));
case FIXED:
return discount.getValue();
default:
throw new IllegalArgumentException("Unknown discount type");
}
}
}
3. Криптографические вычисления
3.1 Реализация RSA
public class RSAImplementation {
public static class KeyPair {
private final BigInteger publicKey;
private final BigInteger privateKey;
private final BigInteger modulus;
public KeyPair(BigInteger publicKey, BigInteger privateKey, BigInteger modulus) {
this.publicKey = publicKey;
this.privateKey = privateKey;
this.modulus = modulus;
}
}
public KeyPair generateKeyPair(int bitLength) {
SecureRandom random = new SecureRandom();
// Генерация простых чисел
BigInteger p = BigInteger.probablePrime(bitLength / 2, random);
BigInteger q = BigInteger.probablePrime(bitLength / 2, random);
// Вычисление модуля
BigInteger n = p.multiply(q);
// Вычисление функции Эйлера
BigInteger phi = p.subtract(BigInteger.ONE)
.multiply(q.subtract(BigInteger.ONE));
// Выбор открытой экспоненты
BigInteger e = BigInteger.valueOf(65537);
// Вычисление закрытой экспоненты
BigInteger d = e.modInverse(phi);
return new KeyPair(e, d, n);
}
public BigInteger encrypt(BigInteger message,
BigInteger publicKey,
BigInteger modulus) {
return message.modPow(publicKey, modulus);
}
public BigInteger decrypt(BigInteger ciphertext,
BigInteger privateKey,
BigInteger modulus) {
return ciphertext.modPow(privateKey, modulus);
}
}
4. Научные вычисления
4.1 Расчёт статистических показателей
public class StatisticalCalculator {
private static final int CALCULATION_SCALE = 10;
private static final int DISPLAY_SCALE = 4;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN;
public StatisticalResult calculate(List<BigDecimal> values) {
int n = values.size();
if (n == 0) {
throw new IllegalArgumentException("Empty dataset");
}
// Среднее значение
BigDecimal sum = values.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal mean = sum
.divide(BigDecimal.valueOf(n), CALCULATION_SCALE, ROUNDING_MODE);
// Дисперсия
BigDecimal variance = values.stream()
.map(x -> x.subtract(mean)
.pow(2))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.divide(BigDecimal.valueOf(n), CALCULATION_SCALE, ROUNDING_MODE);
// Стандартное отклонение
BigDecimal stdDev = sqrt(variance, CALCULATION_SCALE);
return new StatisticalResult(
mean.setScale(DISPLAY_SCALE, ROUNDING_MODE),
variance.setScale(DISPLAY_SCALE, ROUNDING_MODE),
stdDev.setScale(DISPLAY_SCALE, ROUNDING_MODE)
);
}
private BigDecimal sqrt(BigDecimal value, int scale) {
BigDecimal two = BigDecimal.valueOf(2);
BigDecimal precision = BigDecimal.valueOf(0.1)
.movePointLeft(scale);
BigDecimal result = BigDecimal.valueOf(
Math.sqrt(value.doubleValue()));
while (true) {
BigDecimal next = result.add(value
.divide(result, scale, ROUNDING_MODE))
.divide(two, scale, ROUNDING_MODE);
if (result.subtract(next).abs().compareTo(precision) <= 0) {
return result;
}
result = next;
}
}
}
5. Бухгалтерские расчёты
5.1 Расчёт амортизации
public class DepreciationCalculator {
private static final int MONEY_SCALE = 2;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN;
public List<DepreciationPeriod> calculateStraightLine(
BigDecimal initialValue,
BigDecimal salvageValue,
int lifeYears) {
List<DepreciationPeriod> schedule = new ArrayList<>();
// Годовая амортизация
BigDecimal annualDepreciation = initialValue
.subtract(salvageValue)
.divide(BigDecimal.valueOf(lifeYears),
MONEY_SCALE, ROUNDING_MODE);
BigDecimal currentValue = initialValue;
for (int year = 1; year <= lifeYears; year++) {
currentValue = currentValue.subtract(annualDepreciation);
schedule.add(new DepreciationPeriod(
year,
annualDepreciation,
currentValue.setScale(MONEY_SCALE, ROUNDING_MODE)
));
}
return schedule;
}
public List<DepreciationPeriod> calculateDecliningBalance(
BigDecimal initialValue,
BigDecimal salvageValue,
int lifeYears,
BigDecimal rate) {
List<DepreciationPeriod> schedule = new ArrayList<>();
BigDecimal currentValue = initialValue;
for (int year = 1; year <= lifeYears; year++) {
BigDecimal depreciation = currentValue
.multiply(rate)
.setScale(MONEY_SCALE, ROUNDING_MODE);
if (currentValue.subtract(depreciation)
.compareTo(salvageValue) < 0) {
depreciation = currentValue.subtract(salvageValue);
currentValue = salvageValue;
} else {
currentValue = currentValue.subtract(depreciation);
}
schedule.add(new DepreciationPeriod(
year,
depreciation,
currentValue
));
if (currentValue.compareTo(salvageValue) <= 0) {
break;
}
}
return schedule;
}
}
Эти примеры демонстрируют реальные сценарии использования BigInteger и BigDecimal в различных областях. Хотели бы вы: 1. Рассмотреть другие области применения? 2. Углубиться в детали реализации какого-то конкретного примера? 3. Обсудить оптимизацию производительности этих решений? 4. Добавить обработку ошибок и валидацию данных?