임의 정밀도 / 큰 수 산술 (Arbitrary Precision)
정의
임의 정밀도 (Arbitrary Precision) 또는 큰 수 산술 (Big Integer / Bignum) 은 고정된 바이트 한계(32-bit, 64-bit) 없이 메모리가 허용하는 한 임의로 큰 정수를 표현하고 연산하는 기법. 배열에 자릿수를 저장하고 학교 교과서 방식 (O(n^2)) 또는 Karatsuba (O(n^1.585)), FFT/NTT (O(n log n)) 곱셈으로 구현.
문제 상황과 동기
C long long (64-bit, 약 ±9.22×10^18) 으로 표현 불가능한 수를 다룬다. 10000자리 소수 곱셈, 암호학 (RSA 2048-bit key), 조합론 (nCr, n≤100000) 등.
- naive: built-in 64-bit overflow. 해결 불가.
- string/vector 기반: Base 10 또는 Base 10^9 표현. 덧셈/뺄셈 O(n), 곱셈 O(n^2) (schoolbook) / O(n^1.585) (Karatsuba) / O(n log n) (FFT).
핵심 통찰: 큰 수를 작은 단위(자릿수)로 분할. 올림(carry)을 순차 전파.
시각화
핵심 아이디어
숫자를 자릿수 배열로 표현. a[0] = 일의 자리. 덧셈은 각 자리별 덧셈 + 올림 전파.
10^N base 표현 (각 원소가 0~9):
n = a_0 + a_1·10 + a_2·10^2 + ... + a_{k-1}·10^{k-1}
덧셈:
for i = 0..k-1:
sum = a_i + b_i + carry
result_i = sum % 10
carry = sum / 10
곱셈 (schoolbook):
for i = 0..ka-1:
for j = 0..kb-1:
result[i+j] += a_i * b_j
// 올림 정리
구현
// String 기반 큰 수 더하기 (Base 10)
#include <bits/stdc++.h>
using namespace std;
string add(string a, string b) {
if (a.size() < b.size()) swap(a, b);
int carry = 0;
for (int i = a.size() - 1, j = b.size() - 1; i >= 0; i--, j--) {
int sum = (a[i] - '0') + (j >= 0 ? b[j] - '0' : 0) + carry;
a[i] = (sum % 10) + '0';
carry = sum / 10;
}
if (carry) a = char(carry + '0') + a;
return a;
}
int main() {
string a, b; cin >> a >> b;
cout << add(a, b);
return 0;
}1234 56786912
7006652복잡도
| 항목 | 값 |
|---|---|
| 덧셈/뺄셈 (시간) | O(n) |
| 곱셈 (schoolbook) | O(n^2) |
| 곱셈 (Karatsuba) | O(n^{log_2 3}) ≈ O(n^1.585) |
| 곱셈 (FFT/NTT) | O(n log n) |
| 공간 | O(n) |
변형 / 활용
Karatsuba 곱셈
큰 수를 반으로 분할: a = a1·B^m + a0, b = b1·B^m + b0. 곱셈 3회로 축소 (n^2 -> n^1.585).
z2 = a1·b1
z0 = a0·b0
z1 = (a1+a0)·(b1+b0) - z2 - z0
결과 = z2·B^{2m} + z1·B^m + z0
FFT/NTT 곱셈
convolution 으로 변환하여 O(n log n). 수십만 자리 이상에서 실용적. FFT/NTT 문서 참조.
Base 변환
10진 입출력에 유리한 Base 10 vs 연산 효율의 Base 10^9. 내부 Base 2^64 (GMP 스타일).
함정
1. 음수 처리
뺄셈에서 부호 결정. sign 플래그 분리 또는 보수 표현.
2. leading zero
연산 후 앞쪽 불필요한 0 제거. 결과가 0이면 하나의 0 유지.
3. 캐리 전파 지연
덧셈/곱셈 후 올림이 연쇄 전파될 수 있음. 한 번의 정리 패스로 해결.
4. FFT 반올림 오차
복소수 FFT 는 부동소수점 오차 발생. NTT (정수 mod prime) 로 대체.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 10757 | 큰 수 A+B | 51.3% | kokoa-lab |
| BOJ 2338 | 긴자리 계산 | 49.9% | kokoa-lab |
| BOJ 1271 | 엄청난 부자2 | 35.6% | kokoa-lab |
| BOJ 2407 | 조합 | 42.6% | kokoa-lab |
참고
- FFT/NTT (고속 곱셈)
- 분할 정복을 이용한 거듭제곱
- 사칙연산
이 글의 용어 (3개)
- 분할 정복을 이용한 거듭제곱 (Exponentiation by Squaring)algorithm
- 정의 분할 정복을 이용한 거듭제곱 (Exponentiation by Squaring) 은 을 O(log n) 시간에 계산하는 분할 정복 알고리즘. 같은 모듈러 연산에서 특히 필수…
- 사칙연산 (Arithmetic Operations)algorithm
- 정의 사칙연산 (Arithmetic Operations) 은 덧셈, 뺄셈, 곱셈, 나눗셈의 정확한 구현을 다루는 PS 태그. 큰 수 표현 (large integer), 오버플로우…
- FFT, NTTalgorithm
- 정의 FFT (Fast Fourier Transform, 고속 푸리에 변환) 은 길이 인 수열의 이산 푸리에 변환 (DFT) 을 O(n log n) 에 계산하는 분할정복 알고리즘…
💬 댓글