수업 필기를 복습하면서 floor와 ceil의 결과가 반대로 기록된 부분을 발견했다. 공식 문서의 정의를 기준으로 내용을 바로잡고, 양수뿐 아니라 음수와 반올림 경계값까지 비교해 정리한다.
math.floor(x)는 x 이하인 정수 중 가장 큰 값을, math.ceil(x)는 x 이상인 정수 중 가장 작은 값을 반환한다. 단순히 소수점을 버리거나 올린다고 외우기보다, 입력값과 반환값의 대소 관계로 이해해야 음수에서도 혼동하지 않는다.
import math
print(math.floor(1.5)) # 1
print(math.ceil(1.5)) # 2
print(math.floor(-1.5)) # -2
print(math.ceil(-1.5)) # -1
-2 < -1.5 < -1이므로 floor(-1.5)는 -2, ceil(-1.5)는 -1이다. 입력값이 이미 정수라면 두 함수 모두 그 정숫값을 반환한다.
실수를 int()로 변환하면 소수 부분이 제거된다. 처리 방향은 음의 무한대가 아니라 0이다.
| 입력값 | floor | ceil | int |
|---|---|---|---|
| 1.5 | 1 | 2 | 1 |
| -1.5 | -2 | -1 | -1 |
양수 예제만 보면 floor와 int를 같은 연산으로 오해하기 쉽다. 그러나 음수에서 결과가 달라지므로, 문제에서 수학적 내림을 요구한다면 int()로 대체해서는 안 된다.
round()는 가장 가까운 값으로 반올림한다. ndigits를 생략해 정수로 반올림할 때, 두 정수까지의 거리가 정확히 같으면 짝수를 선택한다.
print(round(1.5)) # 2
print(round(2.5)) # 2
print(round(3.5)) # 4
print(round(4.5)) # 4
print(round(2.6)) # 3
짝수를 선택하는 규칙은 정확한 중간값에만 적용된다. 2.6은 2보다 3에 가깝기 때문에 3으로 반올림된다. 따라서 ‘정수 부분이 짝수이면 내림한다’는 설명은 정확하지 않다.
print(round(2.675, 2)) # 2.67
십진수 표기만 보면 2.68을 예상할 수 있지만, 이 값은 이진 부동소수점으로 정확하게 표현되지 않는다. 실제 저장된 근삿값에 반올림 규칙이 적용되므로 결과가 2.67이 된다. 공식 문서에서도 같은 예제를 설명한다.
반올림 결과를 해석할 때는 함수의 규칙과 숫자의 내부 표현을 함께 확인해야 한다.
| 목적 | 함수 | 확인할 조건 |
|---|---|---|
| 입력값 이하의 가장 큰 정수 | math.floor | 음수에서도 작은 방향 |
| 입력값 이상의 가장 작은 정수 | math.ceil | 음수에서도 큰 방향 |
| 실수의 소수 부분 제거 | int | 0에 가까운 방향 |
| 가장 가까운 값으로 반올림 | round | 중간값 규칙과 부동소수점 오차 |
함수를 선택할 때는 이름보다 필요한 연산의 정의를 먼저 확인한다. 양수 하나로 판단하지 않고 음수, 정수, 정확한 중간값을 함께 비교하는 것이 이번 복습의 핵심이다.