Я хочу создать Калькулятор амортизации , чтобы получить цитату из числа N кредиторов на кредиты сроком на 36 месяцев, где у каждого кредитора разные процентные ставки. Цель состоит в том, чтобы обеспечить максимально возможную ставку low и указать ежемесячную сумму погашения и общую сумму погашения. Результат моего кода близок, но не точен .
Я использую формулу
вычисление i
(процентная ставка) как total amount lended / requested amount
, где общая сумма округленных денежных сумм, умноженная на каждого кредитора, умножается на ставку кредитора.
BigDecimal requestedAmountP = new BigDecimal("" + requestedAmount);
BigDecimal minLendersRate = calculateRate(requestedAmount, lenders);
// https://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula
// r*P/(1 - (1+r)^(-N)) if r != 0
// P/N if r == 0
BigDecimal monthlyRepayment;
if (minLendersRate.compareTo(BigDecimal.ZERO) == 0) {
monthlyRepayment = requestedAmountP.divide(DURATION_MONTHS, MathContext.DECIMAL128);
} else {
BigDecimal r = calculateEffectiveInterestInMonths(minLendersRate);
BigDecimal tmp = r.add(BigDecimal.ONE).pow(-DURATION_MONTHS.intValue(), MathContext.DECIMAL128);
BigDecimal dividend = BigDecimal.ONE.subtract(tmp);
monthlyRepayment = r.multiply(requestedAmountP).divide(dividend, MathContext.DECIMAL128);
}
BigDecimal totalRepayment = monthlyRepayment.multiply(DURATION_MONTHS);
Для расчета ставки:
private BigDecimal calculateRate(double requestedAmount, List<Lender> lenders) {
List<Lender> sortedLenders = lenders.stream().sorted(Comparator.comparing(Lender::getRate)).collect(toList());
List<BigDecimal> moneyLended = moneyLended(requestedAmount, sortedLenders);
BigDecimal totalMoneyLended = IntStream.range(0, moneyLended.size())
.mapToObj(index -> moneyLended.get(index).multiply(sortedLenders.get(index).getRate()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
return totalMoneyLended.divide(new BigDecimal("" + requestedAmount), MathContext.DECIMAL128);
}
private List<BigDecimal> moneyLended(double requestedAmount, List<Lender> sortedLenders) {
List<BigDecimal> moneyLended = new ArrayList<>(sortedLenders.size());
int i = 0;
Double remaining = requestedAmount;
while (remaining > 0) {
if (remaining - sortedLenders.get(i).getAvailable().doubleValue() >= 0) {
remaining = remaining - sortedLenders.get(i).getAvailable().doubleValue();
} else {
remaining = 0d;
}
moneyLended.add(sortedLenders.get(i).getAvailable());
i++;
}
return moneyLended;
}
Для расчета Эффективный процент в месяцах
private BigDecimal calculateEffectiveInterestInMonths(BigDecimal nominalInterest) {
// Formula: ((1+nominalInterest)^(1/12))-1
BigDecimal exp = BigDecimal.ONE.divide(new BigDecimal("12"), MathContext.DECIMAL128);
return BigDecimalMath.pow(BigDecimal.ONE.add(nominalInterest), exp, MathContext.DECIMAL128)
.subtract(BigDecimal.ONE);
}
Кажется, есть проблема с десятичными операциями, но я не могу определить, где.