본문으로 건너뛰기
김신건의 로그

사칙연산 (Arithmetic Operations)

· 수정 · 📖 약 4분 · 1,150자/단어 #algorithm #foundation #arithmetic
arithmetic, 사칙연산, 큰 수 연산, overflow

정의

사칙연산 (Arithmetic Operations) 은 덧셈, 뺄셈, 곱셈, 나눗셈의 정확한 구현을 다루는 PS 태그. 큰 수 표현 (large integer), 오버플로우 (overflow), mod p 사칙연산, 부동소수점 정밀도 (floating point precision) 등 기본 연산의 함정을 포함.

정수 타입 범위 (int: -2^31 ~ 2^31-1, long long: -2^63 ~ 2^63-1), 부동소수점 정밀도 (double`: 15자리), mod 연산의 음수 처리 등은 모든 PS 문제에 영향.

문제 상황과 동기

PS 에서 사칙연산 태그는 다음 네 실수를 피하기 위한 검증.

  1. 오버플로우: int a = 2e9; int b = 2e9; int c = a + b; → c 는 음수. long long 필요.
  2. 큰 수: N 이 10^18 이상이면 long long 도 부족. Python int 또는 BigInteger, 또는 mod 연산으로 우회.
  3. 나눗셈의 정수 몫: 5 / 2 = 2 (정수 나눗셈). 부동소수점 변환 조심.
  4. mod 음수: C++/Java 에서 (-5) % 3 = -2 (Python 은 1). 음수 처리 필요.
  5. 부동소수점 오차: 0.1 + 0.2 != 0.3 (IEEE 754). epsilon 비교.

핵심 통찰: 타입 범위를 미리 파악 하고, 중간 계산 오버플로우 를 피한다.

실무 / PS 위치: 큰 수 라이브러리, 암호학 (RSA), 정밀 수치 계산 (금융, 물리 시뮬레이션).

시각화

핵심 아이디어

정수 타입 범위

타입범위비고
int (32bit)-2^31 ~ 2^31-1약 -2·10^9 ~ 2·10^9
long long (64bit)-2^63 ~ 2^63-1약 -9·10^18 ~ 9·10^18
Python int무제한GMP 기반 가변 길이
Java BigInteger무제한느림 (O(N^2) 곱셈)

오버플로우 방지

// WRONG
int a = 2'000'000'000, b = 2'000'000'000;
int c = a + b;   // overflow, c < 0

// RIGHT
long long a = 2'000'000'000, b = 2'000'000'000;
long long c = a + b;   // OK

곱셈도 마찬가지: 10^5 × 10^5 = 10^10 > int max.

mod 연산 음수 처리

int mod(int a, int M) {
    return ((a % M) + M) % M;
}

C++/Java 에서 a % M 가 음수일 때 + M 필요. Python 은 자동 양수.

부동소수점 비교

const double EPS = 1e-9;
bool eq(double a, double b) {
    return abs(a - b) < EPS;
}

a == b 는 부동소수점에서 거의 항상 틀림. epsilon 비교.

큰 수 (Python)

a = 10**100
b = 10**100
c = a + b   # 자동으로 무제한 정밀도

Python 3 의 int 는 임의 정밀도 (arbitrary precision). 단, 시간이 길다 (곱셈 O(N log N) 또는 O(N^2)).

알고리즘

안전한 덧셈/곱셈 (C++)

safe_add(a, b, M):
    if a + b overflows:
        use long long or mod M
    return (a + b) mod M

safe_mul(a, b, M):
    return ((long long)a * b) % M

정수 나눗셈 올림

ceil_div(a, b):   # a, b > 0
    return (a + b - 1) / b

또는 (a - 1) / b + 1. 단, a=0 일 때 조심.

mod 음수 처리

mod(a, M):
    r = a % M
    if r < 0: r += M
    return r

구현

// 오버플로우 방지, mod 음수 처리
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll safe_mod(ll a, ll M) {
  return ((a % M) + M) % M;
}

ll safe_add(ll a, ll b, ll M) {
  return safe_mod(a + b, M);
}

ll safe_mul(ll a, ll b, ll M) {
  return safe_mod(a * b, M);
}

ll ceil_div(ll a, ll b) {   // a, b > 0
  return (a + b - 1) / b;
}

int main() {
  ll a, b, M;
  cin >> a >> b >> M;
  cout << a << " + " << b << " = " << a + b << "\n";
  cout << a << " * " << b << " = " << a * b << "\n";
  cout << a << " + " << b << " mod " << M << " = " << safe_add(a, b, M) << "\n";
  cout << a << " * " << b << " mod " << M << " = " << safe_mul(a, b, M) << "\n";
  cout << a << " / " << b << " (floor) = " << a / b << "\n";
  cout << a << " / " << b << " (ceil) = " << ceil_div(a, b) << "\n";
  ll neg = -17;
  cout << neg << " % " << M << " (C++) = " << neg % M << "\n";
  cout << neg << " mod " << M << " (safe) = " << safe_mod(neg, M) << "\n";
}
stdin
1000000000 2000000000 1000000007
결과
1000000000 + 2000000000 = 3000000000
1000000000 * 2000000000 = 2000000000000000000
1000000000 + 2000000000 mod 1000000007 = 999999986
1000000000 * 2000000000 mod 1000000007 = 951432069
1000000000 / 2000000000 (floor) = 0
1000000000 / 2000000000 (ceil) = 1
-17 % 1000000007 (C++) = -17
-17 mod 1000000007 (safe) = 999999990

복잡도

항목
정수 덧셈/뺄셈O(1) (고정 길이), O(N) (큰 수, N=자릿수)
정수 곱셈O(1) (고정 길이), O(N^2) ~ O(N log N) (큰 수)
mod 연산O(1) (정수), O(N^2) (큰 수)
부동소수점 연산O(1) (하드웨어 지원)

Python int 곱셈은 Karatsuba / Toom-Cook / FFT 로 O(N^1.58) ~ O(N log N). 길이 10^6 자릿수 이상은 느림.

변형 / 활용

기법설명복잡도
고정 소수점정수로 10^6 배하여 정밀도 유지O(1)
분수 (Fraction)분자/분모 쌍으로 정확한 유리수 표현O(log N) (GCD)
BigIntegerJava/C++ 큰 수 라이브러리O(N^2) 곱셈
Python int무제한 정밀도 정수O(N log N) ~ O(N^2)
__int128GCC 128bit 정수 (출력 불가, 내부 계산만)O(1)

함정

1. int 오버플로우

int a = 100000, b = 100000;
int c = a * b;   // overflow, 10^10 > 2^31

곱셈 전에 long long 으로 캐스팅: (long long)a * b.

2. 나눗셈 올림 (ceiling)

int ceil_div(int a, int b) {
    return (a + b - 1) / b;   // a, b > 0
}

(a - 1) / b + 1 은 a=0 일 때 틀림.

3. mod 음수 (C++/Java)

-17 % 5 = -2   // C++/Java
-17 % 5 = 3    // Python

C++/Java 는 ((a % M) + M) % M 또는 Java 8+ Math.floorMod(a, M).

4. 부동소수점 ==

double a = 0.1 + 0.2;
if (a == 0.3) { /* never true */ }
if (abs(a - 0.3) < 1e-9) { /* correct */ }

IEEE 754 오차로 0.1 + 0.2 = 0.30000000000000004. epsilon 비교 필수.

5. long long 도 부족한 경우

N=10^18 의 제곱은 10^36, long long (10^18) 범위 초과. Python 또는 mod 연산으로 우회.

BOJ 연습 문제

번호제목정답률링크
BOJ 1000A+B58.3%kokoa-lab
BOJ 1001A-B55.7%kokoa-lab
BOJ 1008A/B36.2%kokoa-lab
BOJ 1271엄청난 부자241.5%kokoa-lab
BOJ 2338긴자리 계산48.9%kokoa-lab
BOJ 10757큰 수 A+B26.4%kokoa-lab
BOJ 15740A+B - 929.1%kokoa-lab

참고

이 글의 용어 (3개)
분류 모델 지표: Confusion Matrix, Precision, Recall, F1ml
정의 분류 (classification) 모델의 성능을 정량화하는 지표들입니다. 이진 분류를 기준으로 하며, multi-class 로 확장하는 방법도 함께 다룹니다. 핵심 출발점…
수학 (Mathematics)algorithm
정의 수학 (Mathematics) 은 문제 해결에 필요한 모듈러 산술 (modular arithmetic), 최대공약수/최소공배수 (GCD/LCM), 거듭제곱 (exponent…
임의 정밀도 / 큰 수 산술 (Arbitrary Precision)algorithm
정의 임의 정밀도 (Arbitrary Precision) 또는 큰 수 산술 (Big Integer / Bignum) 은 고정된 바이트 한계(32-bit, 64-bit) 없이 메모…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기