林惜城


私信TA

用户名:reminder

访问量:31294

签 名:

等  级
排  名 91
经  验 9070
参赛次数 0
文章发表 95
年  龄 0
在职情况 学生
学  校 西安电子科技大学
专  业

  自我简介:

哈姆


解题思路:

(1)首先优质题解第一那位的代码是有问题的,我在 debug 卡住的时候试了一下他的代码,结果原封不动贴到 IDE 输出的和标准答案不符。

(2)那个兄弟的问题好像是把“判断 NPV 是否接近 0” 和“更新 IRR”两句顺序写错了,也不一定,毕竟我没细看。

(3)但是解题思路是没问题的,就是二分法找零点,因为 NPV(IRR) 这个函数的导数是负的,所以只有两种情况:有一个零点或者没有零点,不存在输出 "Too many" 的情况,判断是否有零点的方法是看 NPV(0) 是否为负值,也就是所有现金流加起来,如果是负值那说明 NPV 永远是负值。

(4)二分法找零点没啥好说的吧,高中数学。用了两个 while 循环嵌套,分别用来连续接收数据和更新二分边界。


注意事项:

唯一不理解的地方是 NPV 的计算公式那块,如果写成 for (int i = 0; i < T + 1; ++i) {    NPV += (term[i] / pow(IRR, i));    } 就没法正常接收,但是先加一句 NPV = 0 就正常了,可是 double 型数据不是默认初始化为 0 吗?想不通。看了我源码的朋友可以自己试一试,最好能在评论留言教教我。


参考代码:

// 题目 1076: 内部收益率
#include <iostream>
#include <cmath>
#include <vector>
#include <iomanip>

using namespace std;

int main() {

	int T, CF, sum;     // 期数,现金流,现金流之和(用于判断是否有零点)
	double left, right; // 二分法的边界
	double IRR, NPV;    // 内部收益率(+1后的正值)和投资净现值

	while (cin >> T && T) {
		vector<int> term; // 保存各期现金流
		for (int i = 0; i < T + 1; ++i) {
			cin >> CF;
			term.push_back(CF); //直接 cin >> term[i] 会出问题
			sum += CF;
		}
		if (sum < 0) {
			cout << "No" << endl;
			break; // 没有零点
		}

		// 初始化,默认给这个范围
		left = 0;
		right = 1e6;
		IRR = 1.5;

		while (1) {

			/* 两种写法,但是没有 NPV = 0 这句话就没法放进下面的 for 中,原因不明
			NPV = 0;
			for (int i = 0; i < T + 1; ++i) {
				NPV += (term[i] / pow(IRR, i));
			}
			*/
			NPV = term[0];
			for (int i = 1; i < T + 1; ++i) {
				NPV += (term[i] / pow(IRR, i));
			}

			if (fabs(NPV) <= 1e-5) {
				break; // 接近0时默认为找到了零点,否则可能计算量巨大
			}

			// 二分法
			if (NPV < 0) {
				right = IRR;
			} else {
				left = IRR;
			}
			IRR = (left + right) / 2;
		}
		cout << fixed << setprecision(2) << IRR - 1 << endl;
	}
	return 0;
}


 

0.0分

6 人评分

  评论区

题有问题,大家可以把给的示例第二组带入方程算一下,一个根确实是0.5但还有一个根是-7/4小于-1,是满足条件的。但给出的的示例答案错了。应该是too many
2022-11-29 08:58:30
在函数体外部定义的全局变量,默认初始化为0;
在函数体内定义的局部变量,默认会被初始化为随机数
2022-07-03 15:43:14
  • «
  • 1
  • »