众所周知,现在银行的分期贷款利率是很有诱惑性人。表面看利率是很低的,例如招行的闪电贷有时给我的利率是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. 深入浅出SharePoint——配置List通过邮件来接收内容

    应用场景:在SharePoint的开发中,我们经常需要通过接收并解析Mail的方式来进行数据通信. 解决方案:通常有两种方式:一种是直接使用公司的Exchange服务器,一种是在SharePoint ...

  2. Hibernate查询(HQL——Hibernate Query Language)

    HQL查询 HQL提供了是十分强大的功能,它是针对持久化对象,用取得对象,而不进行update,delete和insert等操作.而且HQL是面向对象的,具备继承,多态和关联等特性. from子句: ...

  3. 利用Jquey.hover来实现 鼠标移入出现删除按钮,鼠标移出删除消失

    Html代码 <div class="box"><div class="bmbox" onclick="$('.box:first' ...

  4. Java设计模式16:常用设计模式之观察者模式(行为型模式)

    1. Java之观察者模式(Observer Pattern) (1)概述: 生活中我们在使用新闻app,当我们对某一栏比较感兴趣,我们往往会订阅这栏新闻,比如我对军事栏感兴趣,我就会订阅军事栏的新闻 ...

  5. 基于反射启动Spring容器

    基于反射启动Spring容器 package com.maple.test; import org.springframework.context.ApplicationContext; import ...

  6. [JSOI2008]Blue Mary的战役地图

    嘟嘟嘟 当看到n <= 50 的时候就乐呵了,暴力就行了,不过最暴力的方法是O(n7)……然后加一个二分边长达到O(n6logn),然后我们接着优化,把暴力比对改成O(1)的比对hash值,能达 ...

  7. 最新版的Chrome 69.0 设置始终开启flash而不是先询问

    ## 69.0 之前的版本 ##   1.打开 chrome://settings/content/flash   2.禁止网站运行Flash -> 改为“Ask (Default)”   3. ...

  8. 初识Qt窗口界面

    1.新建一个新的Qt Gui应用,项目名称随意,例如MyMainWindow,基类选择QMainWindow,类名为MainWindow. 2.项目建立后,双击mainwindow.ui文件,在界面的 ...

  9. 一个简单好用的http服务器

    http-server 是一个简单的零配置命令行HTTP服务器, 基于 nodeJs. 如果你不想重复的写 nodeJs 的 web-server.js, 则可以使用这个. 安装 (全局安装加 -g) ...

  10. webpack一小时入门

    什么是 webpack? webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX).coffee.样式(含less/sass).图片等都作为模块来使用和处理. 我们可以 ...