반응형
우리가 수학에서 정수 나눗셈과 나머지(modular) 연산을 다룰 때는, 나머지가 0 이상인 정수이다. 하지만 프로그래밍 언어에서는 이러한 연산이 언어마다 다르게 정의되며, 그 차이는 특히 음수 연산에서 두드러진다. 이로 인해 프로그램이 의도와 다르게 동작할 수 있으므로, 정확한 이해가 필요하다.
1. 사례: C++ vs Python
C++
int a = -5 / 2; // 결과: -2
int b = -5 % 2; // 결과: -1
Python
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 0
5. 모듈러 연산(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 |
---|
댓글