此示例代码取自 对于那些不熟悉的人, 范围的元素可以被任意分组和重新排列
为了 在同一个线程中执行的任何此类调用都是不确定的
相对于彼此排序。 如果binary_op不是关联的,则行为是不确定的
不可交换。 给出的示例输出是: AFAIK,Clang或GCC都没有实现图书馆TS,所以样本可能已经组成,但这不是问题的关键。 鉴于浮点的属性,这段代码是“安全的”吗? 这里的假设是操作纯粹是加法,而不是乘法。 std::reduce
的#include <iostream>
#include <chrono>
#include <vector>
#include <numeric>
#include <execution_policy>
int main()
{
std::vector<double> v(10'000'007, 0.5);
{
auto t1 = std::chrono::high_resolution_clock::now();
double result = std::accumulate(v.begin(), v.end(), 0.0);
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ms = t2 - t1;
std::cout << std::fixed << "std::accumulate result " << result
<< " took " << ms.count() << " ms\n";
}
{
auto t1 = std::chrono::high_resolution_clock::now();
double result = std::reduce(std::par, v.begin(), v.end());
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ms = t2 - t1;
std::cout << "std::reduce result "
<< result << " took " << ms.count() << " ms\n";
}
}
std::reduce
与std::accumulate
相似,除了:
std::par
表示:
std::reduce
的页面进一步说:
std::accumulate result 5000003.50000 took 12.7365 ms
std::reduce result 5000003.50000 took 5.06423 ms
std::reduce
实际上会产生与std::accumulate
完全相同的结果,甚至是多次测试吗?
答案 0 :(得分:4)
应用于浮点类型时,std::plus
不是关联的。 (a + b) + c
可能与a + (b + c)
鉴于此,我会说出你的问题的答案
std::reduce
实际上会产生与std::accumulate
完全相同的结果,甚至是多次测试吗?
是:
结果可能不同。它们可能相同,但不能保证。
答案 1 :(得分:2)
IEEE double
有53个有效位,约为1E16左右。
10'000'007
有10位数字。
这意味着IEEE double
可以 完全表示步长为10'000'007/2
的0到0.5
的每个值。
double
添加是确定性的,除非经常你最终会得到&#34;逻辑&#34;不能表示为double
的值,此时会发生舍入。由于没有添加10'000'007
元素的子序列可能会导致double
无法完美表示的数字,因此结果具有确定性且已知。
对double
的通用向量执行此操作不会成立。一个简单的例子是向示例向量添加大约1E20的值和-1E20左右的另一个值。添加0.5
中的任何一个都不会做任何事情;当他们相互加入时,他们会取消。因此结果将是0
和5000003.50000