众所周知,现在银行的分期贷款利率是很有诱惑性人。表面看利率是很低的,例如招行的闪电贷有时给我的利率是4.3%

但是,由于贷款是分期还本的,我手上的本金每月都在减少,到最后一个月时手上只有少量本金,但是还的利息却还是跟第一个月一样。

  excel提供了一个公式叫irr,专门用来计算这种分期贷款实际利率的。

irr函数有两个参数,第一个是现金流,第二个是预估值。只要我们根据贷款情况填好总贷款金额和每月还款金额就可以算出每月的内部收益率。

月内部收益率*12就是我们的实际贷款利率。预估值一般不用填,只有irr计算失败返回#NUM!才要考虑填,具体可见office官方说明。

  https://support.office.com/zh-cn/article/IRR-%E5%87%BD%E6%95%B0-64925eaa-9988-495b-b290-3ad0c163c1bc

  为方便计算,我做了一个excel表格,有兴趣大家可以去下载。只要输入下面图片黄底黑体列,即可自动得出折算年利率。招行的闪电贷利率表面看是4.3%,实际年化利率是7.84%。

  如果你把钱投理财产品,没有7.84%以上你实际是亏本的。

  当然,本文重点不是介绍irr函数,而是我写(抄)的一个计算irr的程序(函数)。使用的是二分迭代法(网上看还有牛顿迭代法和加速迭代法,这两种需要用到数学知识)

之所以用c语言写一个,原因是我们最近项目组有一个c程序需要计算内部收益率。我从网上找了一个程序改了一下,变成一个函数,并加上注释,方便理解和调用。

  程序和代码还有前面提到的表格我都已经上传,有需要可以去下载。实现代码如下:

// testirr.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <math.h> //const double zero = 1e-5; //int n; /*
//代码是在csdn上找到的 我拿下来改了一下
//https://blog.csdn.net/dinghaoseu/article/details/50322117
//这是原来的代码
double quickpow(double a, int b)
{
double ans = 1;
while(b)
{
if(b & 1) ans = ans * a;
a = a * a;
b >>= 1;
}
return ans;
} double makeans(double irr)
{
double ans = 0;
for(int i = 1; i <= n; i++)
ans += ( a[i] / (quickpow(1 + irr, i)) );
return ans;
}
*/
//计算流出Npv
double getNpvOut(double irr, const double arrOutMoney[], int n)
{
double npv = ;
double denominator = + irr; //分母
double multiplier = denominator; //乘数 for (int i = ; i <= n; ++i)
{
npv += arrOutMoney[i] / denominator; //即:arrOutMoney[i] / (quickpow(1 + irr, i)
denominator *= multiplier;
} return npv;
} //最小最大IRR(内部收益率) 用于折算年化率计算
//最小值必须大于-1 最大值1其实就足够了,折算成年化收益率是120%(国家规定利率不能超过30%)
//数字越小计算速度越快,为保险计这里填10
#define IRR_MIN -1.0f
#define IRR_MAX 10.0f //二分迭代寻找合适的irr值(如果存在多个irr,取第一次找到的值,不保证大小顺序)
//arrInOutMoney是分期现金流 nArrLen是arrInOutMoney元素个数
//arrInOutMoney[0]必须是负数,代表总分期金额(负数),后面是每期还款金额(正数)
//返回[IRR_MIN, IRR_MAX]之间的数字代表符合要求的IRR值,<IRR_MIN代表找不到合适的IRR
double binarySearchGetIrr(const double arrInOutMoney[], int nArrLen)
{
double l = IRR_MIN, r = IRR_MAX; //irr取值-1~10之间
int n = nArrLen - ;
//int nCnt = 0; while (l < r)
{
//每次从最大和最小期望IRR中间取一个数值进行npv测算
double mid = (l + r) / ;
//现在是用除法求Npv,其实可以改成用乘法求,效率会高一点
//因为计算机处理乘法速度比较快
double npvOut = getNpvOut(mid, arrInOutMoney, n); //++nCnt;
//如果结果等于0说明找到符合要求的IRR
if (fabs(npvOut + arrInOutMoney[]) <= 1e-) //double类型不能直接与0比较判断是否相等
{
//printf("nCnt = %d\n", nCnt); //经测试,一般分12期迭代次数在30~60之间
return mid;
}
//irr越大,npvOut越小,故npvOut太大时irr就应该落在mid和r之间,反之则反之
else if (npvOut > -arrInOutMoney[])
{
l = mid;
}
else
{
r = mid;
}
} //printf("nCnt = %d\n", nCnt);
//找不到返回比IRR_MIN还小的值
return IRR_MIN - ;
} //输入按月分期现金流,输出对应irr和折算年化收益率
//arrInOutMoney是分期现金流 nArrLen是arrInOutMoney元素个数(一般是7或者13)
//arrInOutMoney[0]必须是负数,代表总分期金额,后面是每期还款金额(正数)
//nCheckFlag = 0,代表直接计算irr,否则会先对数据合法性做检查
//返回0代表成功 其它代表失败 失败原因存放在errBuf(调用者需要保证至少有256个字节空间)
int GetIrrAndAnnualizedRate(const double arrInOutMoney[], int nArrLen,
OUT double *pIrr, OUT double *pAnnualizedRate,
int nCheckFlag, OUT char *errBuf)
{
double irr = ; if (nCheckFlag != )
{
double inMoney, outMoney;
int i; if (arrInOutMoney == NULL || nArrLen < )
{
strcpy(errBuf, "arrInOutMoney需要非空并且元素个数大于2个");
return -;
} inMoney = arrInOutMoney[];
outMoney = ;
for (i = ; i < nArrLen; ++i)
{
if (arrInOutMoney[i] < )
{
//不支持多次现金流入(因为没这个需求,不要浪费计算力)
outMoney = -;
break;
}
outMoney += arrInOutMoney[i];
} if (inMoney >= || (-inMoney > outMoney))
{
strcpy(errBuf, "第一个元素必须是负现金流,之后每个元素均是正现金流,"
"并且正现金流之和要大于负现金流");
return -;
}
} irr = binarySearchGetIrr(arrInOutMoney, nArrLen);
if (irr < IRR_MIN)
{
sprintf(errBuf, "%.5f(%.2f%%)~%.5f(%.2f%%)之间无法找到合适的irr,请检查现金流是否输入异常",
IRR_MIN, IRR_MIN * * , IRR_MAX, IRR_MAX * * );
return -;
} *pIrr = irr;
*pAnnualizedRate = irr * * ; return ;
} int getIrrDemo()
{
double irr, annualizedRate;
double a[ * + ];
int n, nRet;
char errBuf[]; printf("**************如果要退出,请在还款期数填0**************\n");
while ((printf("input 还款期数 n(0代表退出):")) && ~scanf("%d", &n) && n)
{
printf("n = %d\n", n);
if (n >= sizeof(a) / sizeof(a[]))
{
printf("n值太大,不支持\n");
continue;
} printf("输入分期金额(负数):");
if (scanf("%lf", &a[]) != ) {
printf("输入的金额不能包含非数字和小数点\n");
getchar();
continue;
} printf("输入%d期还款金额(正数),每输入一期按一次回车:", n);
for (int i = ; i <= n; i++)
{
scanf("%lf", &a[i]);
} nRet = GetIrrAndAnnualizedRate(a, n + , &irr, &annualizedRate, , errBuf);
if (nRet != )
{
printf("error:[%s]\n", errBuf);
continue;
} //计算irr常用的方法是迭代计算,即不断尝试可能值,根据尝试结果缩小范围,直到找到符合要求的值
//网上能找到的迭代算法有二分迭代,牛顿迭代,加速迭代,其中二分迭代最好理解,最容易开发
irr = binarySearchGetIrr(a, n + );
if (irr < IRR_MIN)
{
printf("找不到合适的irr\n");
}
else
{
printf("irr = %.6f 年化收益率(12 * irr) = %.4f%%\n", irr, annualizedRate);
}
} return ;
} int main(int argc, char *argv[])
{
getIrrDemo();
//system("pause");
return ;
}

  

  

使用c语言计算分期贷款折算年化收益率(内部收益率IRR*12)的更多相关文章

  1. R语言计算moran‘I

    R语言计算moran‘I install.packages("maptools")#画地图的包 install.packages("spdep")#空间统计,m ...

  2. R语言计算相关矩阵然后将计算结果输出到CSV文件

    R语言计算出一个N个属性的相关矩阵(),然后再将相关矩阵输出到CSV文件. 读入的数据文件格式如下图所示: R程序采用如下语句: data<-read.csv("I:\\SB\land ...

  3. R语言计算IV值

    更多大数据分析.建模等内容请关注公众号<bigdatamodeling> 在对变量分箱后,需要计算变量的重要性,IV是评估变量区分度或重要性的统计量之一,R语言计算IV值的代码如下: Ca ...

  4. [转帖]C语言计算时间函数 & 理解linux time命令的输出中“real”“user”“sys”的真正含义

    C语言计算时间函数 & 理解linux time命令的输出中“real”“user”“sys”的真正含义 https://blog.csdn.net/willyang519/article/d ...

  5. C语言计算两个日期间隔天数

    在网上看到了一个C语言计算日期间隔的方法,咋一看很高深,仔细看更高神,很巧妙. 先直接代码吧 #include <stdio.h> #include <stdlib.h> in ...

  6. 闰年计算——JavaScript 语言计算

    ㈠闰年是如何来的? 闰年(Leap Year)是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的.补上时间差的年份为闰年. ㈡什么是闰年? 凡阳历中有闰日(二月为二十九日)的年, ...

  7. [R语言]R语言计算unix timestamp的坑

    R+mongo的组合真是各种坑等着踩 由于mongo中的时间戳普遍使用的是unix timestamp的格式,因此需要对每天的数据进行计算的时候,很容易就想到对timestamp + gap对方式来实 ...

  8. C语言计算开方

    C语言里面有sqrt可以计算开平方根,但似乎想要计算开任意次方根的话却没有一个固定的函数,自己写算法也蛮啰嗦的…… 其实啊,巧妙使用pow函数就可以实现需求. C语言库函数pow的原型声明如下: #i ...

  9. 使用R语言-计算均值,方差等

    R语言对于数值计算很方便,最近用到了计算方差,标准差的功能,特记录. 数据准备 height <- c(6.00, 5.92, 5.58, 5.92) 1 计算均值 mean(height) [ ...

随机推荐

  1. [2018HN省队集训D5T1] 沼泽地marshland

    [2018HN省队集训D5T1] 沼泽地marshland 题意 给定一张 \(n\times n\) 的棋盘, 对于位置 \((x,y)\), 若 \(x+y\) 为奇数则可能有一个正权值. 你可以 ...

  2. sql 模糊查询优化

    在sql语句中使用 like模糊查询时,应该尽量避免%%,因为模糊查询是比较慢的,当出现这样的情况时,应该考虑优化. 举个例子:我在表中查询2012 年创建的记录 SELECT * FROM `com ...

  3. JavaScript基础进阶之常用字符串方法总结

    前面三篇文章简单的把JavaScript基础内容过了一遍,我们已经可以用JavaScript写一些简单的代码了. 今天主要总结一下JavaScript中String对象中自带的一些方法,来帮助我们处理 ...

  4. 盒子模型之margin相关技巧!

    废话不多说,直接进入主题,margin相关技巧. 1.设置元素水平居中:margin:x auto; 2.margin负值让元素位移及边框合并. 外边距合并 指当两个垂直外边距相遇时,它们将形成一个外 ...

  5. FWT背板笔记

    板子 背板子.jpg \(Fwt\)用于解决这样的问题 \[C_i=\sum_{j\bigoplus k=i}A_j\times B_k\] 其中\(\bigoplus\)是一种二元运算符,如\(or ...

  6. input框动态模糊查询,能输入,能选择

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Day2 MySql函数以及单表查询

    SQL中的运算符 算术运算符 --算术运算符(子句) ; ; ; ; --0.75 ; --NULL div ; 比较运算符> < >= <= != = --0表示false, ...

  8. Python的多线程和多进程

    (1)多线程的产生并不是因为发明了多核CPU甚至现在有多个CPU+多核的硬件,也不是因为多线程CPU运行效率比单线程高.单从CPU的运行效率上考虑,单任务进程及单线程效率是最高的,因为CPU没有任何进 ...

  9. Rserve详解,R语言客户端RSclient【转】

    R语言服务器程序 Rserve详解 http://blog.fens.me/r-rserve-server/ Rserve的R语言客户端RSclient https://blog.csdn.net/u ...

  10. model 在线生成工具

    记录一个在线的model生成工具 快捷开发  so easy http://modelend.com