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

21.11.29 java 코드도 추가함.

1. 파이썬 반올림 문제

A. 문제 1.

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


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


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


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


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


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


2.654
2.655
2.656

a. 소수점 셋 째 자리에서 반올림했을 때.
  • 위에 있는 값임.

2.65
2.65
2.66

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

%precision 55

2.6539999999999999147348717087879776954650878906250000000
2.6549999999999998046007476659724488854408264160156250000
2.6560000000000001385558334732195362448692321777343750000

B. 문제 1-B


2.6254
2.6255
2.6256

a. 소수점 넷 째 자리에서 반올림했을 때.
  • 위에 있는 값임.

2.625
2.626
2.626

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

%precision 55

2.6253999999999999559463503828737884759902954101562500000
2.6255000000000001669775429036235436797142028808593750000
2.6255999999999999339195255743106827139854431152343750000

3. 분석

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

참고로, [Appendix A. 코딩테스트를 위한 파이썬 문법#b 실수형 Real Number]에서 알 수 있듯이.

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

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

4. 이걸 한 이유?

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

이 글이 도움이 되었나요?

신고하기
0분 전
작성된 댓글이 없습니다. 첫 댓글을 달아보세요!
    댓글을 작성하려면 로그인이 필요합니다.