# 파이썬 반올림 부동소수점 오차에 대해 알아보자.

- Author: @mildsalmon
- Published: 2021-08-04
- Updated: 2021-11-29
- Source: http://blex.me/@mildsalmon/2021-8-4-%EC%98%A4%ED%9B%84-64434
- Tags: 파이썬, 문제, 자료형, 버그, 실수형, 부동소수점, 해결

---

> 21.11.29 java 코드도 추가함.

# 1. 파이썬 반올림 문제

### A. 문제 1.

> python

```python

print(round(2.650, 2))
print(round(2.651, 2))
print(round(2.652, 2))
print(round(2.653, 2))
print(round(2.654, 2))
print(round(2.655, 2))
print(round(2.656, 2))
print(round(2.657, 2))
print(round(2.658, 2))
print(round(2.659, 2))

```

```

2.65
2.65
2.65
2.65
2.65
2.65
2.66
2.66
2.66
2.66

```

> java

```java

System.out.println(Math.round(2.650 * 100)/100.0);
System.out.println(Math.round(2.651 * 100)/100.0);
System.out.println(Math.round(2.652 * 100)/100.0);
System.out.println(Math.round(2.653 * 100)/100.0);
System.out.println(Math.round(2.654 * 100)/100.0);
System.out.println(Math.round(2.655 * 100)/100.0);
System.out.println(Math.round(2.656 * 100)/100.0);
System.out.println(Math.round(2.657 * 100)/100.0);
System.out.println(Math.round(2.658 * 100)/100.0);
System.out.println(Math.round(2.659 * 100)/100.0);

```

```

2.65
2.65
2.65
2.65
2.65
2.66
2.66
2.66
2.66
2.66

```

> python

```python

print(round(2.6250, 3))
print(round(2.6251, 3))
print(round(2.6252, 3))
print(round(2.6253, 3))
print(round(2.6254, 3))
print(round(2.6255, 3))
print(round(2.6256, 3))
print(round(2.6257, 3))
print(round(2.6258, 3))
print(round(2.6259, 3))

```

```

2.625
2.625
2.625
2.625
2.625
2.626
2.626
2.626
2.626
2.626

```

> java

```java

System.out.println(Math.round(2.6250 * 1000)/1000.0);
System.out.println(Math.round(2.6251 * 1000)/1000.0);
System.out.println(Math.round(2.6252 * 1000)/1000.0);
System.out.println(Math.round(2.6253 * 1000)/1000.0);
System.out.println(Math.round(2.6254 * 1000)/1000.0);
System.out.println(Math.round(2.6255 * 1000)/1000.0);
System.out.println(Math.round(2.6256 * 1000)/1000.0);
System.out.println(Math.round(2.6257 * 1000)/1000.0);
System.out.println(Math.round(2.6258 * 1000)/1000.0);
System.out.println(Math.round(2.6259 * 1000)/1000.0);

```

```

2.625
2.625
2.625
2.625
2.625
2.626
2.626
2.626
2.626
2.626

```

보통 반올림 하면 떠오르는게 5 이상은 올림, 미만은 내림으로 떠올린다.

그런데 파이썬으로 간단하게 돌려보니 예상과는 달랐다. 첫 번째 코드는 5일 때 내림을 두 번째 코드는 5일 때 올림을 하고 있다.

> 수학적으로 말하자면 **최소 단위로 나눈 나머지가 최소 단위의 절반에 미치지 못하는 경우 버리고, 초과하는 경우는 올리는 방법**이다.

위키를 찾아보니 위 처럼 나왔다. 5 미만, 5 초과에는 5가 포함되어 있지 않았다. 과연 언제 올림을 하는 것이고 언제 내림을 하는 것일까? 수십개의 예제를 돌려봤지만 잘 모르겠다.

### B. 문제 2.

> python

```python

print(round(2.605, 2))
print(round(2.615, 2))
print(round(2.625, 2))
print(round(2.635, 2))
print(round(2.645, 2))
print(round(2.655, 2))
print(round(2.665, 2))
print(round(2.675, 2))
print(round(2.685, 2))
print(round(2.695, 2))

```

```

2.6
2.62
2.62
2.63
2.65
2.65
2.67
2.67
2.69
2.69

```

> java

```java

System.out.println(Math.round(2.605 * 100)/100.0);
System.out.println(Math.round(2.615 * 100)/100.0);
System.out.println(Math.round(2.625 * 100)/100.0);
System.out.println(Math.round(2.635 * 100)/100.0);
System.out.println(Math.round(2.645 * 100)/100.0);
System.out.println(Math.round(2.655 * 100)/100.0);
System.out.println(Math.round(2.665 * 100)/100.0);
System.out.println(Math.round(2.675 * 100)/100.0);
System.out.println(Math.round(2.685 * 100)/100.0);
System.out.println(Math.round(2.695 * 100)/100.0);

```

```

2.61
2.62
2.63
2.64
2.65
2.66
2.67
2.68
2.69
2.7

```

이런 것도 있다. 반올림하는 자리인 셋째 자리에는 전부 5인데, 누구는 올림을 하고 누구는 내림을 한다. 왜 이런 차이가 나는 걸까?

# 2. 부동소수점 확인

### A. 문제 1-A

```python

2.654
2.655
2.656

```

##### a. 소수점 셋 째 자리에서 반올림했을 때.

- 위에 있는 값임.

```python

2.65
2.65
2.66

```

##### b. 소수점 55자리까지 표현.

```python

%precision 55

2.6539999999999999147348717087879776954650878906250000000
2.6549999999999998046007476659724488854408264160156250000
2.6560000000000001385558334732195362448692321777343750000

```

### B. 문제 1-B

```python

2.6254
2.6255
2.6256

```

##### a. 소수점 넷 째 자리에서 반올림했을 때.

- 위에 있는 값임.

```python

2.625
2.626
2.626

```

##### b. 소수점 55자리까지 표현.

```python

%precision 55

2.6253999999999999559463503828737884759902954101562500000
2.6255000000000001669775429036235436797142028808593750000
2.6255999999999999339195255743106827139854431152343750000

```

# 3. 분석

소수점 55자리까지 표현해보면 5 초과 올림, 5 미만 내림이 무슨 의미인지 쉽게 이해할 수 있다.

참고로, [[Appendix A. 코딩테스트를 위한 파이썬 문법#b 실수형 Real Number]](https://blex.me/@mildsalmon/chap-1-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EC%9A%94)에서 알 수 있듯이. 

> 실수를 처리할 때 부동 소수점(Floating-point) 방식을 이용한다. IEEE754 표준에서는 실수형을 저장하기 위해 4바이트 OR 8바이트라는 고정된 크기의 메모리를 할당한다. 그래서 현대 컴퓨터 시스템은 실수 정보를 표현하는 정확도에 한계를 가진다.

실수를 표현하는 방식의 문제라고 생각하면 될 것 같다.

# 4. 이걸 한 이유?

누군가는 사사오입이라면서 반올림하는 자릿수 앞에가 짝수면 버리고 홀수는 올림이라고 말한다. 나도 그걸 보고 그냥 그런줄 알았다. 그런데 아무리 봐도 반올림하는 자릿수 앞이 짝수인데 버리고 홀수인데 올리는 경우가 있더라. 그래서 더 찾아봤더니, 소수점 표기하는 과정에서 정확도 한계라는 결론을 얻었다. 뭐든지 그냥 읽고 믿으면 안되는 것 같다. 해보고 맞는지 검증하는건 내 몫인 것 같다.
