zzuli 1332 内部收益率 (湖南省第六届大学生计算机程序设计竞赛)

在金融中,我们有时会用内部收益率IRR来评价项目的投资财务效益,它等于使得投资净现值NPV等于0的贴现率。换句话说,给定项目的期数T、初始现金流CF0和项目各期的现金流CF1, CF2, ...,CFT,IRR是下面方程的解:

image

为了简单起见,本题假定:除了项目启动时有一笔投入(即初始现金流CF0 < 0)之外,其余各期均能赚钱(即对于所有i=1,2,...,TCFi > 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;
}
posted @ 2017-05-01 20:02  aiterator  阅读(253)  评论(0编辑  收藏  举报