.NET 할 줄 아는 애들은 지금 당장


Console.WriteLine(Math.Round(2.5));


찍어 봐라. 3이 나올 거라고 예상했겠지만 2가 출력된다.

부동 소수점 관련해서 오차 때문에 발생한 버그라고 생각하는가?

그렇다면 고정 소수점 방식인 Decimal을 이용해서 아래와 같이 해 보자.


Console.WriteLine(Math.Round(2.5D));


여전히 마찬가지로 2가 출력된다.

그렇다면 Math.Round() 함수에 버그가 있는 것일까?

아니다. .NET의 Math.Round() 함수는 사사오입(四死五入)으로 흔히 표현되는,

우리가 익히 알고 써왔던 표준 반올림(Standard Rounding)이 아니라

은행원의 반올림(Banker's Rounding)이라는 것을 수행해서 이런 결과가 나온 것이다.


일반적인 반올림은 통계학적으로 이런 불공평한 점이 존재한다.


예를 들어 0부터 1 사이의 0.1 간격의 소수 0.1, 0.2, 0.3, 0.4, ..., 0.8, 0.9 이렇게 9개를 나열해 보자.

그러면 여기서 0.1부터 0.4까지 4개가 0이 되는 반면 0.5부터 0.9까지 5개나 1이 되어 버린다.

즉, 내림되는 수보다 올림되는 수가 하나 더 많은 것이다.


은행원의 반올림 알고리즘은 이런 불공평을 해결하기 위해 고안된 것인데,

소수점 이하의 수가 정확히 .5로 중간일 때, 가장 가까운 짝수 정수로 반올림하는 것이다.

이렇게 할 경우 0부터 2까지의 소수 18개를 나열했을 때, 내림되는 수와 올림되는 수가 9개씩 골고루 분배되므로

통계적으로 한 쪽에 편향되지 않는 결과가 된다.


필자가 아는 바로는 Visual Basic 6, MS Office VBA, .NET 플랫폼의 반올림 함수가 모두 은행원의 반올림 알고리즘을 쓰는 걸로

알고 있는데, 혹시 다른 언어에서도 은행원의 반올림 알고리즘을 쓰는 예를 알고 있다면 필자에게 알려 줘라.