Skip to content

Commit 550e352

Browse files
committed
better way 69 정리
1 parent 258c446 commit 550e352

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,4 @@
100100
[66. 재사용 가능한 try/finally 동작을 원한다면 contextlib 과 with 문을 사용하라](./summary/BetterWay66.md)
101101
[67. 지역 시간에는 time 보다는 datetime 을 사용하라](./summary/BetterWay67.md)
102102
[68. copyreg 를 사용해 pickle을 더 신뢰성 있게 만들라](./summary/BetterWay68.md)
103+
[69. 정확도가 매우 중요한 경우에는 decimal 을 사용하라](./summary/BetterWay69.md)

summary/BetterWay69.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# 69. 정확도가 매우 중요한 경우에는 decimal 을 사용하라
2+
3+
## 1. 부동소수점
4+
5+
- 2배 정밀도 부동소수점 타입은 IEEE 754 표준을 따름
6+
- 파이선은 허수 값을 포함하는 표준 복소수 타입 제공
7+
8+
- 국제 전화 고객에게 부과할 통화료를 계산 가정
9+
- 고객이 통화한 시간을 분, 초 단위로 알고 있으며 미국과 남극 사이의 도수(분)당 통화료가 1.45달러/분 이라 가정
10+
11+
```python
12+
rate = 1.45
13+
seconds = 3*60 + 42
14+
cost = rate * seconds / 60
15+
print(cost)
16+
17+
>>>
18+
5.364999999999999
19+
```
20+
21+
```python
22+
print(round(cost, 2))
23+
24+
>>>
25+
5.36
26+
```
27+
28+
- IEEE 754 부동소수점 수의 내부(이진) 표현법으로 인해 결과는 5.365보다 0.00000000000001 만큼 작음
29+
- 부동소수점 수의 오류로 인해 이 값을 가장 가까운 센트 단위로 반올림하면 최종 요금이 늘어나지 않고 줄어들게 됨
30+
31+
32+
## 2. `decimal` 내장 모듈
33+
34+
- `decimal` 내장 모듈에 있는 `Decimal` 클래스 사용
35+
- `Decimal` 클래스는 기본값으로 소수점 이하 28번째 자리까지 고정소수점 수 연산 제공
36+
- 자리수 늘리기 가능
37+
38+
```python
39+
from decimal import Decimal
40+
41+
rate = Decimal('1.45')
42+
seconds = Decimal(3*60 + 42)
43+
cost = rate * seconds / Decimal(60)
44+
print(cost)
45+
46+
>>>
47+
5.365
48+
```
49+
50+
- `Decimal` 클래스를 사용하여 근사치가 아닌 정확한 값 표현 가능
51+
- `Decimal` 인스턴스에 값을 지정하는 방법
52+
- 숫자가 들어있는 str 타입 문자열을 `Decimal` 생성자에 전달
53+
- 파이선 부동소수점 수의 근본적인 특성으로 인해 발생하는 정밀도 손실을 막을 수 있음
54+
- int나 float 타입 인스턴스를 `Decimal` 생성자에 전달
55+
- 정수를 넘기는 경우 문제 안됨
56+
57+
- 정확한 답을 요구하는 경우 문자열로 전달하는 것이 중요
58+
59+
```python
60+
print(Decimal('1.45'))
61+
print(Decimal(1.45))
62+
63+
>>>
64+
1.45
65+
1.4499999999999999555910790149937383830547332763671875
66+
```
67+
68+
69+
- 연결 비용이 훨씬 저렴한 지역 사이의 아주 짧은 통화도 지원하고 싳은 경우
70+
- 통화 시간 5초, 통화료 0.05
71+
- 계산한 값이 너무 작아 0 이 나옴
72+
73+
```python
74+
rate = Decimal('0.05')
75+
seconds = Decimal('5')
76+
small_cost = rate * seconds / Decimal(60)
77+
print(small_cost)
78+
79+
>>>
80+
0.004166666666666666666666666667
81+
```
82+
83+
```python
84+
print(round(small_cost, 2))
85+
86+
>>>
87+
0.00
88+
```
89+
90+
- `Decimal` 클래스의 원하는 소수점 이하 자리까지 원하는 방식으로 근삿값 계산 내장 함수 사용
91+
- 반올림 방식 사용
92+
93+
```python
94+
from decimal import ROUND_UP
95+
rounded = cost.quantize(Decimal('0.01'), rounding=ROUND_UP)
96+
print(f'반올림 전: {cost} 반올림 후: {rounded}')
97+
98+
>>>
99+
반올림 전: 5.365 반올림 후: 5.37
100+
```
101+
102+
```python
103+
rounded = small_cost.quantize(Decimal('0.01'),
104+
rounding=ROUND_UP)
105+
print(f'반올림 전: {small_cost} 반올림 후: {rounded}')
106+
107+
>>>
108+
반올림 전: 0.004166666666666666666666666667 반올림 후: 0.01
109+
```
110+
111+
## 3. 정리
112+
113+
- `Decimal` 은 고정소수점 표현에 대해서 잘 작동함
114+
- 여전히 정밀도에 한계는 존재
115+
- 정밀도 제한 없이 유리수를 사용하고 싶은 경우 `fractions` 내장 모듈의 `Fraction` 클래스 사용할 것

0 commit comments

Comments
 (0)