等额本金与等额本息
等本等息的意思是,每月的本金相等,利息也相等。
等额本息的意思是,每月的本金+利息之和相等(其实每个月本金和利息都有变化,并不相等)
等本等息的意思是,每月的本金相等,利息不等。
等额本金计算:
等额本金是指一种贷款的还款方式,是在还款期内把贷款数总额等分,每月偿还同等数额的本金和剩余贷款在该月所产生的利息,这样由于每月的还款本金额固定,
而利息越来越少,借款人起初还款压力较大,但是随时间的推移每月还款数也越来越少。
1 package com.utils; 2 3 import java.math.BigDecimal; 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 import java.util.Map.Entry; 9 10 /** 11 * 等额本金是指一种贷款的还款方式,是在还款期内把贷款数总额等分,每月偿还同等数额的本金和剩余贷款在该月所产生的利息,这样由于每月的还款本金额固定, 12 * 而利息越来越少,借款人起初还款压力较大,但是随时间的推移每月还款数也越来越少。 13 */ 14 public class AverageCapitalUtils { 15 16 private static final Integer month = 12; 17 18 /** 19 * 等额本金计算获取还款方式为等额本金的每月偿还本金和利息 (返回,期数,月总和。月利息,月本金) 20 * 21 * 公式:每月偿还本金=(贷款本金÷还款月数)+(贷款本金-已归还本金累计额)×月利率 22 * 23 * @param investMoney 24 * 总借款额(贷款本金) 25 * @param yearRate 26 * 总年利率 27 * @param otherRate 28 * 加息年利率 29 * @param unit 30 * 單位:年,月 31 * @param month 32 * 还款总月数 33 * @return 每月偿还本金和利息,不四舍五入,直接截取小数点最后两位 34 */ 35 public static List
等额本息计算:
等额本息是指一种贷款的还款方式,是在还款期内,每月偿还同等数额的贷款(包括本金和利息),和等额本金是不一样的概念,虽然刚开始还款时每月还款额可能会低于等额本金还款方式,但是最终所还利息会高于等额本金还款方式,该方式经常被银行使用。
每月还款数额 计算公式如下:
[ 贷款本金× 月利率×(1+月利率)^还款月数]÷[(1+月利率)^还款月数-1]
下面举例说明等额本息还款法,
假定借款人从银行获得一笔20万元的 个人住房贷款, 贷款期限20年,贷款年利率4.2%,每月还本付息。按照上述公式计算,每月应偿还本息和为1233.14元。
上述结果只给出了每月应付的本息和,因此需要对这个本息和进行分解。仍以上例为基础,一个月为一期,第一期 贷款余额20万元,应支付利息700元(200000×4.2%/12),支付本金533.14元,仍欠银行贷款199466.86元;第二期应支付利息(199466.86×4.2%/12)元。
package com.util; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import com.LoanProductStageVo; import com.TimeUnits; /** * 本息计算器 * @Description: 本息算法 */ public class PrincipalAndInterestEquals { /** * 调试 * @param args */ public static void main(String[] args) { int periods = 4; TimeUnits unit = TimeUnits.day; RoundingMode roundingMode = RoundingMode.UP; BigDecimal rate = new BigDecimal("0.12"); BigDecimal money = new BigDecimal("10000"); // equalPI_stage(periods, rate, unit, money, roundingMode); // System.out.println("每月本息和(等额本息):"+equalPI_everyMonthPrincipalAddInterset(periods, rate, TimeUnits.month, money, RoundingMode.UP)); // System.out.println("每月本息和:"+pEqualI_stage(periods, rate,unit, money, RoundingMode.UP)); // pEqualI_stageSumNum(15 ,periods, rate, unit, money, roundingMode); // equalP_stage(periods, rate, money, roundingMode); // Liststages = equalPI_stage(periods, rate, TimeUnits.month, money, RoundingMode.UP); // for(int i = 0; i < stages.size(); i++) { // System.out.println("------------" + (i+1) + "期"); // System.out.println("本金:" + stages.get(i).getPrincipal()); // System.out.println("利息:" + stages.get(i).getInterset()); // } } /** * 月转年,乘以12 */ private static final BigDecimal MONTH_YEAR = new BigDecimal("12"); /** * 天转月,乘以30,一月按30天算 */ private static final BigDecimal DAY_MONTH = new BigDecimal("30"); // private static final BigDecimal DAY_YEWR = new BigDecimal("365"); /** * 利率百分数转换 */ private static final BigDecimal RATE_CONVERT_PERCENT = new BigDecimal("100"); ///-------------------------------等额本息 /** * 等额本息 —— 计算每期还款本息和 *设贷款额为a,月利率为i,年利率为I,还款月数为n,每月还款额为b,还款利息总和为Y
* @param periods 期数,单位:月 * @param rate 年利率 * @param unit 期数单位(目前仅支持年、月、日) * @param money 要分期的金额 * @param roundingMode 小数位处理 * @return 每期还款额,如单位年,则为每年还款额 */ public static BigDecimal equalPI_everyMonthPrincipalAddInterset(Integer periods, BigDecimal rate, TimeUnits unit, BigDecimal money, RoundingMode roundingMode) { rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode).divide(MONTH_YEAR, roundingMode);//将年利率转换成月利率 /* * 设贷款额为a,月利率为i,年利率为I,还款月数为n,每月还款额为b,还款利息总和为Y * 月均还款:b=a×i×(1+i)^n÷〔(1+i)^n-1〕 */ BigDecimal newrate = rate.add(new BigDecimal("1")).pow(periods);//1+月利率 BigDecimal ch = newrate.subtract(new BigDecimal("1")); BigDecimal monthMoney = money.multiply(rate).multiply(newrate).divide(ch, 2, roundingMode);//每月还款本息和 // System.out.println("每月还款本息:"+monthMoney); // System.out.println("通过每月还款本息计算的还款总和:"+monthMoney.multiply(new BigDecimal(stage.getPeriods()))); if(TimeUnits.year == unit) { return money.multiply(MONTH_YEAR).setScale(2, roundingMode); } else if(TimeUnits.day == unit) { return money.divide(DAY_MONTH, 2, roundingMode); } return monthMoney; } /** * 等额本息 —— 计算各个月份的还款额(仅支持月) *
* 月均还款:b=a×i×(1+i)^n÷〔(1+i)^n-1〕设贷款额为a,月利率为i,年利率为I,还款月数为n,每月还款额为b,还款利息总和为Y
*
* 第n月还款利息为:(a×i-b)×(1+i)^(n-1)+b未完成:单位为年和日的,间隔不是1的情况
* @param periods 分期数,单位:月 * @param rate 年利率 * @param unit 单位(仅支持月) * @param money 贷款总金额 * @param roundingMode 小数位处理 * @return */ public static ListequalPI_stage(Integer periods, BigDecimal rate, TimeUnits unit, BigDecimal money, RoundingMode roundingMode) { rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode).divide(MONTH_YEAR, roundingMode);//计算月利率 /* * 设贷款额为a,月利率为i,年利率为I,还款月数为n,每月还款额为b,还款利息总和为Y * 第n月还款利息为:(a×i-b)×(1+i)^(n-1)+b */ List stageResult = new ArrayList<>(); //BigDecimal principalAddInterset = equalPI_everyMonthPrincipalAddInterset(periods, rate, unit, money,roundingMode); BigDecimal principalAddInterset = equalPI_everyMonthPrincipalAddInterset(periods, rate, TimeUnits.month, money,roundingMode); BigDecimal totalLixi = new BigDecimal(0);//临时:利息总额 BigDecimal totalBenjin = new BigDecimal(0);//临时:本金总额 for(int i = 0; i < periods; i++) { // System.out.println("\n--------" + (i+1) + "期"); LoanProductStageVo stageVo = new LoanProductStageVo(); stageVo.setPrincipalAddInterset(principalAddInterset); if(i + 1 == periods) { //最后一期的计算,将计算中因小数位导致数据不对称的补充回来 stageVo.setInterset(principalAddInterset.multiply(new BigDecimal(periods)).subtract(money).subtract(totalLixi)); stageVo.setPrincipal(money.subtract(totalBenjin)); } else { BigDecimal currentMonthRate = rate.add(new BigDecimal(1)).pow(i); BigDecimal interset = money.multiply(rate).subtract(principalAddInterset).multiply(currentMonthRate).add(principalAddInterset).setScale(2, roundingMode); stageVo.setInterset(interset); stageVo.setPrincipal(principalAddInterset.subtract(interset)); } totalLixi = totalLixi.add(stageVo.getInterset()); totalBenjin = totalBenjin.add(stageVo.getPrincipal()); stageResult.add(stageVo); } // System.out.println("还款利息总额:" + totalLixi); // System.out.println("还款本金总额:" + totalBenjin); return stageResult; } /** * 等额本息 —— 按照公式计算第n期的信息 * @param n 第n期 * @param periods 分期数 * @param rate 月利率 * @param unit 单位(目前仅支持年、月) * @param money 总本金额 * @param roundingMode 小数位取值方式 * @return */ public static LoanProductStageVo equalPI_stageAtNum(int n, int periods, BigDecimal rate, BigDecimal money, RoundingMode roundingMode) { if(n <= 0) { return null; } if(n > periods) { return null; } rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode).divide(MONTH_YEAR, roundingMode); /* * 设贷款额为a,月利率为i,年利率为I,还款月数为n,每月还款额为b,还款利息总和为Y * 第n月还款利息为:(a×i-b)×(1+i)^(n-1)+b */ LoanProductStageVo stageVo = new LoanProductStageVo(); BigDecimal principalAddInterset = equalPI_everyMonthPrincipalAddInterset(periods, rate, TimeUnits.month, money,roundingMode); BigDecimal currentMonthRate = rate.add(new BigDecimal(1)).pow(n - 1); BigDecimal interset = money.multiply(rate).subtract(principalAddInterset).multiply(currentMonthRate).add(principalAddInterset).setScale(2, roundingMode); stageVo.setPrincipalAddInterset(principalAddInterset); stageVo.setInterset(interset); stageVo.setPrincipal(principalAddInterset.subtract(interset)); return stageVo; } ///-------------------------------等额本金 /** * 等额本息 —— 计算每期信息 * 公式:每月还款金额 = (贷款本金 / 还款月数)+(本金 — 已归还本金累计额)×每月利率
* * @param periods 分期数 * @param rate 年利率 * @param money 本金总额 * @param roundingMode 小数位处理 * @return */ public static ListequalP_stage(int periods, BigDecimal rate, BigDecimal money, RoundingMode roundingMode) { final BigDecimal PERIODS = new BigDecimal(periods + ""); rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode).divide(MONTH_YEAR, roundingMode); List stageResult = new ArrayList<>(); //每月还款本金 BigDecimal everyMonthPrincipal = money.divide(PERIODS, 2, roundingMode); BigDecimal totalBenjin = new BigDecimal("0"); BigDecimal totalLixi = new BigDecimal("0"); for(int i = 0; i < periods; i++) { // System.out.println("\n--------" + (i+1) + "期"); LoanProductStageVo stageVo = new LoanProductStageVo(); if(i+1 == periods) { stageVo.setPrincipal(money.subtract(totalBenjin)); stageVo.setInterset(stageVo.getPrincipal().multiply(rate).setScale(2, roundingMode)); } else { stageVo.setPrincipal(everyMonthPrincipal); stageVo.setInterset(money.subtract(totalBenjin).multiply(rate).setScale(2, roundingMode)); } // System.out.println("本金:"+stageVo.getPrincipal()); // System.out.println("利息:"+stageVo.getInterset()); totalBenjin = totalBenjin.add(stageVo.getPrincipal()); totalLixi = totalLixi.add(stageVo.getInterset()); stageResult.add(stageVo); } // System.out.println("本金和:"+totalBenjin); // System.out.println("利息和:"+totalLixi); return stageResult; } }
等本等息为民间借贷、分期购物、银行分期中的一种还款方式。
月还款为:本金+利息。
举例说明,假设借款额3万元,借款期限12个月,预计年化借款利率12%,等本等息还款,每月月末归还本金及利息,则公式如下:每月归还本金=贷款3万÷12期=2500元,预计年利息=3万×12%=3600元,为月息300元,那就是每个月需还2500+300=2800元。
月还款为:本金+利息。
举例说明,假设借款额3万元,借款期限12个月,预计年化借款利率12%,等本等息还款,每月月末归还本金及利息,则公式如下:每月归还本金=贷款3万÷12期=2500元,预计年利息=3万×12%=3600元,为月息300元,那就是每个月需还2500+300=2800元。
package com.zhonglian.jinju.pub.service.support; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import com.LoanProductStageVo; import com.TimeUnits; /** *等 本等息计算器 * @Description: 本息算法 */ public class PrincipalAndInterestEquals2 { /** * 调试 * @param args */ public static void main(String[] args) { int periods = 4; TimeUnits unit = TimeUnits.day; RoundingMode roundingMode = RoundingMode.UP; BigDecimal rate = new BigDecimal("0.12"); BigDecimal money = new BigDecimal("10000"); pEqualI_stageSumNum(15 ,periods, rate, unit, money, roundingMode); // equalP_stage(periods, rate, money, roundingMode); // Liststages = equalPI_stage(periods, rate, TimeUnits.month, money, RoundingMode.UP); // for(int i = 0; i < stages.size(); i++) { // System.out.println("------------" + (i+1) + "期"); // System.out.println("本金:" + stages.get(i).getPrincipal()); // System.out.println("利息:" + stages.get(i).getInterset()); // } } /** * 月转年,乘以12 */ private static final BigDecimal MONTH_YEAR = new BigDecimal("12"); /** * 天转月,乘以30,一月按30天算 */ private static final BigDecimal DAY_MONTH = new BigDecimal("30"); // private static final BigDecimal DAY_YEWR = new BigDecimal("365"); /** * 利率百分数转换 */ private static final BigDecimal RATE_CONVERT_PERCENT = new BigDecimal("100"); ///-------------------------------等本等息 /** * 等本等息 —— 计算每期信息 *算法:第n月还款利息为:贷款总额 * 年利率 / 分期数
* @param periods 分期数,单位月 * @param rate 利率 * @param money 贷款总额 * @param roundingMode 小数位处理 * @return */ public static ListpEqualI_stage(int periods, BigDecimal rate, BigDecimal money, RoundingMode roundingMode) { rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode); List result = new ArrayList<>(); BigDecimal everyMonthPrincipal = money.divide(new BigDecimal(periods+""), 2, roundingMode); BigDecimal everyMonthInterset = money.multiply(rate).divide(MONTH_YEAR, roundingMode); BigDecimal totalInterset = everyMonthInterset.multiply(new BigDecimal(periods+"")); BigDecimal principalAddInterset = everyMonthPrincipal.add(everyMonthInterset); BigDecimal totalBenjin = new BigDecimal("0"); BigDecimal totalLixi = new BigDecimal("0"); for(int i = 0; i < periods; i++) { // System.out.println("\n--------" + (i+1) + "期"); LoanProductStageVo stageVo = new LoanProductStageVo(); if(i + 1 == periods) { //TODO 算法疑问:最后一期会与前面的不一样 // System.out.println("最后"); stageVo.setPrincipal(money.subtract(totalBenjin)); stageVo.setInterset(totalInterset.subtract(totalLixi).setScale(2, roundingMode)); stageVo.setPrincipalAddInterset(principalAddInterset); } else { stageVo.setInterset(everyMonthInterset); stageVo.setPrincipal(everyMonthPrincipal); stageVo.setPrincipalAddInterset(principalAddInterset); } result.add(stageVo); totalBenjin = totalBenjin.add(stageVo.getPrincipal()); totalLixi = totalLixi.add(stageVo.getInterset()); // System.out.println("本金:"+stageVo.getPrincipal()); // System.out.println("利息:"+stageVo.getInterset()); // System.out.println("月本息和:"+stageVo.getPrincipalAddInterset()); } // System.out.println("本金和:"+totalBenjin); // System.out.println("利息和:"+totalLixi); return result; } /** * 等本等息 —— 计算前n期之和,时间单位支持年、月、日(按照公式计算) *
但对最后一期本金或利息不会“多退少补”计算,本方法完全按照公式走 * @param n 要计算的期数,单位:月 * @param periods 分期数 * @param rate 年利率 * @param unit 时间单位 * @param money 总金额 * @param roundingMode 小数位取值方式 * @return 如果要获取的期数超过分期期数,则返回总本息信息 */ public static LoanProductStageVo pEqualI_stageSumNum(int n, int periods, BigDecimal rate, TimeUnits unit, BigDecimal money, RoundingMode roundingMode) { rate = rate.divide(RATE_CONVERT_PERCENT, roundingMode); LoanProductStageVo stageVo = new LoanProductStageVo(); if(n <= 0) { stageVo.setInterset(new BigDecimal("0")); stageVo.setPrincipal(new BigDecimal("0")); return stageVo; } final BigDecimal PERIODS = new BigDecimal(periods+""); final BigDecimal N = new BigDecimal(n + ""); BigDecimal monthPrincipal = money.divide(PERIODS, 2, roundingMode);//月本金 BigDecimal monthInterset = money.multiply(rate).divide(MONTH_YEAR, 2, roundingMode);//月利息 BigDecimal nSumPrincipal = null, nSumInterset = null; boolean nEp = true;//期数校验 if(TimeUnits.year == unit) { if(n * 12 <= periods) { nSumPrincipal = monthPrincipal.multiply(N).multiply(MONTH_YEAR); nSumInterset = monthInterset.multiply(N).multiply(MONTH_YEAR); nEp = false; } } else if(TimeUnits.month == unit) { if(n <= periods) { nSumPrincipal = monthPrincipal.multiply(N); nSumInterset = monthInterset.multiply(N); nEp = false; } } else if(TimeUnits.day == unit) { if(n / 30 <= periods) { nSumPrincipal = monthPrincipal.multiply(N).divide(DAY_MONTH, 2, roundingMode); nSumInterset = monthInterset.multiply(N).divide(DAY_MONTH, 2, roundingMode); nEp = false; } } else { return null; } //n的时间大于分期数情况,计算总和 if(nEp) { nSumPrincipal = monthPrincipal.multiply(PERIODS); nSumInterset = monthInterset.multiply(PERIODS); } stageVo.setPrincipal(nSumPrincipal); stageVo.setInterset(nSumInterset); // System.out.println("等本等息:前"+n+unit.getText()+"信息"); // System.out.println("本金和:"+stageVo.getPrincipal()); // System.out.println("利息和:"+stageVo.getInterset()); return stageVo; } }
TimeUnits类
package com.enums; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @JsonSerialize(as = StringValueTextEnum.class) public enum TimeUnits implements StringValueTextEnum { /** 分 */ minute("minute", "分"), /** 时 */ hour("hour", "时"), /** 天 */ day("day", "天"), /** 周 */ week("week", "周"), /** 月 */ month("month", "月"), /** 年 */ year("year", "年"); private String value; private String text; private TimeUnits(String value, String text) { this.value = value; this.text = text; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getText() { return text; } public void setText(String text) { this.text = text; } }
LoanProductStageVo公共类
package com.bo; import java.math.BigDecimal; /** * 分期计算结果类 * */ public class LoanProductStageVo { //本息和 private BigDecimal principalAddInterset; //本金 private BigDecimal principal; //利息 private BigDecimal interset; /** * 本息和(单独的公式计算,每月相同) * @return */ public BigDecimal getPrincipalAddInterset() { if(principalAddInterset == null && principal != null && interset != null) { principalAddInterset = principal.add(interset); } return principalAddInterset; } /** * 本息和(单独的公式计算,每月相同) * @param principalAddInterset */ public void setPrincipalAddInterset(BigDecimal principalAddInterset) { this.principalAddInterset = principalAddInterset; } /** * 本金 * @return */ public BigDecimal getPrincipal() { return principal; } /** * 本金 * @param principal */ public void setPrincipal(BigDecimal principal) { this.principal = principal; } /** * 利息 * @return */ public BigDecimal getInterset() { return interset; } /** * 利息 * @param interset */ public void setInterset(BigDecimal interset) { this.interset = interset; } }
完