Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::accumulate

Tags:

c++

c++11

stl

I always try to incorporate STL algorithms wherever I can, rather than writing manual loops. However, I'm having difficulty understanding how std::accumulate is generally useful. Whenever I need to calculate sums or averages, I almost always end up resorting to manual loops, because I have difficulty getting std::accumulate to do what I need.

The problem is that I rarely ever have a simple vector of integers that need to be summed. Usually, I want to sum an array of objects using a particular member variable. Yes, I know there is a version of std::accumulate that takes a BinaryFunction, but the problem I see is that this function needs to take two values of type T, where T is the type of the sum, rather than the type of the operands. I'm having trouble understanding how this is useful.

Consider a case which I assume is pretty common. I have the following class:

struct Foo
{
    Foo(int cost_, int id_) : cost(cost_), id(id_)
    { }

    int cost;
    int id;
};

Now, say I want to calculate the sum of an array of Foo objects, using Foo::cost.

I want to say:

std::vector<Foo> vec;
// fill vector with values
int total_cost = std::accumulate(vec.begin(), vec.end(), 0, sum_cost);

And sum_cost is defined as:

int sum_cost(const Foo& f1, const Foo& f2)
{
    return f1.cost + f2.cost;
}

The problem is, this doesn't work because std::accumulate expects a BinaryFunction which takes in two instances of the resulting sum type - which in this case is just int. But how is that useful to me? If my BinaryFunction takes in two ints, I can't specify that I want to sum the cost field.

So, why is std::accumulate designed this way? Am I just not seeing something obvious here?

like image 717
Channel72 Avatar asked Mar 01 '11 18:03

Channel72


People also ask

What does std :: accumulate do?

std::accumulate() is a built-in function in C++'s Standard Template Library. The function takes in a beginning iterator, an ending iterator, initial value, and (by default) computes the sum of the given initial value and the elements in the given range. The function can also​ be used for left folding.

How do you use accumulate?

Accumulate sentence example. They were unable to accumulate enough evidence to make a well-written claim. The couple hoped to accumulate enough money to make the down payment on a house. He was the first man to collect libraries, to accumulate coins.

Is std :: accumulate fast?

As I expect, the manually unrolled loop is the fastest one, but more interesting is that std::accumulate is much slower than simple loop. This is my code, I compiled it with gcc 4.7 with -O3 flag. Visual Studio will need different rdtsc function implementation.

What is the time complexity of accumulate?

Complexity: O(n×k), where n is the distance from first to last , O(k) is complexity of f function.


2 Answers

You're wrong about accumulate operator taking two of the same type. It does that only if you want to. The use the operator is specifically sum = op(sum, *iter). Thus your code:

int count = std::accumulate(stuff.begin(), stuff.end(), 0, [](int current_sum, stuff_value_t const& value) { return current_sum + value.member; });

If you can't use lambda then of course you use the standard binders or boost::bind.

like image 183
Edward Strange Avatar answered Oct 12 '22 15:10

Edward Strange


use functor:

class F { // sum Foos
    F(int init = 0);
    template<class T>
    Foo operator()(const Foo &a, const T &b) const;
    operator int() const;
};

int total_cost = std::accumulate(vec.begin(), vec.end(), F(0), F());

notice you can do other things as well:

class F { // sum foo values members
    template<class T>
    T operator()(const T &a, const Foo &b) const;
};
int total_cost = std::accumulate(vec.begin(), vec.end(), int(0), F());
like image 25
Anycorn Avatar answered Oct 12 '22 16:10

Anycorn