在阅读关于std::inclusive_scan的文章时,似乎没有任何例子。
它与std::partial_sum非常相似。
partial_sum:
template< class InputIt, class OutputIt >
OutputIt partial_sum( InputIt first,
InputIt last, OutputIt d_first );
字符串
inclusive_scan:
template< class InputIt, class OutputIt >
OutputIt inclusive_scan( InputIt first,
InputIt last, OutputIt d_first );
型
有人能详细说明他们的区别吗?我什么时候会选择其中一个?
3条答案
按热度按时间yduiuuwa1#
std::inclusive_scan
的文档说明:换句话说,求和运算可以以任意顺序执行,如果
binary_op
不是关联的,则行为是不确定的。std::partial_sum
的文档毫无保留地指出:字符串
因此,
std::inclusive_scan
仅在binary_op
是关联的时才等价于std::partial_sum
,即当(a
opb)
opc = a
op(b
opc)
时。在非关联
binary_op
的情况下,std::partial_sum
将产生确定性结果,而您不知道std::inclusive_scan
会产生什么结果。f4t66c6m2#
std::inclusive_scan是在C++17中作为并行STD的一部分添加的,而std::partial_sum以前就存在。这两个函数都是重载的。如果不指定运算符,运算符默认为
std::plus
:字符串
对于许多类型,如整数,其中
std::plus
是关联的,partial_sum
和inclusive_scan
将是相同的。背后的算法是相同的,实际上,“包含扫描”,“部分和”等都是同一类型计算的同义词(维基百科称之为prefix sum))。但是在其他采用用户指定的运算符的重载中有一个区别:
型
partial_sum
的约束比inclusive_scan
弱。它只要求op
不能使任何迭代器无效,或者修改所涉及的范围的任何元素。并行化的问题是它不要求
op
是关联的。由于partial_sum
要求按指定的方式顺序执行,因此目前还不需要。缺点是它阻止了并行执行,因为您无法重新排序计算。在
inclusive_scan
中,op
被明确要求是一个关联操作。否则,你会得到未定义的行为。然而,优点是现在可以通过指定执行策略来更改代码以支持并行执行:型
我什么时候会选择其中一个?
inclusive_scan
。即使你总是使用顺序执行,它也可以作为某种形式的文档。partial_sum
,否则,它将是未定义的行为。如果没有用户指定的操作符,我可以总是用
inclusive_scan
替换partial_sum
吗?换句话说,将partial_sum(first, last, out)
更改为inclusive_scan(first, last, out)
安全吗?通常,
std::plus
是关联的(即,x + (y + z) == (x + y) + z
将保持)。在这种情况下,更改它是安全的。但也有例外。一些奇怪的用户定义类可能会以意想不到的方式重载
std::plus
。但更有趣的情况是浮点运算,即not associative in a strict sense:型
如果您的计算需要完全可重现,则在将
partial_sum
更改为inclusive_scan
(与非顺序执行策略组合)时必须记住这一点。尽管如此,在实践中,浮点运算足够接近被认为是关联的。如果运算的顺序不固定,精度甚至可以提高。这意味着,直接的顺序算法无论如何都不是完美的。
ecbunoof3#
这几乎是相同的,但包容性扫描可以并行运行。相同的界面。