Banker’s Rounding – 은행원 방식 반올림

아실지 모르겠지만 반올림은 여러가지 처리 방식이 있습니다.

이 차이를 모르면 소숫점이 있는 수치 계산을 하다가 반올림 처리 방식의 차이로 인해 오차가 생겼다고 생각하고 정합성을 맞추려다 헤메는 경우가 있을 수 있습니다.

제가 학생이던 시절에 금전 계산을 자동으로 복잡하게 하는 정산 소프트웨어를 의뢰받아 만든 적이 있었는데, 의뢰인이 제시해준 계산 방법과 확인용 정산 출력물을 기반으로 계산 소프트웨어를 작성하는 흐름으로 진행했었습니다. 단위 계산이 조금 복잡했고 반복 계산을 한 뒤에 복잡하게 역산하는 것을 한 뒤에 총 결과를 산출하는 것이었습니다. (요즘으로 치면 최적화 비슷한 것입니다만)

그런데 만들 때 적은 양의 데이터로 단위 계산을 몇 개 실험해서 해본 뒤에 나온 결과를 보고 정확하게 계산되었는지를 정확하게 확인했고 문제가 없었습니다, 그 후에 전체 계산을 수행하는 것을 진행해서 총합을 확인해보니 정답지와 결과값이 미세하게 달랐습니다. 다시 단위 계산을 몇개 임의로 선택해서 결과가 어떻게 다른지 점검해 봤는데 몇개가 다르게 나온다는 것을 알았습니다. 이 문제의 원인을 찾느라 시간을 쓸데없이 허비한 적이 있습니다.

원인은 제가 사용하던 컴퓨터 랭귀지에서 제공하는 round 함수가 사사오입이 아닌 뱅커스 라운딩(Bankers’ rounding)을 채택했기 때문에 발생한 문제였고 round 함수를 사사오입 방식의 다른 round로 변경해서 해결했었습니다. 그 뒤로는 round를 하게될 일이 있으면 반드시 사용하는 소프트웨어의 round가 사사오입 방식인지 뱅커스 라운딩인지 확인을 하고 작업을 시작하는 습관이 있습니다. 그게 아니면 오차가 좀 크더라도 정합성을 위해서 무조건 소숫점이하는 절사 시켜버리곤 했습니다. 물론 요즘은 이것마저도 잘 하지 않는 늙은이가 되었습니다만.

어쨌든 당시에는 컴퓨터 랭귀지의 기본 함수에 버그가 있는 줄 알고 리포트를 하려고 했었으나 매뉴얼을 먼저 찾아보니 천절하게 설명을 해 두었더군요. 그리고 관련 자료를 더 찾아보고는 제가 무식했다는 사실을 알았습니다.

“세상에 반올림 방법은 딱 하나 인 줄 만 알았어” 라고 생각했습니다. 배운 것이 그것뿐이라서

앞서 말씀드린 것 처럼 반올림은 여러가지 방식이 있습니다. 꽤 많은 방식들이 있습니다만 우리가 흔히 접할 수 있는 것은 위에서 말한 2가지인 사사오입과 뱅커스 라운딩입니다.
이 포스트에서 그 차이를 간단하게 설명하겠습니다.

사사오입( 四捨五入 ) 반올림

우선, 흔히 아는 반올림은 사사오입(四捨五入, Normal rounding)인데 4는 버림, 5는 올림을 뜻합니다. 보통은 우리는 그냥 “반올림”이라고 하지만 명확환 구분과 설명을 위해서 “사사오입”이라고 하겠습니다.
사사오입 방식은 영어로는 Round, away from zero (0에서 멀어지는) 라고 합니다.
사사오입으로 소숫점이 있는 숫자들을 정수로 반올림한다고 하면 다음과 같이 되는 것입니다.

0.4 반올림 하면 0
0.5 반올림 하면 1
0.6 반올림 하면 1
1.4 반올림 하면 1
1.5 반올림 하면 2
1.6 반올림 하면 2
2.4 반올림 하면 2
2.5 반올림 하면 3
2.6 반올림 하면 3

뱅커스 라운딩

뱅커스 라운딩 올려질 값이 5인 경우에 만들어질 수의 끝이 짝수가 되도록(짝수에 수렴) 하는 방식입니다.

영어의 다른 표현으로는 Round, half to even (절반을 짝수쪽으로)라고 합니다. 금융권에서 많이 채택해서 쓰기 때문에 뱅커스 라운딩이라는 별칭으로 많이 불립니다. 미국의 경우이고 한국 금융권에서도 이것을 채택해서 쓰는지는 모르겠습니다.
어쨌든 다음과 같이 계산 됩니다. 굵은 글씨 부분을 자세히 보세요.

0.4 반올림 하면 0
0.5 반올림 하면 0
0.6 반올림 하면 1
1.4 반올림 하면 1
1.5 반올림 하면 2
1.6 반올림 하면 2
2.4 반올림 하면 2
2.5 반올림 하면 2
2.6 반올림 하면 3
2.45 반올림 하면 2

둘을 비교 해보면 이렇습니다.

대상값 / 방식사사오입뱅커스 라운딩
0.400
0.510
1.411
1.522
1.622
2.422
2.532
2.633
4.554
4.444554

뱅커스 라운딩은 미국 측정 계산의 표준이라고 알려져 있습니다. 직접 물어봐서 확인해 보지 않았지만 온라인 문서에 그렇게 적혀 있습니다. 그래서 최신의 컴퓨터 언어나 계산 관련 소프트웨어들에서 기본으로 지원하는 반올림 함수는 우리가 아는 사사오입 방식이 아닌 뱅커스 라운딩을 사용하는 것이 많습니다. 소프트웨어들이 여전히 미국산이 많기 때문인데 특히 과학계산 용도로 쓰는 것들이 그렇습니다.

반올림?

사사오입은 엄밀히 말하면 반올림이 아닙니다. 우리가 쓰는 반올림은 흔히 round라고 표현하는데 영어로 round라고 하는 것은 숫자를 단순하게 만드는 것을 말합니다.

round 는 둥글게 둥글게, 심플하게 심플하게, 밋밋하게, 밋밋하게,

예를 들면 “무조건 올림”은 영어로 round-up이라고 하고 “무조건 내림”은 영어로 round-down이라고 합니다. round라는 단어가 들어 있지만 “무조건 내림”과 “무조건 올림”은 반올림이 아닙니다. 그냥 올리고 내리는 것이지요.

그리고 사사오입 반올림의 영문 표현이 away from zero인데 뜻을 보면 5를 0에서 멀어지게 하는 것이라서 반올림이라고 표현하는 것에 무리가 있다고 합니다. 반면 half to even 방식은 짝수방향으로 반을 올려주거나 절사하기 때문에 이것이 진짜 반올림 방식 중 하나입니다.

하지만 이미 관행으로 다들 사사오입도 반올림이라고 말하기 때문에 편의상 여기에서도 모두 합쳐서 다 “반올림”이라고 하겠습니다.

뱅커스 라운딩을 사용하는 이유

당연히 계산과정에서 반올림 때문에 발생하는 오차를 줄이기 위해서 고안된 것입니다. 반복계산을 하면서 반올림이 계속 반복되면 결국 오차를 만들게 되는데 최종 결과가 이 반올림에 의한 오차를 줄이도록 하려는 것입니다.

숫자 0과 1이 있습니다. 이 사이에 존재하는 소숫점 첫째자리까지의 수만 보면 다음과 같이 9개가 숫자가 있습니다. 10개가 아닙니다.

0.10.20.30.40.50.60.70.80.9

이 숫자들을 다 반올림한다고 할 때 0.5는 정확하게 한가운데 있기 때문에 절사해서 버릴 것인지 1로 올려줄 것인지가 고민이 됩니다. 그리고 어느쪽으로 하든 오차를 만듭니다. 사사오입 방식은 5를 항상 위로 올리기 때문(away from zero)에 여기서 숫자가 원래 올리지 않았을 때 보다 오차가 커지는 일이 많아집니다. 그리고 잘 생각해 보면 어딘가 공평하지 않은 구석이 있다는 것을 느낄 수 있습니다.

대신 뱅커스 라운딩처럼 짝수쪽으로 수렴하게 해서 조금은 더 공평해집니다. 그리고 이 방식이 오차가 덜 발생한다는 것은 오래전에 여러가지 방법과 실험을 통해 증명되었다고 합니다.

그외의 반올림 방식

위키피디아의 rounding 페이지를 보면 반올림(rounding)방식이 상당히 많다는 것을 보고 놀랄 수 있습니다. 반올림 문제는 메소포타미아에도 기록이 남아 있는 오래된 문제라고 되어 있습니다. 그리고 뱅커스 라운딩이라고 불리는 half to even 방식은 1940년도 나온 것이라고 적혀 있습니다. 오래되었죠.

위키피디아: https://en.wikipedia.org/wiki/Rounding

반올림 비교표

너무 많은 round를 알 필요는 없겠지만 대략 아래와 같은 것이 있습니다.

round 함수의 방식 차이로 인한 정합성 문제

뱅커스 라운딩을 기본으로 채택해서 제공하는 컴퓨터 언어나 소프트웨어가 생각보다 좀 많습니다.

R, Python3과 같은 것들이 그렇습니다. 그 외의 랭귀지도 꽤 많습니다. Excel과 RDBMS 같은 소프트웨어의 반올림 함수는 대부분 우리가 아는 “사사오입”으로 되어 있습니다. 그러다보니 행수가 많은 데이터에서 나누기, 곱하기 같은 것들이 여러번 반복하고 그 결과를 모두 합한다거나 평균을 구한다거나 하면 동일한 데이터를 가지고 계산을 해도 사용하는 컴퓨터 언어나 툴에 따라 양쪽의 결과값에 미묘한 차이가 발생합니다.

즉, round함수의 방식이 다른 것을 각각 따로 어떤 데이터의 사칙 연산을 하면서 반올림이 섞인 계산을 반복하는 경우에는 양쪽에서 똑같이 계산해도 round의 방식으로 인해 서로 결과값이 안맞는 문제가 발생합니다.
이때 정합성 오류가 부동소숫점 연산 문제나 반올림 방식의 차이로 인한 문제라는 것을 알면 그것은 해결하기도 어렵고 원인을 알면 오차를 감수하고 넘어갈 수도 있지만, 그것을 모르면 오차가 어디서 발생했는지 원인를 찾기 위해서 시간을 허비하게 됩니다.

버그인지 계산을 잘못한 것인지…

그래서 차이가 있다는 것을 알고 있는 것이 좋습니다.
물론 뱅커스 라운딩을 기본으로 채택한 것들은 별도로 사사오입을 지원하는 함수를 따로 제공하는 것이 많습니다. (아닌 것도 있는데 그럴 때는 구현해야 합니다)

컴퓨터 언어, 소프트웨어의 기본 반올림 방식

직접 몇 개를 확인해 봤습니다. 결과는 아래 테이블에 있습니다.

언어/소프트웨어방식
Linux shell (printf)뱅커스 라운딩
R뱅커스 라운딩
Python2사사오입
Python3뱅커스 라운딩
C/C++사사오입
Object-C사사오입
C#뱅커스 라운딩
Visual Basic뱅커스 라운딩
Go사사오입
Ruby사사오입
Scala사사오입
PHP사사오입
Julia뱅커스 라운딩
Javascript사사오입
Java사사오입
Erlang사사오입
Pascal뱅커스 라운딩
Cobol뱅커스 라운딩 (기본으로 되어 있습니다. 변경 가능해요)
Fortran사사오입
Excel사사오입
Google Spread Sheet사사오입
MySQL사사오입
Hive사사오입
Redshift (PostgreSQL?)사사오입
BigQuery사사오입
Oracle사사오입
SQLite사사오입
Matlab사사오입
Mathematica뱅커스 라운딩
WolframAlpha뱅커스 라운딩 (매쓰메티카와 같은 언어를 쓰므로)
Tableau사사오입 (시각화 도구는 역시 짤 없습니다)

정리하면

  • Linux에 있는 printf뱅커스 라운딩 (리눅스 코맨드마다 다를 수도 있겠지만 이것만 확인했어요)
  • Java 계열사사오입
  • 닷넷(.net) 계열뱅커스 라운딩 (.net이 아닌 MFC를 확인 안해봤습니다. 귀찮아요)
  • 데이터에 중점을 둔 것들은 사사오입
  • 과학, 공학에 중점을 둔 것은 뱅커스 라운딩
  • 함수형 언어뱅커스 라운딩
  • 시스템 개발에 중점을 둔 언어는 사사오입
  • Python은 2에서 3으로 바뀔 때 뱅커스 라운딩을 기본으로 바꿈
  • 시각화 도구는 DB에서 데이터를 끌어와서 표현하는 일이 많기 때문에 DB와 같은 방식을 사용

그리고 매우 오래전부터 사용해온 소프트웨어들은 일관성과 변경한 후 달라질 정합성으로 인해 별도로 뱅커스 라운딩 함수를 사용할 수 있게 제공하고 기본 함수의 방식을 바꾸지는 않는 것 같습니다.

하지만 뱅커스 라운딩이 더 권고되는 표준이기 때문에 새로 만들어지는 것들은 뱅커스 라운딩을 지원해야 한다고 하는 사람이 많습니다.

데이터베이스의 경우에는 잘 쓰고 있는데 어느날 업그레이드를 하고 나서 계산값이 달라지거나 합계를 했는데 총합이 달라지거나 하게 되면 문제가 커질 수도 있을 것입니다.

반올림의 인해 엄청난 문제가 발생하는 경우는 일상 생활에 별로 없겠습니다. 하지만 수능점수같은 것은 반올림 문제로 학생의 인생이 바뀔 수도 있어서 매우 골치가 아플것 같습니다. 작은 차이가 큰 문제를 만드는 경우도 있습니다.

뭘 하시든지 정밀한 수치 확인이 필요한 작업을 혹시 하게 되는 경우를 위해서 알아두시면 좋을 것 같습니다.

댓글 남기기