[EXT-002][입문] 소수점 계산이 어긋나는 이유 알기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[EXT-002][입문] 소수점 계산이 어긋나는 이유 알기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 33회 작성일 26-09-06 23:33

본문

[이번 수업]
`0.1 + 0.1 + 0.1`이 정확히 `0.3`이 아닌 까닭을 이해하고, 금액처럼 십진수 자릿수가 중요한 값을 안전하게 계산합니다. Python 표준 라이브러리만 사용하는 로컬 실습으로 부동소수점과 Decimal의 차이, 반올림 규칙을 확인합니다.

[선수지식]
CORE-002의 2진수와 PY-002의 숫자·문자열을 알면 좋습니다. Python 파일을 만들고 실행할 수 있으면 따라갈 수 있습니다.

[학습목표]
1. 이진 부동소수점에서 일부 소수가 근삿값이 되는 이유를 설명합니다.
2. 금액을 문자열에서 Decimal로 바꾸어 계산합니다.
3. 반올림 자리와 규칙을 코드에 분명하게 기록합니다.

[핵심개념]
부동소수점은 제한된 비트로 매우 크거나 작은 수를 빠르게 표현하는 방식입니다. 컴퓨터가 주로 쓰는 이진 부동소수점에서는 0.5처럼 2의 거듭제곱으로 나뉘는 값은 정확히 표현할 수 있지만 0.1은 유한한 이진수로 끝나지 않습니다. 그래서 가장 가까운 표현 가능한 값을 저장합니다. 이는 특정 언어의 오류가 아니라 표현 방식의 성질입니다.

화면에 `0.3`으로 보여도 내부 값에는 작은 차이가 있을 수 있습니다. 측정·그래픽 계산에서는 허용 오차를 정하고 비교할 수 있지만, 청구 금액이나 세금처럼 자릿수와 반올림 규칙이 계약인 값은 십진 연산이 알맞습니다. Python의 Decimal은 십진수를 정확하게 다루며 정밀도와 반올림 방식을 선택할 수 있습니다.

정밀도는 유효 숫자를 얼마나 유지할지, 스케일은 소수점 아래 자릿수를 몇 자리 둘지 뜻합니다. 반올림은 계산이 끝난 뒤 대충 붙이는 장식이 아닙니다. 어느 단계에서 어떤 규칙으로 반올림하는지에 따라 합계가 달라질 수 있으므로 요구사항으로 정해야 합니다. Python의 `round()`는 정확히 중간인 경우 짝수 쪽을 선택하며, 아래 예제는 일반적인 금액 예시를 위해 `ROUND_HALF_UP`을 명시합니다. 실제 업무에서는 해당 통화·세무·계약 규칙을 확인해야 합니다.

[따라하기]
빈 폴더에 decimal_check.py를 만들고 다음 코드를 저장합니다.

```python
from decimal import Decimal, ROUND_HALF_UP

float_total = 0.1 + 0.1 + 0.1
price = Decimal("19.99")
quantity = 3
tax_rate = Decimal("0.10")

subtotal = price * quantity
tax = (subtotal * tax_rate).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)
total = subtotal + tax

print(f"float: {float_total:.17f}")
print("소계:", subtotal)
print("세금:", tax)
print("합계:", total)
```

macOS와 Linux에서는 `python3 decimal_check.py`, Windows에서는 `py decimal_check.py`로 실행합니다. 예상 결과는 다음과 같습니다.

```text
float: 0.30000000000000004
소계: 59.97
세금: 6.00
합계: 65.97
```

`Decimal("19.99")`처럼 문자열을 전달한 점이 중요합니다. 이미 근삿값이 된 `Decimal(0.1)`을 만들면 그 근삿값을 정확하게 옮기게 됩니다. `quantize(Decimal("0.01"))`는 소수 둘째 자리까지 맞추라는 뜻입니다.

[흔한 실수]
금액을 float로 계산한 뒤 마지막 출력에서만 자릿수를 숨기지 마세요. 항목별 반올림과 총액 반올림은 결과가 다를 수 있으므로 순서를 통일합니다. 서로 다른 통화의 소수 자릿수를 모두 둘로 가정하지 말고, 데이터베이스의 NUMERIC 정밀도와 애플리케이션 규칙도 맞추세요. 과학 계산의 float 비교에는 무조건 `==`를 쓰기보다 허용 오차가 적절한지 검토합니다.

[보안 주의]
금액·수량·비율은 외부 입력을 그대로 믿지 말고 형식, 범위, 최대 자릿수를 서버에서 검사합니다. NaN이나 Infinity처럼 업무 규칙에 없는 값은 거부하고, 클라이언트가 보낸 합계는 서버가 다시 계산하세요. 지나치게 긴 숫자는 자원 소모를 일으킬 수 있으므로 길이 제한도 둡니다. 실습은 본인 소유의 로컬 파일과 고정값으로만 진행합니다.

[직접 해볼 과제]
가격을 `0.05`, 수량을 `3`, 세율을 `0.10`으로 바꾸어 결과를 확인하세요. 그다음 `ROUND_HALF_UP`과 `ROUND_HALF_EVEN`으로 소수 둘째 자리 반올림 결과가 달라지는 입력을 찾아 테스트 두 개로 기록합니다. 음수 수량과 소수 셋째 자리 가격은 거부하도록 검증도 추가하세요.

[확인문제]
1. 이진 부동소수점에서 0.1이 근삿값으로 저장되는 이유는 무엇인가요?
2. `Decimal("0.1")`이 `Decimal(0.1)`보다 금액 계산에 알맞은 이유는 무엇인가요?
3. 반올림 위치와 규칙을 요구사항으로 정해야 하는 이유는 무엇인가요?

[다음 학습]
다음 확장 수업에서는 정규 표현식으로 문자열 형식을 검사하는 법을 배웁니다. 짧고 읽기 쉬운 패턴부터 시작하고 복잡한 입력에서의 성능과 보안도 함께 살펴봅니다.

[공식 참고 자료]
Python 부동소수점 산술 안내
https://docs.python.org/3/tutorial/floatingpoint.html

Python decimal 공식 문서
https://docs.python.org/3/library/decimal.html

Python round 공식 문서
https://docs.python.org/3/library/functions.html#round

RFC 8259 JSON 숫자 형식
https://www.rfc-editor.org/rfc/rfc8259.html

PostgreSQL 숫자 자료형 공식 문서
https://www.postgresql.org/docs/current/datatype-numeric.html

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
837
어제
5,103
최대
16,772
전체
771,891
Copyright © 소유하신 도메인. All rights reserved.