跟踪矢量元素的总和而不会丢失

时间:2017-07-08 14:38:36

标签: c++ precision

我有一段代码在一个程序中运行了数百万次,因此它对性能至关重要。在这个函数中发生的一件事是更新向量中的单个元素V,我需要跟踪它的元素之和S.通过在向量的创建中计算元素和,然后通过删除更新元素的当前值然后将新值相加来更新总和,我已经获得了很大的性能提升

S -= V[i];
S += newValue;
V[i] = newValue;

而不是用std::accumulate(V.begin(), V.end(),0.0)再次做全部总和。在程序的另一部分中,然后我使用和S作为可能结果的范围生成一个值,这个生成的值后来被发现超出范围。我的问题是:以这种方式存储元素总和是否有任何精度损失?设置它的另一种方法是:在充分实现此更新过程之后,S中的值是否会偏离'accumulate'返回的值?我现在正在测试这个假设,但是会对那些对机器操作有更好理解的人有所了解。如果确实存在精度损失并导致错误,是否存在快速但更精确的存储和S的方法?

编辑:存储在V中的数据类型是double:std::vector<double> V;,其元素之和也存储在双变量S中:double S;

Edit2:根据要求,这里有一个关于我正在进行总结的程序的更详细的视图:

    #include <random>
    #include <vector>
    #include <iostream>

    int chooseUpdateIndex(
    // here we choosen some element of V to be updated. The probability
    // of choosing index 'i' is just 'V[i]/S'
        std::uniform_real_distribution<double>& uniform,
        std::default_random_engine& rng,
        double S,
        std::vector<double>& V)
    {
        double randomLength = uniform(rng)*S;
        double partialSum = 0;
        for (int i = 0; i < V.size(); ++i) {
            partialSum += V[i];
            if (randomLength < partialSum) return i;
        }
        throw std::runtime_error("reached end of function without selecting an index");
    }

    int main()
    {
        std::default_random_engine rng;
        std::uniform_real_distribution<double> uniform(0.0, 1.0);
        std::vector<double> V(200);

        for (auto& v : V) v = 10*uniform(rng); // populate vector
        double S = std::accumulate(V.begin(), V.end(), 0.0); // make initial sum
        for (int i = 0; i < 1000000; ++i) {
            // sometimes, with enough iterations, this function call throws an error
            // because the randomLength is greater than the length of vector V
            int updateIndex = chooseUpdateIndex(uniform, rng, S, V);
            double newValue = uniform(rng)*10;
            S -= V[updateIndex];
            S += newValue;
            V[updateIndex] = newValue;
        }

        double recalculatedS = std::accumulate(V.begin(), V.end(), 0.0);

        if (S == recalculatedS) std::cout << "S == recalculatedS\n";
        else if (S < recalculatedS) std::cout << "S < recalculatedS\n";
        else std::cout << "S > recalculatedS\n";

        return 0;
    }

运行这个例子我通常会得到S&lt;重新计算的S,表示舍入错误使值变小。但是如果S> recalculatedS,那么chooseUpdateIndex函数可能会抛出错误。

0 个答案:

没有答案