이번 튜토리얼에서는 C++의 transform_inclusive_scan() 함수에 대해 자세히 알아보겠습니다.
transform_inclusive_scan() 함수란?
transform_inclusive_scan()은 C++17부터 <numeric> 헤더에서 제공하는 알고리즘으로, 컨테이너의 각 요소에 단항 연산(unary operation)을 먼저 적용한 뒤, 그 결과들을 이진 연산(binary operation)으로 순차적으로 누적하는 기능을 수행합니다.
결과적으로 각 위치에는 '현재 요소까지의 변환된 누적 값'이 저장됩니다. 흔히 알고 있는 접두사 합(prefix sum)에 변환 단계가 추가된 형태라고 이해하면 쉽습니다. 아래 예제에서는 이 함수를 직접 구현하여 내부 동작 원리를 확인해 보겠습니다.
예제 코드
#include <iostream>
#include <vector>
using namespace std;
namespace point_input_iterator {
template <class InputItrator, class OutputItrator, class BinaryOperation, class UnaryOperation>
OutputItrator transform_inclusive_scan(InputItrator first,
InputItrator last,
OutputItrator d_first,
BinaryOperation binary_op,
UnaryOperation unary_op){
*d_first = unary_op(*first);
first++;
d_first++;
for (auto it = first; it != last; it++) {
// 접두사 합 계산
*d_first = binary_op(unary_op(*it), *(d_first - 1));
d_first++;
}
return d_first;
}
}
int main(){
// 벡터를 사용하여 요소 입력
vector<int> InputVector{ 11, 22, 33, 44, 55, 66, 77, 88 };
vector<int> OutputVector(8);
point_input_iterator::transform_inclusive_scan(
InputVector.begin(), InputVector.end(), OutputVector.begin(),
[](auto xx, auto yy) {
return xx + yy;
},
[](auto xx) {
return xx * xx;
});
for (auto item : OutputVector) {
// 출력 항목 출력
cout << item << " ";
}
cout << std::endl;
return 0;
}
실행 결과
121 605 1694 3630 6655 11011 16940 24684
동작 원리 분석
위 예제에서는 두 개의 람다 식이 사용되었습니다.
- 단항 연산(
xx * xx): 입력 벡터의 각 요소를 제곱합니다. - 이진 연산(
xx + yy): 변환된 현재 값과 바로 앞 요소까지의 누적 값을 더합니다.
입력 벡터 {11, 22, 33, 44, 55, 66, 77, 88}의 각 요소를 제곱하면 {121, 484, 1089, 1936, 3025, 4356, 5929, 7744}가 되고, 이를 차례대로 누적하면 다음과 같은 결과가 만들어집니다.
- 첫 번째 요소: 121
- 두 번째 요소: 121 + 484 = 605
- 세 번째 요소: 605 + 1089 = 1694
- 네 번째 요소: 1694 + 1936 = 3630
- 이후 요소들도 동일한 방식으로 계속 누적됩니다.
이처럼 transform_inclusive_scan()은 데이터 변환과 누적 계산을 한 번의 순회로 동시에 처리할 수 있어, 부분합 계산이나 통계 데이터 처리 등에서 매우 유용하게 활용됩니다.