Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有序数的有效稳定和_C++_Floating Point_Precision - Fatal编程技术网

C++ 有序数的有效稳定和

C++ 有序数的有效稳定和,c++,floating-point,precision,C++,Floating Point,Precision,我有一个相当长的浮点正数列表(std::vector,大小~1000)。数字按降序排序。如果我按照以下顺序求和: for (auto v : vec) { sum += v; } 我想我可能会遇到一些数值稳定性问题,因为接近向量末尾的sum将比v大得多。最简单的解决方案是以相反的顺序遍历向量。我的问题是:这和远期交易一样有效吗?我会有更多的缓存丢失 是否有其他智能解决方案?为此,您可以使用反向迭代器,而不必在std::vector-vec中进行任何换位: float sum{0.f}; for

我有一个相当长的浮点正数列表(
std::vector
,大小~1000)。数字按降序排序。如果我按照以下顺序求和:

for (auto v : vec) { sum += v; }
我想我可能会遇到一些数值稳定性问题,因为接近向量末尾的
sum
将比
v
大得多。最简单的解决方案是以相反的顺序遍历向量。我的问题是:这和远期交易一样有效吗?我会有更多的缓存丢失


是否有其他智能解决方案?

为此,您可以使用反向迭代器,而不必在
std::vector-vec中进行任何换位:

float sum{0.f};
for (auto rIt = vec.rbegin(); rIt!= vec.rend(); ++rIt)
{
    sum += *rit;
}
或者使用标准算法执行相同的工作:

float sum = std::accumulate(vec.crbegin(), vec.crend(), 0.f);
性能必须相同,只需绕过向量的方向即可更改

最简单的解决方案是以相反的顺序遍历向量。我的问题是:这和远期交易一样有效吗?我会有更多的缓存丢失

是的,它很有效。您的硬件的分支预测和智能缓存策略针对顺序访问进行了优化。您可以安全地累积向量:

#include <numeric>

auto const sum = std::accumulate(crbegin(v), crend(v), 0.f);
#包括
自动常数和=标准::累加(crbegin(v),crend(v),0.f);
我想我会有一些数值稳定性问题

所以测试一下。现在你有一个假设的问题,也就是说,没有问题

如果您进行了测试,并且假设变成了实际问题,那么您应该担心实际修复它

也就是说,浮点精度可能会引起问题,但您可以先确认它是否真的对您的数据有影响,然后再将其优先考虑

。。。我会有更多的缓存丢失

1000个浮点数是4Kb——它将适合现代大众市场系统中的缓存(如果您想使用另一个平台,请告诉我们它是什么)

唯一的风险是,当向后迭代时,预取程序不会帮助您,但当然,您的向量可能已经在缓存中。只有在完整程序的上下文中进行概要分析后,才能真正确定这一点,因此,在拥有完整程序之前,担心这一点是没有用的

还有其他智能解决方案吗

不要担心可能成为问题的事情,直到它们真正成为问题。最多值得注意的是可能出现的问题,并对代码进行结构化,以便您可以在以后用经过仔细优化的解决方案替换最简单的解决方案,而无需重新编写其他所有内容。

I您的用例和结果(请参见附图)指向向前或向后循环不会产生任何性能差异的方向

您可能还需要在硬件+编译器上进行测量


使用STL执行求和,速度与手动循环数据一样快,但更具表现力

使用以下方法进行反向累积:

std::accumulate(rbegin(data), rend(data), 0.0f);
std::accumulate(begin(data), end(data), 0.0f);
而对于远期积累:

std::accumulate(rbegin(data), rend(data), 0.0f);
std::accumulate(begin(data), end(data), 0.0f);

如果您所说的数值稳定性是指精度,那么是的,您可能最终会遇到精度问题。根据最大值与最小值的比率,以及您对结果准确性的要求,这可能是问题,也可能不是问题

如果你确实想要高精度,那么考虑一下,这是用额外的浮点来进行误差补偿。还有

有关精度和时间之间权衡的详细分析,请参阅

C++17的更新:

其他一些答案提到了
std::acculate
。从C++17开始,就有一些算法可以并行化

比如说

#include <vector>
#include <execution>
#include <iostream>
#include <numeric>

int main()
{  
   std::vector<double> input{0.1, 0.9, 0.2, 0.8, 0.3, 0.7, 0.4, 0.6, 0.5};

   double reduceResult = std::reduce(std::execution::par, std::begin(input), std::end(input));

   std:: cout << "reduceResult " << reduceResult << '\n';
}
#包括
#包括
#包括
#包括
int main()
{  
向量输入{0.1,0.9,0.2,0.8,0.3,0.7,0.4,0.6,0.5};
双reduceResult=std::reduce(std::execution::par,std::begin(输入),std::end(输入));

标准:cout Speed这个问题很容易回答。对它进行基准测试。速度比准确度更重要吗?这不是一个完全重复的问题,但非常类似的问题:你可能必须注意负数。如果你真的非常在意准确度,请检查。如果我错了,请纠正我,但我认为这比foreach statem更有效ent OP正在使用,因为它引入了开销。YSC在数值稳定性方面是正确的,tho。@sephiroth不,任何半体面的编译器都不会真正关心您是为编写范围还是为编写迭代器。由于缓存/预取,真实世界的性能肯定不能保证相同。OP对此保持警惕是合理的。Can您澄清:在此上下文中,“顺序访问”是指向前、向后还是两者兼而有之?@RuggeroTurra我不能,除非我能找到一个源,而且我现在没有心情阅读CPU数据表。@RuggeroTurra通常顺序访问意味着向前。所有半正常的内存预取器都会捕获向前顺序访问。@Tootbrush,谢谢。因此,如果我原则上向后循环,这可能是一种性能nce问题原则上,至少在某些硬件上,如果整个向量不在一级缓存中。该网站非常酷。只是为了确保:您没有对随机生成进行计时,对吗?不,只有
状态
循环中的部分进行计时。