반응형
머리말
Baekjoon 13705번 문제(( Ax + B \sin(x) = C ))를 풀 때,
처음에는 Python 내장 math.sin()을 사용했지만 '틀렸습니다'가 발생했다.
왜 그럴까?
이 글에서는
- math.sin()을 사용한 기존 코드
- Decimal + 직접 테일러 전개로 구현한 정답 코드
를 비교하고,
왜 Decimal + 테일러 전개가 필요한지 쉽게 설명한다.
1. 기존 코드 (math.sin 사용)
import sys
import math
input = sys.stdin.readline
a, b, c = map(int, input().split())
l = (c - b) / a
r = (c + b) / a
for _ in range(80):
m = (l + r) / 2
V = a * m + b * math.sin(m)
if V < c:
l = m
else:
r = m
U = 1_000_000
D = 0.5
result = (U * r + D) // U / 1_000_000
print(f"{result:.6f}")
결과: Colab에서는 통과, Baekjoon에서는 '틀렸습니다'
2. 정답 코드 (Decimal + sin 직접 구현)
import sys
from decimal import Decimal, getcontext
input = sys.stdin.readline
getcontext().prec = 50 # Decimal 정밀도 설정
def sin(x):
PI2 = Decimal('6.283185307179586476925286766559')
x %= PI2
res = x
term = x
sign = -1
for d in range(2, 30, 2):
term = term * x * x / (d * (d + 1))
res += sign * term
sign *= -1
return res
a, b, c = map(int, input().split())
a = Decimal(a)
b = Decimal(b)
c = Decimal(c)
l = (c - b) / a
r = (c + b) / a
for _ in range(80):
m = (l + r) / 2
V = a * m + b * sin(m)
if V < c:
l = m
else:
r = m
U = Decimal('1000000')
D = Decimal('0.5')
ans = (U * r + D) // 1 / U
print(f"{ans:.6f}")
결과: Baekjoon에서도 '맞았습니다' 통과
3. 왜 math.sin()은 안 되는가?
(1) math.sin()은 float64 기반
- Python의 math.sin(x)는 float64 (소수점 15자리 정도) 정확도를 가진다.
- 그런데 문제는, (A \times x + B \times \sin(x)) 계산 결과가
소수점 6자리 반올림 기준에서 아주 미세하게 차이날 수 있다는 것!
(예: 19.44178699999... vs 19.44178700000...)
- 이 미세한 오차가 Baekjoon 채점기에서는 '틀렸습니다'가 된다.
(2) 해결: Decimal + 직접 테일러 전개
- Python의 Decimal 모듈은 원하는 만큼 정밀도를 설정할 수 있다.
- 직접 테일러 전개를 하면
- 정밀하게 (\sin(x)) 값을 계산할 수 있고
- 문제 출제자 채점 기준과 일치할 수 있다.
4. 추가 주의사항
- Decimal에서도 sin(x)는 직접 구현해야 한다 (math.sin 사용 금지)
- 고정소수점 반올림도 수동으로 처리해야 한다
ans = (U * r + D) // 1 / U
- 이진탐색은 80회 반복이면 충분하다
5. 마무리 정리
항목 | 기존 코드 | 수정한 코드 |
---|---|---|
실수 처리 방식 | float64 (math.sin) | Decimal 50자리 |
sin 계산 방식 | math.sin 사용 | 테일러 전개 직접 구현 |
오차 발생 여부 | 있을 수 있음 | 거의 없음 |
최종 결과 | 틀렸습니다 | 맞았습니다 |
✅ 결론
Python으로 부동소수점 정확한 계산이 필요할 때는 Decimal을 사용해야 한다.
특히 sin / cos / tan 계산은 직접 구현해야 오차를 제어할 수 있다.
✨ 앞으로 부동소수점 문제에서는 Decimal + 테일러 전개를 기억하자!
반응형
'Algorithm > 백준' 카테고리의 다른 글
[백준 / 2143 / Python] 두 배열의 합 (0) | 2025.06.13 |
---|---|
[백준 / 27172 / Python] 수 나누기 게임 (0) | 2025.06.13 |
[백준 / 1647 / Python] 도시 분할 계획 (0) | 2025.06.10 |
[백준 / 27440 / Python] 1 만들기 (0) | 2025.05.30 |
[백준 / 2166 / Python] 다각형의 면적 (0) | 2025.05.28 |