Chapter 5

시그마와 인덱스

긴 덧셈을 짧게 쓰는 약속
핵심 질문

Σ\Sigma는 어떤 반복 덧셈을 뜻할까?

시그마와 인덱스

핵심 질문

긴 배열의 값을 더할 때 왜 기호와 번호가 필요할까?

교과서 설명

배열은 여러 값을 순서대로 적어 둔 목록이다. 컴퓨터 수학에서는 보통 첫 번째 칸을 번이라고 부른다.

여기서 은 배열에 들어 있는 값의 개수다. 번호 은 지금 보고 있는 칸의 위치를 뜻한다.

값을 모두 더해야 할 때 매번 길게 쓰면 불편하다.

그래서 같은 뜻을 더 짧게 다음처럼 쓴다.

이 표기는 “부터 시작해서 까지 차례대로 넣고 모두 더하라”는 뜻이다.

시그마가 두 번 나오면 바깥 번호를 하나 고정하고, 안쪽 번호를 전부 돌며 더한 뒤, 그 일을 바깥 번호마다 반복한다.

이 식은 표의 모든 칸을 더하는 것처럼 볼 수 있다. 먼저 번째 줄에서 모든 를 더하고, 다음 줄로 넘어가는 식이다.

예를 들어 표가

라면 을 뜻한다. 바깥 번호 는 줄을 고르고, 안쪽 번호 는 그 줄 안의 칸을 차례로 고른다.

합성곱에서는 두 번호 가 함께 움직인다. 라고 두면, 같은 를 만드는 모든 쌍을 한 칸에 모은다.

그래서 나중에 로 바뀌어도, 뜻은 “모든 가능한 두 칸의 조합을 한 번씩 본다”는 것이다.

DFT의 식도 결국 같은 모양이다. 를 하나 고정해 놓고, 모든 샘플 번호 에 대해 계산한 값을 더한다.

인덱스 조작과 합의 범위

시그마에서 사용하는 글자 이름은 본질이 아니다. 아래 두 식은 같은 뜻이다.

이런 글자를 더미 인덱스라고 부른다. 중요한 것은 인덱스가 도는 범위와, 그 인덱스를 식 안에서 어떻게 쓰는가다.

시그마는 덧셈이므로 분배법칙도 그대로 따른다. 같은 범위에서 더한다면

이고, 상수 는 합 밖으로 뺄 수 있다.

이 성질은 뒤에서 DFT의 선형성을 증명할 때 그대로 사용된다.

합성곱처럼 라고 쓸 때는 숨어 있는 조건이 있다. 배열 밖의 값은 으로 보겠다고 약속하면 모든 정수 에 대해 쓸 수 있지만, 실제로 더해지는 항은 다음 조건을 만족하는 것뿐이다.

따라서 실제 범위는 다음처럼 정리할 수 있다.

처음에는 복잡해 보이지만, 의미는 단순하다. 에서 하나, 에서 하나를 골랐을 때 두 번호의 합이 가 되는 조합만 더한다는 뜻이다. FFT 합성곱의 증명에서는 이런 인덱스 정리가 로 바꾸는 핵심 역할을 한다.

직관 비유

반 학생들의 키를 모두 더한다고 생각하자. “1번 학생 키 + 2번 학생 키 + ...”라고 길게 말하는 대신, “모든 학생 번호를 돌며 키를 더한다”고 말할 수 있다. 은 이 반복 덧셈을 짧게 적는 약속이다.

예제

배열이 다음과 같다고 하자.

그러면 이고, 번호는 이다.

값을 넣으면

조금 더 복잡하게, 번호와 값을 곱해서 더할 수도 있다.

시그마는 새로운 계산법이 아니라, 반복되는 덧셈을 정리해서 쓰는 표기법이다.

손풀이 체크

  1. 이면 은?

    답 보기

    33

  2. 은 어떤 덧셈을 뜻할까?

    답 보기

    x[0]+x[1]+x[2]x[0]+x[1]+x[2]

  3. 일 때 은?

    답 보기

    2+5+1=82+5+1=8

다음으로 이어지는 생각

여러 숫자를 번호로 관리하고 더할 수 있으면, 두 배열이 얼마나 같은 방향인지 재는 내적도 자연스럽게 이해할 수 있다.

이번 장에서 기억할 3문장

  1. 시그마는 정해진 인덱스 범위를 차례로 넣어 더하라는 약속이다.
  2. 배열의 nn번째 값은 x[n]x[n]처럼 쓰고, 보통 0번부터 센다.
  3. DFT 식은 모든 샘플 nn에 대해 같은 규칙을 반복해서 더하는 식이다.

C++ Practice

C++로 확인하기

시그마 n=0N1x[n]\sum_{n=0}^{N-1}x[n]를 반복문으로 직접 계산하기

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> values = {3, 1, 4, 2};
    int sum = 0;
    int weighted_sum = 0;

    for (int n = 0; n < static_cast<int>(values.size()); ++n) {
        sum += values[n];
        weighted_sum += n * values[n];
    }

    cout << "sum x[n] = " << sum << "\n";
    cout << "sum n*x[n] = " << weighted_sum << "\n";
}

연습: x[n]x[n] 배열을 바꾸고 x[n]\sum x[n], nx[n]\sum n x[n]을 손으로 먼저 계산해 보자.