Can we use std::reduce to subtract?

214 Views Asked by At

I discovered the std::reduce algorithm recently and wanted to compare it with std::accumulate. I found this blog post explaining how std::reduce can be parallelised using std::execution::par. However, the blog post notes that parallelisation only works with operations that are "both associative and commutative."

I wanted to test this out. While I originally thought that subtraction failed due to the algorithm being parallelised, I discovered that it seems std::reduce doesn't give the correct answer for subtraction even when used with std::execution::seq or just run without an execution policy (which should run the algorithm sequentially).

Running this:

std::vector<int> vec = {5, 4, 3, 2, 1};
auto diff = std::reduce(begin(vec), end(vec), 0, std::minus<>{});
std::cout << diff << "\n";

Gives this output:

-1

Am I doing something wrong? Or does std::reduce just never work with subtraction?

2

There are 2 best solutions below

2
Pepijn Kramer On BEST ANSWER

Yes you can, with a very slight modification to the calculation. You need to leave the first value out of reduce, and subtract the sum of the other elements.

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

int main()
{
    std::vector<int> vec = { 5, 4, 3, 2, 1 };
    auto sum_of_rest = std::reduce(std::execution::par, vec.begin() + 1, vec.end());
    auto diff = vec.front() - sum_of_rest;
    std::cout << diff << "\n";
    return 0;
}
1
Toby Speight On

It's not clear what a "correct" result should be when using a non-commutative or non-associative operation. Given that the operations may be performed in any order, there are many possible results for the operation of "subtracting all elements", and the standard specifically states:

The difference between reduce and accumulate is that reduce applies binary_op in an unspecified order, which yields a nondeterministic result for non-associative or non-commutative binary_op such as floating-point addition.

- [numeric.ops]/[reduce] p9