Namespaces
Variants

std::transform_reduce

cppreference.net에서 가져옴
 
 
알고리즘 라이브러리
제한된 알고리즘 및 범위에 대한 알고리즘 (C++20)
제한된 알고리즘, 예: ranges::copy, ranges::sort, ...
정렬 및 관련 연산
분할 연산
(C++11)    

정렬 연산
이진 검색 연산
(분할된 범위에 대해)
집합 연산 (정렬된 범위에 대해)
병합 연산 (정렬된 범위에 대해)
힙 연산
최소/최대 연산
(C++11)
(C++17)
사전식 비교 연산
순열 연산


 
 
헤더 <numeric>
template< class InputIt1, class InputIt2, class T >
T transform_reduce( InputIt1 first1, InputIt1 last1,
                    InputIt2 first2, T init );
에 정의됨 (1) (C++17 이후)
(C++20부터 constexpr)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class T >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt1 first1, ForwardIt1 last1,
                    ForwardIt2 first2, T init );
(2) (C++17 이후)
template< class InputIt1, class InputIt2, class T,
          class BinaryOp1, class BinaryOp2 >
T transform_reduce( InputIt1 first1, InputIt1 last1,
                    InputIt2 first2, T init,
                    BinaryOp1 reduce, BinaryOp2 transform );
(3) (C++17 이후)
(C++20부터 constexpr)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class T,
          class BinaryOp1, class BinaryOp2 >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt1 first1, ForwardIt1 last1,
                    ForwardIt2 first2, T init,
                    BinaryOp1 reduce, BinaryOp2 transform );
(4) (C++17 이후)
template< class InputIt, class T,
          class BinaryOp, class UnaryOp >
T transform_reduce( InputIt first, InputIt last, T init,
                    BinaryOp reduce, UnaryOp transform );
(5) (C++17 이후)
(C++20부터 constexpr)
template< class ExecutionPolicy,
          class ForwardIt, class T,
          class BinaryOp, class UnaryOp >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt first, ForwardIt last, T init,
                    BinaryOp reduce, UnaryOp transform );
(6) (C++17 이후)
1) 다음과 동일합니다.
transform_reduce(first1, last1, first2, init,
                 std::plus<>(), std::multiplies<>())
, 기본 std::inner_product의 효과적인 병렬화 버전입니다.
3) 각 요소 쌍에 대해 transform을(를) 범위 [first1, last1)와 std::distance(first1, last1)에서 시작하는 first2 요소 범위에 적용하고, init에 대한 reduce을(를) 통해 결과(지정되지 않은 방식으로 순열 및 집계될 수 있음)를 초기값
과 함께 축소합니다.reduce
이(가) 결합적이지 않거나 교환적이지 않은 경우(예: 부동소수점 덧셈) 결과는 비결정적입니다.T 다음 값 중
  • reduce(init, init)
  • reduce(init, transform(*first1, *first2))
  • reduce(transform(*first1, *first2), init)
  • reduce(transform(*first1, *first2), transform(*first1, *first2))
에(로) 변환할 수 없는 값이 있으면 프로그램의 형식이 잘못되었습니다. last2 std::distance(first1, last1)의 번째 다음 반복자를 first2로 지정할 때, 다음 조건 중 하나라도 충족되면 동작이 정의되지 않습니다.
  • T이(가) MoveConstructible이(가) 아닙니다.
  • transform 또는 reduce이(가) [first1, last1) 또는 [first2, last2)의 요소를 수정합니다.
  • transform 또는 reduce이(가) [first1, last1] 또는 [first2, last2]의 반복자나 하위 범위를 무효화합니다.
5) 범위 transform의 각 요소에 [first, last)을(를) 적용하고, init에 대한 reduce을(를) 통해 결과(지정되지 않은 방식으로 순열 및 집계될 수 있음)를 초기값
과 함께 축소합니다.reduce
이(가) 결합적이지 않거나 교환적이지 않은 경우(예: 부동소수점 덧셈) 결과는 비결정적입니다.T 다음 값 중
  • reduce(init, init)
  • reduce(init, transform(*first))
  • reduce(transform(*first), init)
  • reduce(transform(*first), transform(*first))
에(로) 변환할 수 없는 값이 있으면 프로그램의 형식이 잘못되었습니다.
  • T 다음 조건 중 하나라도 충족되면 동작이 정의되지 않습니다. 이(가) MoveConstructible
  • transform이(가) 아닙니다.reduce 또는 [first, last)이(가)
  • transform의 요소를 수정합니다.reduce 또는 [first, last]이(가)
의 반복자나 하위 범위를 무효화합니다.2,4,6) (1,3,5)와 동일하지만 policy에 따라 실행됩니다.
이러한 오버로드는 다음 표현식의 값이 true인 경우에만 오버로드 해결에 참여합니다.

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(C++20까지)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(C++20부터)

매개변수

first1, last1 - 범위 를 정의하는 반복자 쌍으로, transform 의 좌측 피연산자로 사용될 요소들을 지정합니다.
first2 - transform 의 우측 피연산자로 사용될 요소들의 범위 시작점입니다.
first, last - 범위 를 정의하는 반복자 쌍으로, transform 의 피연산자로 사용될 요소들을 지정합니다.
init - 일반화된 합계의 초기값입니다.
policy - 사용할 실행 정책 입니다.
reduce - 이항 FunctionObject 로, transform 의 결과, 다른 reduce 의 결과, 그리고 init 에 대해 지정되지 않은 순서로 적용됩니다.
transform - 단항 또는 이항 FunctionObject 로, 입력 범위(들)의 각 요소에 적용됩니다. 반환 타입은 reduce 의 입력으로 사용 가능해야 합니다.
타입 요구사항
-
InputIt1, InputIt2, InputIt 는 LegacyInputIterator 요구사항을 충족해야 합니다.
-
ForwardIt1, ForwardIt2, ForwardIt 는 LegacyForwardIterator 요구사항을 충족해야 합니다.

반환값

1,2) init 과 values 의 일반화된 합을 std:: plus <> ( ) 에 대해 계산하며, 여기서 values 는 std:: multiplies <> ( ) 로 변환된 값들이고, 각 값은 두 입력 범위의 요소 쌍으로부터 변환됩니다.
3,4) init 과 values 의 일반화된 합을 reduce 를 통해 계산하며, 여기서 values 는 transform 으로 변환된 값들이고, 각 값은 두 입력 범위의 요소 쌍으로부터 변환됩니다.
5,6) init 과 values 의 일반화된 합을 reduce 에 대해 계산하며, 여기서 values 는 transform 에 의해 변환된 값들이고, 각 값은 입력 범위의 요소로부터 변환됩니다.

요소 그룹의 일반화된 합 은 이진 연산 binary_op 에 대해 다음과 같이 정의됩니다:

  • 그룹에 요소가 하나만 있는 경우, 합계는 해당 요소의 값입니다.
  • 그렇지 않은 경우, 다음 작업을 순서대로 수행합니다:
  1. 그룹에서 임의의 두 요소 elem1 과 elem2 를 가져옵니다.
  2. binary_op ( elem1, elem2 ) 을 계산하고 결과를 그룹에 다시 넣습니다.
  3. 그룹에 요소가 하나만 남을 때까지 1단계와 2단계를 반복합니다.

복잡도

주어진 N 을 std:: distance ( first1, last1 ) (또는 오버로드 (5,6) 의 경우 std:: distance ( first, last ) )으로 정의합니다:

1,2) O(N) 번의 std:: plus <> ( ) 및 std:: multiplies <> ( ) 적용 각각.
3-6) O(N) 번의 reduce 및 transform 적용 각각.

예외

ExecutionPolicy 라는 템플릿 매개변수를 사용하는 오버로드는 다음과 같이 오류를 보고합니다:

  • 알고리즘의 일부로 호출된 함수 실행 중 예외가 발생하고 ExecutionPolicy 가 표준 정책 중 하나인 경우, std::terminate 가 호출됩니다. 다른 ExecutionPolicy 의 경우 동작은 구현에 따라 정의됩니다.
  • 알고리즘이 메모리 할당에 실패하는 경우, std::bad_alloc 이 throw됩니다.

참고 사항

transform 는 init 에 적용되지 않습니다.

만약 first == last 이거나 first1 == last1 인 경우, init 이 수정되지 않은 상태로 반환됩니다.

예제

transform_reduce 는 std::inner_product 의 병렬화에 사용될 수 있습니다. 일부 시스템에서는 병렬 실행의 이점을 얻기 위해 추가 지원이 필요할 수 있습니다. 예를 들어, GNU/Linux에서는 Intel TBB 가 설치되고 gcc/clang 컴파일러에 - ltbb 옵션이 제공되어야 합니다.

#if PARALLEL
#include <execution>
#define PAR std::execution::par,
#else
#define PAR
#endif
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <locale>
#include <numeric>
#include <vector>
// to parallelize non-associate accumulative operation, you'd better choose
// transform_reduce instead of reduce; e.g., a + b * b != b + a * a
void print_sum_squared(long const num)
{
    std::cout.imbue(std::locale{"en_US.UTF8"});
    std::cout << "num = " << num << '\n';
    // create an immutable vector filled with pattern: 1,2,3,4, 1,2,3,4 ...
    const std::vector<long> v{[n = num * 4] {
        std::vector<long> v;
        v.reserve(n);
        std::generate_n(std::back_inserter(v), n,
            [i = 0]() mutable { return 1 + i++ % 4; });
        return v;
    }()};
    auto squared_sum = [](auto sum, auto val) { return sum + val * val; };
    auto sum1 = std::accumulate(v.cbegin(), v.cend(), 0L, squared_sum);
    std::cout << "accumulate(): " << sum1 << '\n';
    auto sum2 = std::reduce(PAR v.cbegin(), v.cend(), 0L, squared_sum);
    std::cout << "reduce(): " << sum2 << '\n';
    auto sum3 = std::transform_reduce(PAR v.cbegin(), v.cend(), 0L, std::plus{},
                                      [](auto val) { return val * val; });
    std::cout << "transform_reduce(): " << sum3 << "\n\n";
}
int main()
{
    print_sum_squared(1);
    print_sum_squared(1'000);
    print_sum_squared(1'000'000);
}

가능한 출력:

num = 1
accumulate(): 30
reduce(): 30
transform_reduce(): 30
num = 1,000
accumulate(): 30,000
reduce(): -7,025,681,278,312,630,348
transform_reduce(): 30,000
num = 1,000,000
accumulate(): 30,000,000
reduce(): -5,314,886,882,370,003,032
transform_reduce(): 30,000,000
// Compile-options for parallel execution on POSIX:
// g++ -O2 -std=c++17 -Wall -Wextra -pedantic -DPARALLEL ./example.cpp -ltbb -o tr; ./tr

참고 항목

요소 범위를 합산하거나 폴드합니다
(함수 템플릿)
요소 범위에 함수를 적용하여 결과를 대상 범위에 저장합니다
(함수 템플릿 & 알고리즘 함수 객체)
(C++17)
std::accumulate와 유사하지만 순서에 상관없음
(함수 템플릿)