使用c语言计算分期贷款折算年化收益率(内部收益率IRR*12)
众所周知,现在银行的分期贷款利率是很有诱惑性人。表面看利率是很低的,例如招行的闪电贷有时给我的利率是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)的更多相关文章
- R语言计算moran‘I
R语言计算moran‘I install.packages("maptools")#画地图的包 install.packages("spdep")#空间统计,m ...
- R语言计算相关矩阵然后将计算结果输出到CSV文件
R语言计算出一个N个属性的相关矩阵(),然后再将相关矩阵输出到CSV文件. 读入的数据文件格式如下图所示: R程序采用如下语句: data<-read.csv("I:\\SB\land ...
- R语言计算IV值
更多大数据分析.建模等内容请关注公众号<bigdatamodeling> 在对变量分箱后,需要计算变量的重要性,IV是评估变量区分度或重要性的统计量之一,R语言计算IV值的代码如下: Ca ...
- [转帖]C语言计算时间函数 & 理解linux time命令的输出中“real”“user”“sys”的真正含义
C语言计算时间函数 & 理解linux time命令的输出中“real”“user”“sys”的真正含义 https://blog.csdn.net/willyang519/article/d ...
- C语言计算两个日期间隔天数
在网上看到了一个C语言计算日期间隔的方法,咋一看很高深,仔细看更高神,很巧妙. 先直接代码吧 #include <stdio.h> #include <stdlib.h> in ...
- 闰年计算——JavaScript 语言计算
㈠闰年是如何来的? 闰年(Leap Year)是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的.补上时间差的年份为闰年. ㈡什么是闰年? 凡阳历中有闰日(二月为二十九日)的年, ...
- [R语言]R语言计算unix timestamp的坑
R+mongo的组合真是各种坑等着踩 由于mongo中的时间戳普遍使用的是unix timestamp的格式,因此需要对每天的数据进行计算的时候,很容易就想到对timestamp + gap对方式来实 ...
- C语言计算开方
C语言里面有sqrt可以计算开平方根,但似乎想要计算开任意次方根的话却没有一个固定的函数,自己写算法也蛮啰嗦的…… 其实啊,巧妙使用pow函数就可以实现需求. C语言库函数pow的原型声明如下: #i ...
- 使用R语言-计算均值,方差等
R语言对于数值计算很方便,最近用到了计算方差,标准差的功能,特记录. 数据准备 height <- c(6.00, 5.92, 5.58, 5.92) 1 计算均值 mean(height) [ ...
随机推荐
- 你可能不知道的 10 条 SQL 技巧,涨知识了!
转自:http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&mid=2650076293&idx=1&sn=38f6acc759df ...
- 【转】【Flex】FLEX 学习网站分享
[转:http://hi.baidu.com/tanghecaiyu/item/d662fbd7f5fbe02c38f6f764 ] FLEX 学习网站分享 http://blog.minidx.co ...
- Spring源码分析之IOC容器(一)
Spring作为当今风靡世界的Web领域的第一框架,作为一名Java开发程序员是一定要掌握的,除了需要掌握基本的使用之外,更需要掌握其实现原理,因为我们往往在开发的过程中,会出现各种各样的异常问题.而 ...
- java微信小程序解密AES/CBC/PKCS7Padding
摘要:微信小程序解密建议使用1.6及以上的环境使用maven下载jar包org.bouncycastlebcprov-jdk15on1.55加密类代码importorg.bouncycastle.jc ...
- VMWare虚拟机下为Windows Server 2012配置静态IP(NAT方式)
利用VMWare Workstation安装了Windows Server 2012 R2, 对于服务器来说,使用动态分配的IP会很不方便,最好设置为静态IP,此例中虚拟机和主机的网络联接方式为NAT ...
- ECharts 定制 label 样式
起因 实现对 label 的样式定制,自定义字体颜色.大小等属性:效果如下图 实现 itemStyle: { normal: { color: '#f7ba0e', label: { ...
- sqooq同步mysql tinyint类型到hive的一个诡异问题
sqoop job运行完成之后,发现为tinyint类型的一类始终没有值,经检查发现上游mysql有值,再查看hdfs文件,发现这列被抓换为了boolean类型 搜索一下发现有人碰到过了,以下原文来自 ...
- ansible-playbook快速入门
一.yaml语法: 1. yaml语法编写 1.1 同层级的字段通过相同缩进表示 1.2 map结构里面key/value用‘:’来分隔 1.3 key/value可以同行写,也可以换行写,换行写必须 ...
- yii在哪些情况下可以加载yiilite.php?
yii权威指南上说,在开启apc缓存的情况下,可以加载yiilite.php提升性能.我有以下几点疑问: 1.开启apc缓存的情况下,引入yiilite.php能提升性能的原因是因为缓存了opcode ...
- virtualbox+vagrant学习-2(command cli)-27-vagrant connect命令
Connect 命令: vagrant connect NAME connect命令通过启用对共享环境的访问来补充share命令.你可以在“vagrant share”部分了解有关vagrant sh ...