比较向量中的元素时花费的时间呈指数增长

Time taken increasing exponentially when comparing elements in vectors

我有一段代码如下所示:

void MonteCarloRainbowOptionFunction::ValueInstrument()
{
    std::vector<MJArray> correlatedNormVariates = GetArraysOfCorrelatedGauassiansByBoxMuller(numberOfPaths, covMatrix); 
    std::vector<StatisticAllPaths> thesePathGatherers;
    for (unsigned long i = 0; i < S_vect.size(); i++)
    {
        StandardExcerciseOption thisOption(ThePayOffVect[i], TTM);
        StatisticAllPaths onePathGatherer;
        thesePathGatherers.push_back(onePathGatherer);
        OneStepMonteCarloValuation(thisOption, S_vect[i], impvol_vect[i], r, d_vect[i], numberOfPaths, correlatedNormVariates[i], thesePathGatherers[i]);
    }
    f = 0;
    for (unsigned long i = 0; i < numberOfPaths; i++)
    {       
        int count = 0;
        if (i % 2500 == 0)
        {
            count += 1;
            std::cout << i << " paths done" << "\n";
        }
        std::vector<double> outcomes;
        for (unsigned long j = 0; j < S_vect.size(); j++)
        {
            outcomes.push_back(thesePathGatherers[j].GetResultsSoFar()[0][i]);
        }
        switch (optionType)
        {
        case RainbowOptionType::best_of:
            f += *max_element(outcomes.begin(), outcomes.end());
            break;
        case RainbowOptionType::worst_of:
            f += *min_element(outcomes.begin(), outcomes.end());
            break;          
        default:
            throw std::runtime_error("Unsupported or unknown option type found in " + GetuniqueIdentifier()[0]);
            break;
        }   
    }
    f *= ((double)nominal/numberOfPaths);
    return;
}

在第一部分(在第一部分之前 "Time Check")我模拟了大量的值,这些值通过函数 OneStepMonteCarloValuation 保存在向量中(实际上在向量向量的第一个向量中)thesePathGatherers。像这样(这样做花费的时间最少):

void OneStepMonteCarloValuation(const StandardExcerciseOption& TheOption, double Spot, double Vol, double r, double d, unsigned long NumberOfPaths, MJArray normVariates, StatisticsMC& gatherer)
{
    if (normVariates.size() != NumberOfPaths)
        throw("mismatched number of paths and normal variates");
    //Pre-calculate as much as possible
    double Expiry = TheOption.GetExpiry();
    double variance = Vol * Vol * Expiry;
    double rootVariance = sqrt(variance);
    double itoCorrection = -0.5 * variance;
    double movedSpot = Spot * exp((r-d) * Expiry + itoCorrection);
    double thisSpot;
    double discounting = exp(-r * Expiry);
    for (unsigned long i = 0; i < NumberOfPaths; i++)
    {
        thisSpot = movedSpot * exp(rootVariance * normVariates[i]);
        double thisPayoff = TheOption.OptionPayOff(thisSpot);
        gatherer.DumpOneResult(discounting * thisPayoff);
    }
    return;
}

这里调用的 gatherer 是 class:

StatisticAllPaths::StatisticAllPaths(const unsigned long minimumNumberOfPaths) : PathsDone(0)
{
    ResultList.reserve(minimumNumberOfPaths);
}

void StatisticAllPaths::DumpOneResult(double result)
{
    ResultList.push_back(result);
    PathsDone++;
}

std::vector<std::vector<double>> StatisticAllPaths::GetResultsSoFar() const
{
    vector<double> innerVector(ResultList);
    vector<vector<double> > Results(1, innerVector);
    Results[0] = ResultList;
    return Results;
}

在第二部分中,我遍历所有向量并将第 i 个元素保存在临时 "output" 向量中,比较输出中的值并保存结果,然后执行相同的操作。遍历 thesePathGatherers 中的所有值。第一部分运行速度很快,但这个部分需要更长的时间,甚至无法一起完成足够多的 numberOfPaths。我添加了这部分:

    if (i % 2500 == 0)
    {
        count += 1;
        std::cout << i << " paths done" << "\n";
    }

调试并发现,例如,如果路径总数很大,则执行前 10^4 条路径会花费更长的时间,即每条路径花费的时间越长,您执行的路径越多。 GetResultsSoFar() implementation/usage 有问题吗?这是我唯一能想到的。任何帮助表示赞赏

如果有更多需要分享的内容,请告诉我。

好吧,您将 ResultList 向量复制了 4 次,这无济于事。

std::vector<std::vector<double>> StatisticAllPaths::GetResultsSoFar() const
{
    vector<double> innerVector(ResultList); //first copy
    vector<vector<double> > Results(1, innerVector); //second copy
    Results[0] = ResultList;// third copy
    return Results;// return by value = fourth copy
}

你最好通过引用传递你的矢量并填充它:

void StatisticAllPaths::GetResultsSoFar(std::vector<std::vector<double>> & result ) const
{
    result.clear(); //discard the current contents if any
    result.push_back(ResultList); //one copy
}

希望对您有所帮助

这里有一些答案着重于 GetResultsSoFar 中发生的过度复制,但其中 none 解决了您如何调用此函数的毫无意义的问题:

std::vector<double> outcomes;
for (unsigned long j = 0; j < S_vect.size(); j++)
{
    outcomes.push_back(thesePathGatherers[j].GetResultsSoFar()[0][i]);
}

在这里,您要为每个 "path gatherer" 收集一个结果值,但为此您要在提取一个值之前多次复制每个结果列表。我认为改进这一点的第一步是避免 any 复制 ResultList 因为它不需要。

相反,如何向结果返回一个 const 引用。我还将重命名此函数以避免将其与您现有的定义混淆。但随便你怎么称呼它:

const std::vector<double>& StatisticAllPaths::GetResultList() const
{
    return ResultList;
}

当然,循环随后将访问 ith 值作为 thesePathGatherers[j].GetResultList()[i]。这里的关键区别是根本没有发生复制。

outcomes 还有一个小的优化要做。由于您确切知道要推送多少项目,因此您应该预先保留该内存。

std::vector<double> outcomes;
outcomes.reserve(S_vect.size());
for (unsigned long j = 0; j < S_vect.size(); j++)
{
    outcomes.push_back(thesePathGatherers[j].GetResultList()[i]);
}

如果你想让它更整洁,可以考虑定义 double GetResult(size_t) const 只有 returns 一个结果,然后调用 thesePathGatherers[j].GetResult(i).