我在计算双重总和时遇到了问题。当我将迭代设置为100000时,函数Asian_call_MC仍然返回一个数字。但是,当我将迭代设置为大约500000及以上时,它开始返回1.#INF。有人能告诉我它为什么会发生以及如何解决它?我正在使用visual studio 2013来编写c ++代码。
double Avg_Price(double init_p, double impl_vol, double drift, int step, double deltasqrt)
{
//Calculate the average price of one sample path
//delta = T/ step
//drift = (risk_free - div_y - impl_vol*impl_vol / 2)*(T / step)
double Sa = 0.0;
double St = init_p;
for (int i = 0; i < step; i++)
{
St = St*exp(drift + impl_vol*deltasqrt*normal_gen());
//Sa = Sa * i / (i + 1) + St / (i + 1);
Sa += St;
}
Sa = Sa / double(step);
return Sa;
}
double Asian_call_MC(double strike_p, double T, double init_p, double impl_vol, double risk_free, double div_y, int iter, int step)
{
//Calculate constants in advance to reduce computation time
double drift = (risk_free - div_y - impl_vol*impl_vol / 2)*double(T / step);
double deltasqrt = sqrt(double(T / step));
//Generate x1, average x and y
double cur_p = Avg_Price(init_p,impl_vol,drift,step,deltasqrt);
double pay_o=0.0;
double x = max(cur_p - strike_p,0.0);
//double y = pow(x, 2.0);
//Generate x2 to xn
for (int i = 0; i < iter; i++)
{
cur_p = Avg_Price(init_p, impl_vol, drift, step, deltasqrt);
x = max(cur_p - strike_p,0.0);
//double q = double(i) / double(i + 1);
//pay_o = pay_o *i/(i+1) + x / (i + 1);
pay_o += x;
//y = (1 - (1 / (i + 1)))*y + x*x / (i + 1);
}
//pay_o = pay_o / double(iter);
//stdev = sqrt((y - pow(pay_o , 2)) / (iter - 1));
//return pay_o*exp(-risk_free*T) ;
return pay_o;
}
答案 0 :(得分:1)
当您增加迭代次数时,您将增加总和的值。在某些时候,该值会溢出double
中可能包含的值,从而返回表示无穷大的1.#INF
值作为您计算的值。这样做是因为计算出的值大于一对中的值。
要解决此问题,您需要将保存总和的变量更改为可以保存的数字大于double
的变量。起点是使用long double
。
另一种选择是在for
循环后构建一些逻辑,以便处理较小的数字。如何执行此操作将取决于您要精确计算的字符串。
答案 1 :(得分:0)
你已经满溢双重所能容纳的东西。 INF是无穷大的缩写,是溢出浮点时得到的错误代码。
根据编译器的不同,long double可能会有所帮助,也可能没有帮助。在Microsoft C ++中,我认为long double和double都是64位,所以没有运气。
查看Boost multiprecision库,它有更大的类型,如果你真的需要大的东西,不能重做你的数学。我看到你正在成倍增加然后分裂。你可以将一些乘法,然后除法,然后再乘以一些来节省空间吗?
答案 2 :(得分:0)
看起来你想要计算平均值。大多数人学习计算均值的方法是总结所有的值,然后将总和除以导致总和的值的数量。
这种方法存在一些与之相关的问题 - 例如,在一起添加多个值可能会给持有它的变量一个太大的总和。
经常使用另一种技术,它会积累一个&#34;运行&#34;意味着而不是总和。运行平均值的值始终是已累积的所有样本的平均值,因此它永远不会爆炸成溢出(浮点无穷大)值(除非其中一个累积样本为无穷大)。
下面的示例演示了如何计算运行平均值。它还计算总和,并显示总和/计数与运行平均值的比较(表明它们是相同的 - 我没有让它运行足够长的时间来溢出总和)。
该示例使用C-Library rand(),用于演示目的 - 我只需要一些东西来计算平均值。
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
int main() {
srand(static_cast<unsigned>(time(0)));
double count = 0;
double running_mean = 0;
double sum = 0;
auto start = time(0);
auto end = start + 5;
while(time(0) < end) {
double sample = rand();
count += 1;
running_mean += (sample - running_mean)/count;
sum += sample;
}
std::cout << std::setprecision(12);
std::cout << "running mean:" << running_mean << " count:" << count << '\n';
double sum_mean = sum / count;
std::cout << "sum:" << sum << " sum/count:" << sum_mean << '\n';
}
编辑:他已经尝试过这个 - 该技术出现在我在OP代码
中遗漏的注释掉的行中与通过累积总和来计算平均值不同,运行平均技术不能简单地在某个时刻溢出。因此,知道他已经尝试过并且它没有帮助解决这个问题,可能的原因就是迭代的一个术语本身就是INF。只要添加单个INF术语,累积的总和或平均值将变为INF并保持INF。
代码中最可能的部分是normal_gen()
,用于调用exp
函数。名称normal_gen()
听起来像是正常分布的随机值的来源。通常的实现采用Box-Muller变换,其不能产生超过平均值约7个标准偏差的值。因此,如果Box-Muller生成器导致INF,则可能在比报告的迭代次数更少的情况下发生。但是,更先进的生成器可以产生更多的极值 - 理想情况下,正态分布具有非零概率产生任何有限实际值。
如果一个随机大的Normal样本是引起问题的原因,那么它与迭代计数增加的相关性就不会是更多的迭代使总和膨胀,通过添加更多的值来溢出 - 这将是更多迭代给出的该程序更有可能达到一个不太可能的随机值,这将导致一个INF术语。