zzuli 1332 内部收益率 (湖南省第六届大学生计算机程序设计竞赛)
在金融中,我们有时会用内部收益率IRR来评价项目的投资财务效益,它等于使得投资净现值NPV等于0的贴现率。换句话说,给定项目的期数T、初始现金流CF0和项目各期的现金流CF1, CF2, ...,CFT,IRR是下面方程的解:
为了简单起见,本题假定:除了项目启动时有一笔投入(即初始现金流CF0 < 0
)之外,其余各期均能赚钱(即对于所有i=1,2,...,T
,CFi > 0
)。根据定义,IRR可以是负数,但不能小于-1。
Input
输入文件最多包含25组测试数据,每个数据占两行,第一行包含一个正整数T(1<=T<=10),表示项目的期数。第二行包含T+1个整数:CF0, CF1, CF2, ..., CFT,其中CF0< 0, 0 < CFi< 10000 (i=1,2,...,T)。T=0表示输入结束,你的程序不应当处理这一行。
Output
对于每组数据,输出仅一行,即项目的IRR,四舍五入保留小数点后两位。如果IRR不存在,输出"No",如果有多个不同IRR满足条件,输出"Too many"(均不含引号)
Sample Input
1
-1 2
2
-8 6 9
0
Sample Output
1.00
0.50
由题意可知, 解的范围为从(-1, +∞);由于改式子具有单调性,所以可以直接二分。上界之所以设置为50,是因为double
的数据范围
代码如下:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
int arr[17];
int t;
bool judge(double x)
{
double res = 0;
for(int i=0; i<=t; ++ i)
res += 1.0 * arr[i] / pow((1+x), i);
return res > 0;
}
int main()
{
while(scanf("%d",&t), t != 0)
{
for(int i=0; i<=t; ++ i)
scanf("%d", &arr[i]);
double b = eps-1, e = 50;
if(judge(b) == false)
{
printf("No\n");
continue;
}
while(e-b > eps)
{
double mid = (e+b)/2;
if(judge(mid))
b = mid;
else
e = mid;
}
printf("%.2f\n", b);
}
return 0;
}
方法二是根据牛顿迭代法求一个方程近似解。
今天最大收获就是学会了牛顿迭代法, 感觉超级叼啊。
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
int arr[17];
int t;
double cou(double x)
{
double res = 0;
for(int i=0, j=t; i<=t; ++ i, -- j)
res += arr[i] * pow((1+x), j);
return res;
}
double cou2(double x)
{
double res = 0;
for(int i=0, j=t-1; i<t; ++ i, -- j)
res += pow((1+x), j) * arr[i] * (j + 1);
return res;
}
int main()
{
while(scanf("%d",&t), t != 0)
{
for(int i=0; i<=t; ++ i)
scanf("%d", &arr[i]);
if(cou(eps-1) < 0)
{
printf("No\n");
continue;
}
while(true)
{
srand(time(0));
double ans = (1.0 * rand() / INT_MAX * 50);
double res = ans + 1;
while(fabs(ans - res) > eps)
{
res = ans;
ans = ans - cou(ans) / cou2(ans);
}
if(ans > eps - 1)
{
printf("%.2f\n", ans);
break;
}
}
}
return 0;
}