23 Beginner The Hundred
The Sum That Rounds Every Step
four quarters that don't make a whole
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<double> v{0.25, 0.25, 0.25, 0.25};
std::cout << std::accumulate(v.begin(), v.end(), 0) << '\n';
std::cout << std::accumulate(v.begin(), v.end(), 0.0) << '\n';
}
Run it. Both lines sum the same four quarters — what do they print?
Answer
0, then 1. The first sum comes out to exactly nothing.
Why¶
The third argument of std::accumulate is not just a starting value — its type becomes
the type of the accumulator. The literal 0 is an int, so the running sum is an int,
no matter what the iterators point at. Each step computes acc = acc + 0.25: the addition
yields a double (0.25), but storing it back into the int accumulator truncates it to
0 — the sum rounds toward zero at every single step, and four quarters make nothing.
The same trap bites integers, too: summing a vector<long long> of large values with
init 0 does each addition in long long but stores the result back into the int
accumulator, silently narrowing out-of-range sums (implementation-defined until C++20,
wrap-around modulo 2^N since) — the total is quietly wrong either way. Worst of
all, the compiler is silent — not even -Wconversion flags it, because the narrowing
happens inside the <numeric> template, in a system header where GCC suppresses warnings.
The fix¶
Spell the initial value as the type you want the sum to have:
std::accumulate(v.begin(), v.end(), 0.0); // accumulates in double → prints 1
std::vector<long long> big{3'000'000'000, 3'000'000'000};
std::accumulate(big.begin(), big.end(), 0LL); // accumulates in long long → 6000000000
// (with 0, an int accumulator wraps it)
Takeaway: std::accumulate sums in the type of its initial value — write the init
literal as the type you want (0.0, 0LL), never a reflexive 0.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo