C++ Algorithm Numeric | "Numeric Algorithms" Guide

C++ Algorithm Numeric | "Numeric Algorithms" Guide

이 글의 핵심

Numeric algorithms: accumulate, reduce, transform_reduce—folds, parallel reductions, and choosing safe initial types.

Header <numeric> provides folds (accumulate, reduce), partial sums, adjacent differences, and inner product—operations that combine elements across a range with a custom binary op. accumulate is sequential and can take any binary function (default +). reduce (C++17) may reorder for parallel execution (std::execution::par), so the operation should be associative (e.g. don’t use parallel reduce for string concatenation unless you accept reordering). Pick the initial value type carefully (0.0 for double sums).

Numeric algorithms

Sum is the most common use of accumulate; pass std::multiplies<>{} as the fourth argument for a product.

#include <numeric>
#include <vector>

std::vector<int> v = {1, 2, 3, 4, 5};

// Sum
int sum = std::accumulate(v.begin(), v.end(), 0);

// Product
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>());

accumulate

The initial value determines the result type: accumulate(..., 0) yields int; use 0L, 0.0, or 0.0f when you need wider numeric types.

#include <numeric>

std::vector<int> v = {1, 2, 3, 4, 5};

// Sum
int sum = std::accumulate(v.begin(), v.end(), 0);
std::cout << "Sum: " << sum << std::endl;  // 15

// Product
int product = std::accumulate(v.begin(), v.end(), 1, 
    [](int a, int b) { return a * b; });
std::cout << "Product: " << product << std::endl;  // 120

Practical Examples

Example 1: Average

#include <numeric>
#include <vector>

double average(const std::vector<int>& v) {
    if (v.empty()) return 0.0;
    
    int sum = std::accumulate(v.begin(), v.end(), 0);
    return static_cast<double>(sum) / v.size();
}

int main() {
    std::vector<int> scores = {85, 90, 78, 92, 88};
    std::cout << "Average: " << average(scores) << std::endl;
}

Example 2: transform_reduce

#include <numeric>
#include <vector>

int main() {
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {2, 2, 2, 2, 2};
    
    // Dot product
    int dotProduct = std::transform_reduce(
        v1.begin(), v1.end(),
        v2.begin(),
        0
    );
    
    std::cout << "Dot Product: " << dotProduct << std::endl;  // 30
}

Example 3: reduce (C++17)

#include <numeric>
#include <execution>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // Sequential
    int sum1 = std::reduce(v.begin(), v.end());
    
    // Parallel
    int sum2 = std::reduce(std::execution::par, v.begin(), v.end());
    
    std::cout << "Sum: " << sum2 << std::endl;  // 55
}

Example 4: partial_sum

#include <numeric>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::vector<int> result(v.size());
    
    // Cumulative sum
    std::partial_sum(v.begin(), v.end(), result.begin());
    
    for (int x : result) {
        std::cout << x << " ";  // 1 3 6 10 15
    }
}

Numeric Algorithms

// Aggregation
std::accumulate(begin, end, init)
std::reduce(begin, end, init)  // C++17, supports parallel execution

// Transform and aggregate
std::transform_reduce(begin1, end1, begin2, init)

// Cumulative operations
std::partial_sum(begin, end, out)
std::inclusive_scan(begin, end, out)  // C++17
std::exclusive_scan(begin, end, out)  // C++17

// Difference
std::adjacent_difference(begin, end, out)

// Dot product
std::inner_product(begin1, end1, begin2, init)

// Sequence generation
std::iota(begin, end, value)

Common Issues

Issue 1: Initial Value

std::vector<int> v = {1, 2, 3, 4, 5};

// ❌ Incorrect initial value
int sum = std::accumulate(v.begin(), v.end(), 0.0);  // double

// ✅ Correct initial value
int sum = std::accumulate(v.begin(), v.end(), 0);

Issue 2: Overflow

std::vector<int> v = {1000000, 1000000, 1000000};

// ❌ int overflow
int sum = std::accumulate(v.begin(), v.end(), 0);

// ✅ long long
long long sum = std::accumulate(v.begin(), v.end(), 0LL);

Issue 3: Order

// accumulate: Order guaranteed
int result1 = std::accumulate(v.begin(), v.end(), 0);

// reduce: Order not guaranteed (supports parallel execution)
int result2 = std::reduce(v.begin(), v.end(), 0);

// Use only operations that satisfy commutative/associative properties

Issue 4: Parallel Processing

#include <execution>

std::vector<int> v(1000000);

// Sequential
auto sum1 = std::reduce(v.begin(), v.end());

// Parallel
auto sum2 = std::reduce(std::execution::par, v.begin(), v.end());

// par_unseq: Vectorized execution
auto sum3 = std::reduce(std::execution::par_unseq, v.begin(), v.end());

iota

#include <numeric>

std::vector<int> v(10);

// Sequential generation
std::iota(v.begin(), v.end(), 1);

for (int x : v) {
    std::cout << x << " ";  // 1 2 3 4 5 6 7 8 9 10
}

FAQ

Q1: accumulate?

A: Aggregation. Order guaranteed.

Q2: reduce?

A: C++17. Supports parallel execution. Order not guaranteed.

Q3: transform_reduce?

A: Transform followed by aggregation.

Q4: Parallel processing?

A: std::execution::par.

Q5: Initial value?

A: Type consistency is important.

Q6: Learning resources?

A:

  • “C++17 The Complete Guide”
  • “Effective STL”
  • cppreference.com

Here are other posts related to this topic:

Practical Tips

Tips for immediate application in real-world scenarios.

Debugging Tips

  • Check compiler warnings first when issues arise
  • Reproduce the issue with simple test cases

Performance Tips

  • Avoid optimization without profiling
  • Set measurable performance metrics first

Code Review Tips

  • Anticipate common review comments and address them proactively
  • Follow your team’s coding conventions

Practical Checklist

A checklist to ensure proper application of these concepts in real-world projects.

Before Writing Code

  • Is this technique the best solution for the current problem?
  • Can team members understand and maintain this code?
  • Does it meet performance requirements?

While Writing Code

  • Have all compiler warnings been resolved?
  • Are edge cases accounted for?
  • Is error handling adequate?

During Code Review

  • Is the intent of the code clear?
  • Are there sufficient test cases?
  • Is the code documented?

Use this checklist to minimize mistakes and improve code quality.


Keywords Covered in This Post (Related Search Terms)

Search for terms like C++, algorithm, numeric, reduce, STL to find content related to this post.