有同学问我,说通货膨胀率这么高,是不是贷款买房很划算,我这边先上结论,再上代码。
_(:з」∠)_,这边同学给的设定,是通货膨胀率6%,每年存款4000,或者还房贷4000,房贷利率多少时,这俩玩意才一样划算?答案是15.25%。
这东西乍一听听容易算,但是真的动手算,还蛮头大的。大家可以直接看代码,我注释很全,不做文字赘述了。
package main.java;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/*
* 问题1:年通货膨胀率6%,是否意味着,你前一年的钱,在今年价值为94%?
* 问题2:是否每年叠加?
* 问题3:假设你每月4000用于存款or还房贷,房贷还20年,年通货膨胀率6%,房贷利率多少的情况下,房贷比存放着任由通货膨胀贬值划算?
* */
public class Main {
public static void main(String[] args) {
System.out.println("代码开始。\n");
// 月份,4年就是240个月。
int monthes = 240;
// 通货膨胀率,6%,也即0.06。
BigDecimal inflation = new BigDecimal("0.06");;
// 每月要还的金额,4000元。
int annualPay = 4000;
// 利率上限,设为100%,也就是1。
BigDecimal interestUp = new BigDecimal("1");
// 利率下限,设为0%,也就是0。
BigDecimal interestDown = new BigDecimal("0");
// 利率,利率=(利率上限+利率下限)/ 2,接下来用二分法找最合适的利率。
BigDecimal interestRate = interestUp.subtract(interestDown).divide(new BigDecimal("2"), 10, RoundingMode.HALF_UP);
// 二分法终止条件,这里只要金额相差1元以内,就认为找到近似解。
BigDecimal tolerantDifference = new BigDecimal("1");
// 要增加利率的标志。
boolean addTheInterestFlag = true;
// 存款20年,最终的钱。
BigDecimal moneyDeposit = new BigDecimal(annualPay * monthes);
/* 这里想算出,现在我贷款多大价值的房产,等于二十年后的存款。过程中会解决通货膨胀比例问题哦。 */
BigDecimal moneyHouseInitiate = new BigDecimal(1);
moneyHouseInitiate = moneyHouseInitiate.divide(inflation.add(BigDecimal.ONE), 10, RoundingMode.HALF_UP);
System.out.println("问题1,去年我有Y元,房价Z元,我能买Y/Z的房子;今年房价1.06×Z元,我能买Y/(1.06×Z)的房子。以房子" +
"作为参考系,金钱贬值为(Y/(1.06×Z)) / (Y/Z) = 1/1.06 , 约等于:" + moneyHouseInitiate.multiply(new BigDecimal("100")) + "%,");
moneyHouseInitiate = moneyHouseInitiate.pow(20).multiply(moneyDeposit);
System.out.println("存款20年,最终的钱是:" + moneyDeposit + "元。");
System.out.println("这里算出今天" + moneyHouseInitiate.intValue() + "元的房子,等于20年后" + moneyDeposit + "的存款。\n");
System.out.println("问题2,当然是叠加的啦。\n");
/* 不幸的是,我的智商没有算出解析解,只能算出数值解,猛男落泪o(╥﹏╥)o
* 假设房子全部靠贷款,每月要还4000元。
* 设f(x)为第x个月还剩贷款本金,y为利率,能推出f(x)=(4000 + f(x+1)) / (1+y)。我能循环地求数值解,但是我没办法推导出解析解的公司呀。
* 所以只好用二分法,假设最大利率、最小利率、停止条件,然后不停地试验,直到满足要求。
* */
while (true) {
/* 先建好所有月份的列表,后面就可以直接用啦。 */
List<BigDecimal> debt = new ArrayList<>();
for (int i = 0; i < monthes; i++) {
BigDecimal bigDecimal = new BigDecimal("0");
debt.add(bigDecimal);
}
// 先把分母1+y求出来,后面就直接除了。
BigDecimal bigDecimalBottom = new BigDecimal("1");
bigDecimalBottom = bigDecimalBottom.add(interestRate);
/* 遍历每个月份,从最后一个月开始计算,循环地求出每个月的剩余贷款。 */
for (int i = monthes - 2; i >= 0; i--) {
BigDecimal bigDecimalTop = new BigDecimal(annualPay);
bigDecimalTop = bigDecimalTop.add(debt.get(i + 1));
bigDecimalTop = bigDecimalTop.divide(bigDecimalBottom, 10, RoundingMode.HALF_UP);
debt.set(i, bigDecimalTop);
}
/* 显示每次二分法的关键数据。测试时很好用哦。 */
// System.out.println("利率是:" + interestRate);
// System.out.println("利率上限是:" + interestUp);
// System.out.println("利率下限是:" + interestDown);
// System.out.println("本金是:" + debt.get(0).toString());
// System.out.println();
// 求出当前利率的初始贷款,和目标贷款的差值。
BigDecimal difference = debt.get(0).subtract(moneyHouseInitiate);
addTheInterestFlag = difference.signum() > 0;
difference = difference.abs();
// 差值小于设定,就结束。
if (difference.compareTo(tolerantDifference) < 0) {
// 月利率转化为年利率,然后转化成百分比。
System.out.println("问题3,算出来啦,");
System.out.println("利率是:" + interestRate.multiply(new BigDecimal("1200")).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP) + "%。");
System.out.println("贷款金额是:" + debt.get(0).intValue() + "元。\n");
System.out.println();
break;
}
/* 二分法,利率大了就把上限调为当前利率,否则把下限调为当前利率 */
if (addTheInterestFlag) {
interestDown = interestRate;
} else {
interestUp = interestRate;
}
// 新的利率 =(利率上限+利率下限)/ 2
interestRate = interestUp.add(interestDown).divide(new BigDecimal("2"), 10, RoundingMode.HALF_UP);
}
System.out.println("代码结束。");
}
}
代码的运行结果:
问题1,去年我有Y元,房价Z元,我能买Y/Z的房子;今年房价1.06×Z元,我能买Y/(1.06×Z)的房子。以房子作为参考系,金钱贬值为(Y/(1.06×Z)) / (Y/Z) = 1/1.06 , 约等于:94.3396226400%,
存款20年,最终的钱是:960000元。
这里算出今天299332元的房子,等于20年后960000的存款。
问题2,当然是叠加的啦。
问题3,算出来啦,
利率是:15.25%。
贷款金额是:299332元。