房貸的還款方式一般分等額本息和等額本金兩種,其中等額本息,就是每個月的還款額是相同的,等額本金呢,就是把本金等分,拆分到每個月的還款額裏,因此每個月的還款額是變化的。
以下是等額本息算法:計算方式其實很簡單,就是列一個等式,假設貸款100萬元,分30年還清,年利率是5.39%,還款方式是等額本息,則我們設置H是要得到的月供金額,得出以下等式:
月本息利率L =
第一個月還款後的本息和 =
第二個月還款後的本息和 = 展開:
第三個月還款後的本息和 = 展開:
......
第360個月的還款後的本息和 = (爲0表示全部還完)
即:
即:
即:
展開L 得到:
標準公式:,其中:M表示月利率,H表示月還款額度,1000000是本金,360是還款總月數
實際使用過程中,發現因爲浮點運算的四捨五入會有一定的誤差,需要重新校準,就是把算出的月供值按還款月份循環計算得出最後一次還款後剩餘的本息和是否<=0(表示徹底還完),根據上一次的校準結果和下一次的校準結果之間是否包含0這個界限來得出最優還款額(銀行不會少收你一分錢,但是可以多收你的錢。。)
/* 貸款本金 */
private final static double BaseMoney = 1000000;
/* 貸款年利率 */
private final static float MonthRate = 0.0539f/12;
/* 貸款月份 */
private final static int MonthLength = 12*30;
/* 總利息 */
private static double lixi = 0;
public static void main(String[] args) {
/* 驗證還款,因爲有分的誤差,需要微調才能確認 */
double yueHuan = calyueHuan();
BigDecimal bd = new BigDecimal(yueHuan);
yueHuan = bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
yueHuan = getFinalResult(yueHuan, 0);
System.out.println("最終月供:"+yueHuan);
getHuankuanResult(yueHuan, true);
}
private static double getFinalResult(double yueHuan, double lastResult) {
double result = getHuankuanResult(yueHuan, false);
if (result < 0) {
if (lastResult > 0) {
/* 上次是少還,這次是多還,則爲此值 */
System.out.println("上次是少還,這次是多還,則爲此值 yueHuan:"+yueHuan);
return yueHuan;
} else if (lastResult < 0) {
/* 上次是多還,這次還是多還,繼續減 */
System.out.println("上次是多還,這次還是多還,繼續減 yueHuan:"+yueHuan);
yueHuan -= 0.01;
return getFinalResult(yueHuan, result);
} else {
/* 多還了 */
System.out.println("多還了 yueHuan:"+yueHuan);
yueHuan -= 0.01;
return getFinalResult(yueHuan, result);
}
} else if (result > 0) {
if (lastResult > 0) {
/* 上次是少還,這次還是少還,繼續加 */
System.out.println("上次是少還,這次還是少還,繼續加 yueHuan:"+yueHuan);
yueHuan += 0.01;
return getFinalResult(yueHuan, result);
} else if (lastResult < 0) {
/* 上次是多還,這次是少還了,則就是上次 */
System.out.println("上次是多還,這次是少還了,則就是上次 yueHuan:"+yueHuan);
return yueHuan + 0.01;
} else {
/* 少還了 */
System.out.println("少還了 yueHuan:"+yueHuan);
yueHuan += 0.01;
return getFinalResult(yueHuan, result);
}
}
System.out.println("剛好是0 yueHuan:"+yueHuan);
return yueHuan;
}
/* 計算月供 */
private static double calyueHuan() {
double result = Math.pow(MonthRate+1, MonthLength)*BaseMoney;
double result2 = 0;
for (int i = 0; i < MonthLength; i++) {
result2 += Math.pow(MonthRate+1,i);
}
double yueHuann = result/result2;
System.out.println("月供毛坯值:"+yueHuann);
return yueHuann;
}
/* 傳入月供計算所有月份結束之後剩餘本息和 */
private static double getHuankuanResult(double yueHuann, boolean isPrintLog) {
double tmpBaseMoney = BaseMoney;
for (int i = 0; i < MonthLength; i++) {
double monthLixi = tmpBaseMoney*MonthRate;
tmpBaseMoney += monthLixi;
double benxi = tmpBaseMoney;
tmpBaseMoney -= yueHuann;
lixi += monthLixi;
if (isPrintLog) {
System.out.println("第"+(i+1)+"個月"+" 你欠債本息共:"+benxi+" 還了"+yueHuann+" 剩餘欠債本息:"+tmpBaseMoney+" 其中月利息:"+monthLixi+" 本月還本金:"+(yueHuann-monthLixi)+" 總利息:"+lixi);
}
}
return tmpBaseMoney;
}