반응형
우리가 수학에서 정수 나눗셈과 나머지(modular) 연산을 다룰 때는, 나머지가 0 이상인 정수이다. 하지만 프로그래밍 언어에서는 이러한 연산이 언어마다 다르게 정의되며, 그 차이는 특히 음수 연산에서 두드러진다. 이로 인해 프로그램이 의도와 다르게 동작할 수 있으므로, 정확한 이해가 필요하다.
1. 사례: C++ vs Python
C++
int a = -5 / 2; // 결과: -2
int b = -5 % 2; // 결과: -1Python
a = -5 // 2 # 결과: -3
b = -5 % 2 # 결과: 1둘 다 -5 ÷ 2를 계산하는 코드지만, 결과는 다르다.
2. 핵심 차이: 몫 연산의 방향성과 나머지의 부호
나눗셈을 수행할 때 소수점 이하의 값을 어떻게 처리하느냐에 따라 이러한 차이가 발생한다.
C++: 0을 기준으로 내림(truncate toward zero)
- 나눗셈
/: 소수점 이하는 0 방향으로 버림
→-5 / 2 = -2 - 나머지
%:a = q * d + r관계를 만족시키되, 나머지 r은 피제수(a)와 같은 부호
→-5 = (-2) * 2 + (-1)
Python: 음의 무한대로 내림(floor division)
- 나눗셈
//: 결과를 항상 아래 방향(−∞) 으로 내림
→-5 // 2 = -3 - 나머지
%: 제수와 같은 부호를 가지며, 항상0 ≤ r < |d|를 만족
→-5 = (-3) * 2 + 1
3. 나머지 정리
정수 나눗셈은 다음의 기본식으로 표현된다:
a = q * d + r여기서
a: 피제수d: 제수q: 몫r: 나머지
그리고 나머지는 아래 조건을 만족해야 한다:
0 ≤ r < |d|즉, Python의 정수 나눗셈과 모듈러 연산은 수학적인 floor 기반 나머지 정리를 충실히 따르지만, C++은 몫을 0 방향으로 자르고 나머지를 피제수의 부호로 맞추는 방식으로 구현되어 있다.
4. 왜 이런 차이가 생겼을까?
C/C++/Java의 이유:
- 성능 중심의 설계
- 하드웨어의
idiv명령은 몫을 0 방향으로 자르는 방식을 따름 - 따라서
q = trunc(a / b)구현이 간단함
Python의 이유:
- 수학적 일관성을 중시
- 나머지가 항상 제수의 부호를 따르며,
0 ≤ r < |d|를 만족 - 반복문, 배열 인덱싱 등에서 더 직관적인 동작을 제공
예:
for i in range(-3, 4):
print(i % 3, end=' ')출력 결과:
0 1 2 0 1 2 05. 모듈러 연산(mod)과의 관계
mod 연산은 수학적으로 다음과 같이 정의된다:
a mod d = a - d * floor(a / d)이 정의는 Python의 % 연산과 일치한다.
C++의 %는 이 정의와 다르게 동작하므로, Python과 동일한 결과를 얻기 위해선 다음과 같이 보정할 수 있다:
int mod(int a, int d) {
int r = a % d;
return r < 0 ? r + abs(d) : r;
}✅ 요약
| 항목 | C++ / Java | Python |
|---|---|---|
| 나눗셈 | 0 기준 내림 (truncate) | 아래 방향 내림 (floor) |
| 나머지 | 피제수 a와 같은 부호 |
제수 d와 같은 부호 |
a = q*d + r 만족 여부 |
✅ | ✅ |
mod 수학적 의미와 일치 |
❌ | ✅ |
반응형
'Study' 카테고리의 다른 글
| Julian Day Number (율리우스 적일) (0) | 2025.05.08 |
|---|
댓글