我有一段代码在一个程序中运行了数百万次,因此它对性能至关重要。在这个函数中发生的一件事是更新向量中的单个元素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函数可能会抛出错误。