1. 函数介绍

最近有用到计算一些投资现金与未来收益的场景,产品经理使用了excel公式,我也只能找找解决方法。

参考:

  • 微软 PV函数
  • 微软 FV函数
  • 微软 PMT函数

这三个函数的计算,其实都是从一个数据公式代换来的:

2. 工具类与官方示例结果有不一样的地方

注意:下方展示的代码与excel中计算的结果相似,但是和微软的官方示例结果不同,官方示例的结果小数位不同

不同之处--1:FV函数的结果不同
① 自己的excel公式计算结果


② 官方的示例结果


不同之处--2、官方示例excel对比


PV函数与PMT函数基本一样,只有四舍五入的区别。

3. 工具类源码

/** * PMT 是一个财务函数,用于根据固定付款额和固定利率计算贷款的付款额。 * * @param rate 必需。 贷款利率。 * @param nper 必需。 该项贷款的付款总数。 * @param pv 必需。 现值,或一系列未来付款额现在所值的总额,也叫本金。 * @param fv 可选。 未来值,或在最后一次付款后希望得到的现金余额。 如果省略 fv,则假定其值为 0(零),即贷款的未来值是 0。 * @param Type 可选。 0或省略-期末,1-期初 * @return */ private static double PMT(double rate, double nper, double pv, double fv, double type) { if (rate == 0) { throw new RuntimeException("缺少年利率"); } double pmt = (pv*Math.pow(1 + (rate / 12), nper)+fv)/((Math.pow(1 + (rate / 12), nper)-1)/(rate / 12))/(1 + (rate / 12)*type)*(-1); return new BigDecimal(pmt).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** *参考:https://support.microsoft.com/zh-cn/office/pv-%E5%87%BD%E6%95%B0-23879d31-0e02-4321-be01-da16e8168cbd * * PV 是一个财务函数,用于根据固定利率计算贷款或投资的现值。 * 可以将 PV 与定期付款、固定付款(如按揭或其他贷款)或投资目标的未来值结合使用。 * * @param Rate 必需。 各期利率。 例如,如果您获得年利率为 10% 的汽车贷款,并且每月还款一次,则每月的利率为 10%/12(即 0.83%)。 您需要在公式中输入 10%/12(即 0.83%)或 0.0083 作为利率。 * @param Nper 必需。 年金的付款总期数。 例如,如果您获得为期四年的汽车贷款,每月还款一次,则贷款期数为 4*12(即 48)期。 您需要在公式中输入 48 作为 nper。 * @param Pmt 必需。 每期的付款金额,在年金周期内不能更改。 通常,pmt 包括本金和利息,但不含其他费用或税金。 例如,对于金额为 ¥100,000、利率为 12% 的四年期汽车贷款,每月付款为 ¥2633.30。 您需要在公式中输入 -2633.30 作为 pmt。 如果省略 pmt,则必须包括 fv 参数。 * @param fv 可选。 未来值,或在最后一次付款后希望得到的现金余额。 如果省略 fv,则假定其值为 0(例如,贷款的未来值是 0)。 例如,如果要在 18 年中为支付某个特殊项目而储蓄 ¥500,000,则 ¥500,000 就是未来值。 然后,您可以对利率进行保守的猜测,并确定每月必须储蓄的金额。 如果省略 fv,则必须包括 pmt 参数。 * @param type 可选。 数字 0 或 1,用以指定各期的付款时间是在期初还是期末。 * * PS: pmt与fv至少出现一个! * * @return */ public static double PV(double rate, double nper, double pmt, double fv, double type) { /** * 如果年化收益率为零,monthRate作分母会出现NaN错误,需要对年利率为零进行特殊处理 */ if (rate == 0) { return nper * pmt; } double result = -(fv+pmt*(1 + (rate / 12)*type)*((Math.pow(1 + (rate / 12), nper)-1)/(rate / 12)))/Math.pow(1 + (rate / 12), nper); return new BigDecimal(result).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); } // FV(rate,nper,pmt,pv,type) /** *参考:https://support.microsoft.com/zh-cn/office/fv-%E5%87%BD%E6%95%B0-2eef9f44-a084-4c61-bdd8-4fe4bb1b71b3 * * FV 是一个财务函数,用于根据固定利率计算投资的未来值。 * 可以将 FV 与定期付款、固定付款或一次付清总额付款结合使用。 * * @param Rate 必需。 各期利率。年利率,月利率=年利率/12 * @param Nper 必需。 年金的付款总期数。 * @param Pmt 必需。 各期所应支付的金额,在整个年金期间保持不变。 通常 pmt 包括本金和利息,但不包括其他费用或税款。 如果省略 pmt,则必须包括 pv 参数。 * @param pv 可选。 现值,或一系列未来付款的当前值的累积和。 如果省略 pv,则假定其值为 0(零),并且必须包括 pmt 参数。 * @param type 可选。 数字 0 或 1,用以指定各期的付款时间是在期初-1还是期末-0。 如果省略 type,则假定其值为 0。 * * PS: pmt与fv至少出现一个! * * @return */ public static double FV(double rate, double nper, double pmt, double pv, double type) { /** * 如果年化收益率为零,monthRate作分母会出现NaN错误,需要对年利率为零进行特殊处理 */ if (rate == 0) { return nper * pmt; } // "1 + (rate / 12)"的nper次幂 BigDecimal powers = new BigDecimal(Math.pow(1 + (rate / 12), nper)); double fv = -1*(pv*powers.doubleValue()+pmt*(1 + (rate / 12)*type)*((powers.doubleValue()-1)/(rate / 12))); return new BigDecimal(fv).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); } public static void main(String[] args) { // 结果:PV:597771.46 System.out.println("PV:"+PV(0.08, 240, -5000,0,0)); // FV:2581.4 System.out.println("FV:"+FV(0.06, 10, -200,-500,1)); // 要在 18 年以后有一笔 ¥500,000 的年金,每月需存入金额。 // pmt:1290.81 System.out.println("pmt:"+PMT(0.06, 18*12, 0,-500000,0)); // 指定参数条件下贷款的月支付额,不包括支付期限在期初的支付额。 // pmt:10301.64 System.out.println("pmt:"+PMT(0.08, 10, -100000,0,1)); }

如有优化的地方,敬请指点!