Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C++  Module 11 – Iterators, algorithms and ranges

C++ <numeric>: accumulate, reduce, prefix sums

How std::accumulate, std::reduce and prefix sums with std::partial_sum work, the type traps in each, and std::gcd, std::lcm, std::midpoint and std::iota.

  • Intermediate
  • 20 minutes
  • Examples run with Clang 21.0.0, GCC 16.2.0 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 8 of 20 minutes free
Free: accumulate adds in the type of its initial value · reduce may regroup the additions, so the operation must allow it · Prefix sums answer range totals with one subtraction · 2 more sections. With a pass: 2 in-depth parts and 3 interview answers, about 12 minutes.

What you will learn

  • Combine values with std::accumulate and std::reduce, and choose the type of the total
  • Build prefix sums with partial_sum or inclusive_scan to answer range-sum queries
  • Explain why std::reduce can give a different floating-point total from std::accumulate
  • Use std::gcd, std::lcm, std::midpoint and std::iota without overflow

Before you start

Four deposits of 1,000,000,000 paise add up to 4,000,000,000, yet std::accumulate(deposits.begin(), deposits.end(), 0) returns -294,967,296 with both compilers, and nothing warns: the initial 0 made the running total an int. Traps like this are why <numeric> is worth knowing.

std::accumulate fold: Combining the elements of a range into one value with an operation, starting from an initial value: a left fold of 1, 2 and 3 with + computes ((0 + 1) + 2) + 3. std::accumulate and C++23's std::ranges::fold_left fold from the left. a range from left to right, starting from an initial value. std::reduce (C++17) computes the same kind of total but may group and reorder the additions, so it can run in parallel, and std::transform_reduce first applies a function to each element, or to each pair of two ranges. std::partial_sum and std::inclusive_scan write running totals, the prefix sums: An array whose position i holds the total of the first i values, with 0 at position 0, so the total of the half-open range [l, r) is prefix[r] - prefix[l], one subtraction whatever its length. std::partial_sum and std::inclusive_scan write the running totals. that answer any “total from position l to r” question with one subtraction, and std::adjacent_difference turns running totals back into values. std::iota fills a range with increasing values, and std::gcd, std::lcm and std::midpoint do integer arithmetic that is easy to get wrong by hand.

accumulate adds in the type of its initial value

Four deposits and three hours, added from different starting values:

accumulate_type.cpp C++ · accumulate_type.cpp
// std::accumulate adds in the type of its initial value: 0 means int, whatever the elements are.
#include <algorithm>
#include <functional>
#include <numeric>
#include <print>
#include <vector>

int main() {
    std::vector<long long> deposits(4, 1'000'000'000);  // four deposits of 1,000,000,000 paise each
    std::println("accumulate with 0:   {}", std::accumulate(deposits.begin(), deposits.end(), 0));
    std::println("accumulate with 0LL: {}", std::accumulate(deposits.begin(), deposits.end(), 0LL));

    std::vector<double> hours{0.5, 0.75, 1.25};
    std::println("accumulate with 0:   {}", std::accumulate(hours.begin(), hours.end(), 0));
    std::println("accumulate with 0.0: {}", std::accumulate(hours.begin(), hours.end(), 0.0));

    // C++23's fold_left keeps the total in the type that the operation returns: int + long long is long long.
    std::println("fold_left with 0:    {} and {}", std::ranges::fold_left(deposits, 0, std::plus<>{}),
                 std::ranges::fold_left(hours, 0, std::plus<>{}));
}
The same sums with 0, 0LL, 0.0 and fold_left Python · accumulate_type_session.py
from session import run

run("""
clang++ -std=c++23 -Wall -Wextra accumulate_type.cpp -o accumulate_type && ./accumulate_type
g++-16 -std=c++23 -Wall -Wextra accumulate_type.cpp -o accumulate_type-gcc && ./accumulate_type-gcc
""")

Output

$ clang++ -std=c++23 -Wall -Wextra accumulate_type.cpp -o accumulate_type && ./accumulate_type
accumulate with 0:   -294967296
accumulate with 0LL: 4000000000
accumulate with 0:   1
accumulate with 0.0: 2.5
fold_left with 0:    4000000000 and 2.5
$ g++-16 -std=c++23 -Wall -Wextra accumulate_type.cpp -o accumulate_type-gcc && ./accumulate_type-gcc
accumulate with 0:   -294967296
accumulate with 0LL: 4000000000
accumulate with 0:   1
accumulate with 0.0: 2.5
fold_left with 0:    4000000000 and 2.5

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 accumulate_type_session.py

With 0, the running total is an int. For the deposits, each addition happens in long long and the result is stored back into the int. Since C++20 that conversion is defined as wrapping round modulo 2³², so both compilers print -294,967,296 every time: a wrong answer that looks plausible at a glance. For the hours, every step cuts the double back to a whole number, so 0.5 and 0.75 vanish and only the 1 of 1.25 survives. Step through the hours, added once from 0 and once from 0.0:

Interactive · step by step Three hours added from 0 and from 0.0 Step through std::accumulate over the hours 0.5, 0.75 and 1.25. On the left the total starts as the int 0, on the right as the double 0.0.
Three hours added from 0 and from 0.0, step 5 of 5. Showing from 0: an int, from 0.0: a double, 0 + 0.5, 0.0 + 0.5, 0 + 0.75, 0.5 + 0.75, 0 + 1.25, 1.25 + 1.25, returns 1, returns 2.5. In focus: returns 1, returns 2.5.from 0: an inttotal = 0from 0.0: a doubletotal = 0.00 + 0.5is 0.5, stored as 00.0 + 0.5is 0.5, stored as 0.50 + 0.75is 0.75, stored as 00.5 + 0.75is 1.25, stored as 1.250 + 1.25is 1.25, stored as 11.25 + 1.25is 2.5, stored as 2.5returns 1an intreturns 2.5a double

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. Two starting values. std::accumulate keeps its running total in the type of the initial value. Pass 0 and the total is an int; pass 0.0 and it is a double. The hours themselves are doubles either way.
  2. The first hour. Each step computes total + element in double, because one operand is a double, and stores the result back into the total. 0.5 fits a double, but stored in an int it becomes 0.
  3. The second hour. On the left the total is still 0, so 0 + 0.75 is 0.75 and is cut back to 0 again. On the right 0.5 + 0.75 is 1.25 and is kept.
  4. The third hour. 0 + 1.25 is 1.25, and the int keeps only the 1. On the right 1.25 + 1.25 is 2.5.
  5. Two different answers. Both calls return their total in the initial value's type: 1 from 0, and 2.5 from 0.0, exactly what both compilers printed. Nothing warned, because every conversion happened inside the library.

Passing 0LL or 0.0 fixes both. C++23’s std::ranges::fold_left avoids the trap by design: its total takes the type that the operation returns, and adding a long long to an int returns a long long. When the elements and the initial value are both int, an overflowing sum is not even wrapped: it is undefined behaviour.

The same rule explains a common compile error: std::accumulate(words.begin(), words.end(), "") on a vector of strings does not compile, because the initial value makes the total a const char*, and a joined std::string cannot be stored in one. With std::string{} as the initial value it compiles and joins the words. Write the initial value in the type you want the total to have.

Checkpoint

Check: The type of an accumulate total

  1. Question 1 of 2 What does std::accumulate(hours.begin(), hours.end(), 0) return for the hours 0.5, 0.75 and 1.25?

    Type a number.

    A hint

    The total is an int, and every step stores the sum back into it.

    Show the answer: Question 1 of 2

    Answer: 1

    0 + 0.5 is stored as 0, 0 + 0.75 as 0, and 0 + 1.25 as 1, so the call returns the int 1, as both compilers printed. With 0.0 it returns 2.5.

  2. Question 2 of 2 std::accumulate(words.begin(), words.end(), "") does not compile for a std::vector<std::string>. Which initial value makes it join the words?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: std::string{}

    The initial value sets the type of the total. "" is a const char*, so every step would have to store a std::string in a pointer; std::string{} makes the total a string.

reduce may regroup the additions, so the operation must allow it

std::reduce returns what accumulate would, as long as the operation does not care how the values are grouped or ordered. The standard lets it apply the operation in an unspecified order, so that it can split the range across threads when given an An argument such as std::execution::par (C++17, header <execution>) that permits a standard algorithm to spread its work over several threads, or to use vector instructions., and it notes that the result is then nondeterministic for operations such as floating-point addition. For integers that changes nothing; for float and double the last digits can change, and with large and small values mixed, much more than the last digits. Step through eight whole numbers added in two orders:

Interactive · step by step Eight values added left to right, and in pairs Step through two ways of adding the eight days of rain. On the left the order std::accumulate must follow, on the right one of the orders std::reduce may choose.
Eight values added left to right, and in pairs, step 5 of 5. Showing accumulate, after 3, 1, 4 and 1, then 5, 9, 2 and 6, accumulate returns, reduce, one grouping, the four pair sums, pairs of pairs, reduce may return. In focus: accumulate returns, reduce may return.accumulatestrictly left to rightafter 3, 1, 4 and 1totals 3, 4, 8, 9then 5, 9, 2 and 6totals 14, 23, 25, 31accumulate returns31reduce, one grouping3+1, 4+1, 5+9, 2+6the four pair sums4, 5, 14 and 8pairs of pairs4+5 = 9 and 14+8 = 22reduce may return0 + 9 + 22 = 31

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. One total, two orders. The rain of eight days, 3, 1, 4, 1, 5, 9, 2 and 6, is to be totalled from 0. accumulate must add them one at a time from the left; reduce may group and reorder them, so that parts can be added at the same time.
  2. Left to right. accumulate computes ((((0 + 3) + 1) + 4) + 1): every addition needs the result of the one before, so no two of them can run at the same time. After four values its total is 9.
  3. Pairs first. One grouping reduce may use adds neighbours in pairs: 3 + 1, 4 + 1, 5 + 9 and 2 + 6. The four additions do not depend on each other, so four threads could do one each.
  4. Then pairs of pairs. The pair sums 4, 5, 14 and 8 are added in pairs again, 9 and 22, while accumulate is still working through 5, 9, 2 and 6 one at a time.
  5. The same 31. Both reach 31, the total range_queries.cpp printed for all 8 days. Integer addition gives the same answer in any grouping, so reduce is safe here; floating-point addition rounds at every step, so a different grouping can change the result.

Use reduce when the operation is associative and commutative, such as integer addition, a maximum or a bitwise or, and keep accumulate when the order is part of the result: subtraction, joining strings, or floating-point totals that must come out the same everywhere. Three questions decide between the three folds:

Interactive · answer and compare Which fold fits your total? Answer three questions about the total you need. A row that cannot give it is ruled out with the reason; a row that needs care gets a caveat.
Does the order of the operations matter, as for subtraction, joined strings or a float total that must match everywhere?
Will the total be computed on several threads, with an execution policy?
Could the total outgrow the initial value's type, as an int 0 does with long long values?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

std::accumulate, std::reduce and std::ranges::fold_left against five things that decide between them
Algorithm Order of the operations Type of the total Same total every time Execution policies Standard
std::accumulate Good left to right, one element at a time Mixed the initial value's type: 0 makes it an int Good yes Poor none Good C++98
std::reduce Mixed any grouping and any order Mixed the initial value's type, as for accumulate Mixed only for associative, commutative operations Good yes, such as std::execution::par Good C++17
std::ranges::fold_left Good left to right, one element at a time Good what the operation returns Good yes Poor none Mixed C++23, in recent compilers
How the answers decide
  • “Does the order of the operations matter, as for subtraction, joined strings or a float total that must match everywhere?” Yes, the order is part of the result: rules out std::reduce. reduce may regroup and reorder the operations, so subtraction, joined strings and float totals can come out differently.
  • “Will the total be computed on several threads, with an execution policy?” Yes, in parallel: rules out std::accumulate and std::ranges::fold_left. Only reduce takes an execution policy; accumulate and fold_left always apply the operation one step after another.
  • “Could the total outgrow the initial value's type, as an int 0 does with long long values?” Yes, it could: adds a caveat to std::accumulate and std::reduce. Write the initial value in the type the total needs, such as 0LL or 0.0; fold_left takes the type that the operation returns.

Checkpoint

Check: Why reduce may give another total

  1. Question 1 of 2 Called on the same vector of float values with the same initial value, which of these may return a different total from std::accumulate?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: std::reduce

    std::reduce may group and reorder the additions, and floating-point addition gives different results in a different grouping. accumulate, partial_sum and fold_left all add from left to right, one element at a time.

  2. Question 2 of 2 You join the names of a list of students into one std::string, in the list's order. Which fold must you not use?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: std::reduce

    reduce is for operations that do not care about grouping or order. Joining is associative but not commutative, so "Asha" + "Bilal" and "Bilal" + "Asha" differ, and reduce is allowed to swap them.

Prefix sums answer range totals with one subtraction

Eight days of rain and their prefix sums; the program builds them and answers two questions:

Eight daily rain values, their nine prefix sums starting at 0, and a range total computed as 23 minus 4.rain, days 0 to 7prefix, positions 0 to 8days 2 to 5:prefix[6] − prefix[2]= 23 − 4 = 19314159260348914232531partial_sum,from position 1one subtraction

Prefix sums turn any range total into one subtraction

Text description of the diagram

The diagram has three parts, one below the other.

  1. The rain on days 0 to 7: 3, 1, 4, 1, 5, 9, 2 and 6 millimetres.
  2. The prefix sums, one more value than there are days: 0, 3, 4, 8, 9, 14, 23, 25 and 31. Position i holds the total of the first i days, so position 0 is 0 and position 8 is the total of all eight days. std::partial_sum writes them from position 1.
  3. A question answered with one subtraction: the rain on days 2 to 5 is the prefix at position 6 minus the prefix at position 2, 23 minus 4, which is 19.
range_queries.cpp C++ · range_queries.cpp
// Prefix sums answer "what is the total from day l to day r?" with one subtraction.
#include <numeric>
#include <print>
#include <vector>

int main() {
    std::vector<long long> rain{3, 1, 4, 1, 5, 9, 2, 6};  // millimetres of rain on days 0 to 7

    // prefix[i] is the total of the first i days, so prefix[0] = 0 and prefix has one element more than rain.
    std::vector<long long> prefix(rain.size() + 1, 0);
    std::partial_sum(rain.begin(), rain.end(), prefix.begin() + 1);
    std::println("prefix: {}", prefix);

    // The total of days [l, r) is prefix[r] - prefix[l]: no loop, whatever the length.
    auto total = [&](std::size_t l, std::size_t r) { return prefix[r] - prefix[l]; };
    std::println("days 2 to 5: {}", total(2, 6));
    std::println("all 8 days: {}", total(0, 8));

    // adjacent_difference undoes partial_sum: it gives back the daily values.
    std::vector<long long> back(prefix.size());
    std::adjacent_difference(prefix.begin(), prefix.end(), back.begin());
    std::println("adjacent_difference of prefix: {}", back);

    // C++17's scans: inclusive_scan matches partial_sum; exclusive_scan starts from an initial value instead.
    std::vector<long long> inc(rain.size()), exc(rain.size());
    std::inclusive_scan(rain.begin(), rain.end(), inc.begin());
    std::exclusive_scan(rain.begin(), rain.end(), exc.begin(), 0LL);
    std::println("inclusive_scan: {}", inc);
    std::println("exclusive_scan: {}", exc);
}
Prefix sums of eight days of rain Python · range_queries_session.py
from session import run

run("""
clang++ -std=c++23 -Wall -Wextra range_queries.cpp -o range_queries && ./range_queries
g++-16 -std=c++23 -Wall -Wextra range_queries.cpp -o range_queries-gcc && ./range_queries-gcc
""")

Output

$ clang++ -std=c++23 -Wall -Wextra range_queries.cpp -o range_queries && ./range_queries
prefix: [0, 3, 4, 8, 9, 14, 23, 25, 31]
days 2 to 5: 19
all 8 days: 31
adjacent_difference of prefix: [0, 3, 1, 4, 1, 5, 9, 2, 6]
inclusive_scan: [3, 4, 8, 9, 14, 23, 25, 31]
exclusive_scan: [0, 3, 4, 8, 9, 14, 23, 25]
$ g++-16 -std=c++23 -Wall -Wextra range_queries.cpp -o range_queries-gcc && ./range_queries-gcc
prefix: [0, 3, 4, 8, 9, 14, 23, 25, 31]
days 2 to 5: 19
all 8 days: 31
adjacent_difference of prefix: [0, 3, 1, 4, 1, 5, 9, 2, 6]
inclusive_scan: [3, 4, 8, 9, 14, 23, 25, 31]
exclusive_scan: [0, 3, 4, 8, 9, 14, 23, 25]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 range_queries_session.py

prefix[i] holds the total of the first i values and prefix[0] is 0, so the total of the half-open range [l, r) is prefix[r] - prefix[l]: one subtraction, however long the range. Building the array takes one pass with std::partial_sum, written from position 1. std::adjacent_difference reverses it, which is why the round trip prints the daily values again, behind the 0. C++17’s std::inclusive_scan writes the same running totals as partial_sum, and std::exclusive_scan writes the total before each position, starting from an initial value. Step through the build and two questions:

Interactive · step by step Building prefix sums of eight days of rain, then asking them Step through std::partial_sum writing the prefix array one running total at a time, then two range totals answered by subtraction, then the way back.
Building prefix sums of eight days of rain, then asking them, step 7 of 7. Showing rain, prefix (0 3 4 8 9 14 23 25 31), partial_sum reads (days 3 to 7), and writes (9 14 23 25 31), a range [l, r) (all 8 days: [0, 8)), one subtraction (31 - 0 = 31), adjacent_difference (0 3 1 4 1 5 9 2 6). In focus: adjacent_difference, prefix.adds to the totalundoes itrain3 1 4 1 5 9 2 6prefix0 3 4 8 9 14 23 25 31partial_sum readsdays 3 to 7and writes9 14 23 25 31a range [l, r)all 8 days: [0, 8)one subtraction31 - 0 = 31adjacent_difference0 3 1 4 1 5 9 2 6

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. One slot more than days. prefix has 9 elements for 8 days, all 0 to start with. prefix[i] will hold the total of the first i days, so prefix[0] stays 0, and partial_sum writes from position 1.
  2. The first day. partial_sum reads day 0, 3 millimetres. The running total is 3, and it writes 3 into prefix[1].
  3. A running total. Each later day is added to the total so far: 3 + 1 = 4 goes to prefix[2] and 4 + 4 = 8 to prefix[3].
  4. To the last day. Five more additions finish the array: 9, 14, 23, 25 and 31. One pass over the data, eight additions, and the program printed prefix: [0, 3, 4, 8, 9, 14, 23, 25, 31].
  5. Days 2 to 5. Days 2 to 5 are the half-open range [2, 6). Their total is prefix[6] - prefix[2], the first six days minus the first two: 23 - 4 = 19, as the program printed.
  6. Any length, the same cost. All 8 days are [0, 8): prefix[8] - prefix[0] = 31 - 0 = 31. A range of eight days costs one subtraction, the same as a range of one day.
  7. And back again. adjacent_difference subtracts each element from the one after it, so it turns the running totals back into 0 followed by the daily values: [0, 3, 1, 4, 1, 5, 9, 2, 6].

The cost is one pass to build the array and one subtraction per question, against a walk over the whole range for every question when you add it up again. That trade is why prefix sums are the standard tool for many questions about data that does not change. When values change between questions, the array would have to be rebuilt; a Fenwick tree handles both an update and a range total in O(log n) steps.

Checkpoint

Check: Range totals from prefix sums

  1. Question 1 of 2 The prefix sums of eight values are [0, 3, 4, 8, 9, 14, 23, 25, 31]. What is the total of the values at positions 3, 4, 5 and 6, the range [3, 7)?

    Type a number.

    A hint

    The total of [l, r) is prefix[r] - prefix[l].

    Show the answer: Question 1 of 2

    Answer: 17

    The total of [l, r) is prefix[r] - prefix[l], here prefix[7] - prefix[3] = 25 - 8 = 17. Check it against the values themselves: 1 + 5 + 9 + 2 = 17.

  2. Question 2 of 2 How many elements does the prefix array of 200 daily values have?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 201 elements

    One more than the data: prefix[0] is 0 and prefix[i] is the total of the first i values, up to prefix[200], the total of all of them. The rain example has 8 days and a prefix array of 9.

gcd, lcm, midpoint and iota do small integer jobs

Four more functions of <numeric> handle integer arithmetic that hand-written code often gets wrong:

  • std::gcd(m, n) (C++17) returns the greatest common divisor of the absolute values, and 0 when both are 0.
  • std::lcm(m, n) (C++17) returns the least common multiple, which must fit in the result type.
  • std::midpoint(a, b) (C++20) returns half the sum without overflowing, rounded towards a for integers.
  • std::iota(first, last, value) fills a range with value, value + 1 and so on; C++23 adds std::ranges::iota.
Seats, tiles, lights and a middle C++ · helpers.cpp
// std::iota fills a range with increasing values; std::gcd, std::lcm and std::midpoint do small integer jobs.
#include <numeric>
#include <print>
#include <vector>

int main() {
    std::vector<int> seats(6);
    std::iota(seats.begin(), seats.end(), 101);  // 101, 102, ..., 106
    std::println("seats: {}", seats);

    // The largest square tile that covers a 48 x 18 floor exactly, with no tile cut.
    std::println("gcd(48, 18) = {}", std::gcd(48, 18));
    // Two lights that blink every 4 and every 6 seconds blink together every lcm seconds.
    std::println("lcm(4, 6) = {}", std::lcm(4, 6));
    // Half the sum, computed in a way that cannot overflow.
    std::println("midpoint(10, 20) = {}", std::midpoint(10, 20));
}

Output

seats: [101, 102, 103, 104, 105, 106]
gcd(48, 18) = 6
lcm(4, 6) = 12
midpoint(10, 20) = 15

Recorded with Apple clang version 21.0.0 (clang-2100.3.34.2) on macOS 26 arm64. To run it yourself: clang++ -std=c++23 -O2 -Wall -Wextra -Werror -pedantic -fsanitize=address,undefined helpers.cpp -o helpers && ./helpers

Each job is one call: seats from 101, a tile of side 6 for a 48 by 18 floor, lights that blink together every 12 seconds and 15 halfway between 10 and 20. Small positive test values like these never reach the edges: negative numbers, zeros, results too large for their type and odd sums.

Checkpoint

Check: iota, gcd, lcm and midpoint

  1. Question 1 of 2 std::iota(seats.begin(), seats.end(), 101) runs on a vector of 6 ints. What does it write?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 101, 102, 103, 104, 105, 106

    iota writes value, value + 1, value + 2 and so on into [first, last), as helpers.cpp printed: seats: [101, 102, 103, 104, 105, 106].

  2. Question 2 of 2 Two lights blink every 6 and every 10 seconds, starting together. After how many seconds do they next blink together, std::lcm(6, 10)?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 30 seconds

    The lights meet again at the smallest number that both 6 and 10 divide: 30. The program's lights, every 4 and 6 seconds, met every lcm(4, 6) = 12.

Practise: totals, types and ranges

The questions below start where your answers have been weakest, and each choice names the slip it guards against.

Practice that adapts to you

Practise this lesson

8 questions about 8 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 8 What does std::accumulate(v.begin(), v.end(), 0) return for std::vector<double> v{0.4, 0.4, 0.4}?

    Choose one answer.

    Show the answer: Question 1 of 8

    Answer: 0

    The initial value 0 is an int, so the total is an int: 0 + 0.4 is 0.4, stored back as 0, three times over. Pass 0.0 to add in double, or use C++23's std::ranges::fold_left, whose total takes the type that the addition returns.

  2. Question 2 of 8 Which call adds the four deposits of 1,000,000,000 paise into the right total, 4,000,000,000?

    Choose one answer.

    Show the answer: Question 2 of 8

    Answer: std::accumulate(deposits.begin(), deposits.end(), 0LL)

    The elements are long long, but the total follows the initial value. 0LL, or C++23's fold_left, gives a long long total and the right answer.

  3. Question 3 of 8 A vector of a million ints is summed from 0LL with std::reduce. Can the total differ from std::accumulate's?

    Choose one answer.

    Show the answer: Question 3 of 8

    Answer: No, because integer addition gives the same total in any grouping

    reduce is safe whenever the operation is associative and commutative, and integer addition is both. The rain of eight days gave 31 in both orders in the figure.

  4. Question 4 of 8 Which operation is unsafe to pass to std::reduce?

    Choose one answer.

    Show the answer: Question 4 of 8

    Answer: std::minus<>{}, subtraction

    reduce may regroup and reorder, so its operation must not care about either. Subtraction cares about both, so fold it with accumulate or fold_left.

  5. Question 5 of 8 With the rain prefix [0, 3, 4, 8, 9, 14, 23, 25, 31], how much rain fell on day 5 alone, the range [5, 6)?

    Type a number.

    Show the answer: Question 5 of 8

    Answer: 9 mm

    prefix[6] - prefix[5] = 23 - 14 = 9, the rain of day 5 in the data 3 1 4 1 5 9 2 6. A range of one day costs the same one subtraction as any other.

  6. Question 6 of 8 The daily values are corrected 10,000 times between the questions. What happens to the prefix-sum approach?

    Choose one answer.

    Show the answer: Question 6 of 8

    Answer: Each correction means rebuilding the array, so a Fenwick tree, with O(log n) updates and totals, fits better

    One pass to build and one subtraction per question is a great trade only while the data stays fixed. With frequent updates, rebuilding costs a pass each time, and a Fenwick tree handles both in O(log n) steps.

  7. Question 7 of 8 Why write std::midpoint(lo, hi) instead of (lo + hi) / 2 for two large ints?

    Choose one answer.

    Show the answer: Question 7 of 8

    Answer: It returns half the sum without overflowing, while lo + hi can exceed the int range

    (lo + hi) / 2 adds first, and the sum of two ints near the top of their range does not fit; midpoint computes the same middle without forming that sum.

  8. Question 8 of 8 What does std::gcd(-12, 18) return?

    Type a number.

    A hint

    gcd works on the absolute values of its arguments.

    Show the answer: Question 8 of 8

    Answer: 6

    gcd uses the absolute values, 12 and 18, and the largest number dividing both is 6. The result is never negative.

Prefix sums at scale: grids, overflow budgets and timed queries Pro: opens with a Pro, Premium or Ultimate pass

Prefix sums are the standard answer to range questions in reports and in coding rounds, and the details decide whether the answer is right: the type of the running total, the extra zero row of a grid and the cost of the alternative. This part works through all three with code that runs, then gives you an exercise in one and two dimensions.

In this part:

  • A running total kept in the input’s type, reproduced
  • Choosing the type of a prefix array: an overflow budget, worked
  • Rectangle sums in a grid, worked by hand
  • Measured: adding each range against one subtraction per query
  • Your turn: range sums in one dimension and two

1 diagram · 8 runnable examples (C header, C++, Python) · about 8 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

reduce, transform_reduce, gcd, lcm and midpoint: the traps, reproduced Pro: opens with a Pro, Premium or Ultimate pass

Each of these functions has one way to go wrong that a quick test does not show. This part reproduces each failure on both standard libraries and shows the version that holds.

In this part:

  • The same floats, two libraries, two different totals from reduce
  • Weighted totals with transform_reduce
  • gcd and lcm: signs, zeros and the overflow nobody checks
  • Midpoints without overflow, and which way they round
  • Choosing between them: a summary with the trade-offs

8 runnable examples (C++, Python) · about 6 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Interview questions

  1. Fresher · Warm-up

    What does std::accumulate(v.begin(), v.end(), 0) return for std::vector<double> v{0.5, 0.75, 1.25}, and why?

    It returns 1, as an int. accumulate keeps its running total in the type of the initial value, and 0 is an int, so every step converts the sum back to a whole number: 0 + 0.5 becomes 0, 0 + 0.75 becomes 0, and 0 + 1.25 becomes 1. Nothing warns about it, because the conversion happens inside the library. Passing 0.0 gives 2.5. The same rule makes a sum of large long long values with an initial 0 wrap round, since the total is still an int, and makes an initial "" fail to compile when joining strings. A good answer adds that C++23's std::ranges::fold_left takes the type of its total from what the operation returns, so it gives 2.5 even with 0.

  2. Fresher to mid

    You receive 200,000 daily sales figures, each up to 10^9 paise, and then 200,000 questions of the form "total sales from day l to day r". Design the solution, choose the types and give its cost. What changes if figures are corrected between questions?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A reporting job switched from std::accumulate to std::reduce, and now the float total of a revenue column changes in its last digits and differs between the Linux build with GCC and the Mac build with Clang. Is this a bug? Explain, and choose a fix.

    Model answer, Pro. First step and follow-ups

  4. Fresher to mid

    A binary search over byte offsets in a 3 GB file uses int lo and hi and computes mid = (lo + hi) / 2. It works on small files and hangs or crashes on large ones. Explain both failures, fix them, and say what std::midpoint guarantees.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • std::accumulate adds in the type of its initial value: write 0LL or 0.0, never a bare 0, for large or fractional sums.
  • std::reduce may regroup the additions, so floating-point totals can differ from accumulate.
  • Prefix sums turn the total of [l, r) into prefix[r] - prefix[l].
  • gcd, lcm and midpoint handle signs and overflow for you, except that the lcm itself must fit in its result type.

Terms in this lesson

fold
Combining the elements of a range into one value with an operation, starting from an initial value: a left fold of 1, 2 and 3 with + computes ((0 + 1) + 2) + 3. std::accumulate and C++23's std::ranges::fold_left fold from the left.
prefix sums
An array whose position i holds the total of the first i values, with 0 at position 0, so the total of the half-open range [l, r) is prefix[r] - prefix[l], one subtraction whatever its length. std::partial_sum and std::inclusive_scan write the running totals.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.