.NET에서 기본적으로 은행가 반올림을 사용하는 이유는 무엇입니까?


271

설명서에 따르면이 decimal.Round방법은 대부분의 응용 프로그램에서 일반적이지 않은 반올림 알고리즘을 사용합니다. 그래서 나는 항상 더 자연스러운 반반 알고리즘을 수행하기 위해 사용자 정의 함수를 작성합니다.

public static decimal RoundHalfUp(this decimal d, int decimals)
{
    if (decimals < 0)
    {
        throw new ArgumentException("The decimals must be non-negative", 
            "decimals");
    }

    decimal multiplier = (decimal)Math.Pow(10, decimals);
    decimal number = d * multiplier;

    if (decimal.Truncate(number) < number)
    {
        number += 0.5m;
    }
    return decimal.Round(number) / multiplier;
}

아무도이 프레임 워크 디자인 결정의 이유를 알고 있습니까?

프레임 워크에 반 반올림 알고리즘을 구현 한 것이 있습니까? 아니면 관리되지 않는 Windows API일까요?

단순히 decimal.Round(2.5m, 0)3을 결과로 쓰지만 대신 2를 얻는 초보자에게는 오해의 소지가 있습니다 .


105
반올림은 "보다 자연스럽지 않습니다". 자연은 그것과 아무 관련이 없습니다. "반올림"개념을 배웠을 때 초등학교에서 배운 것입니다. 초등학교 수업이 항상 전체 그림을 그리는 것은 아닙니다.
Rob Kennedy

45
@Rob 그리고 그것이 그것이 정확 하지 않더라도 더 자연스러운 이유입니다
Pacerier

10
나는 이해하지 못한다, @Pacerier. 그것의 이유를 설명 하지 자연, 그리고 당신이 왜 그 사실에 말할 것입니다 자연. 내 주장 은 내 결론 에 반하는 데 어떻게 작용 합니까? 당신이 익숙해 져 온 것들이 자연스럽게 느껴질 수 있으며, 때로는 우리는 무언가가 "제 2의 본성"이라고 말하지만 자연스럽게 만들지는 않습니다.
Rob Kennedy

16
@Rob 자연 스럽습니다. 자연 스럽습니다. 같은 변수 이름을 가진 36 개의 다른 개체가 자연스럽게 있다는 것을 알고 있습니까?
Pacerier

9
자연은 분명히 아날로그이므로 사용하기에는 잘못된 단어입니다. 그러나 이것은 현란한 것입니다. 어쩌면 사용에 더 나은 단어가 '보통'이 될 것입니다 .. "사람들이 수행하는 것이 보통 라운딩이 무엇인지"> 0.5은 1.0로 이동
whytheq

답변:


196

아마도 더 나은 알고리즘이기 때문일 것입니다. 많은 반올림이 수행되는 동안, 모든 0.5는 반올림 및 반올림됩니다. 예를 들어 둥근 숫자를 더하면 실제 결과를 더 잘 추정 할 수 있습니다. 나는 그것이 어떤 사람들이 기대할 수는 없지만, 아마도 더 올바른 일이라고 말할 것입니다.


71
홀수 및 짝수 입력의 평평한 분포가 있다고 가정하면
jk.

7
+1 더 나은 알고리즘 , Ostemar은 가지고 있지만 실제 대답 ( stackoverflow.com/questions/311696/... )
이안 보이드

2
@Ian, 나는 그 대답에 +1도 준다. 어쨌든 우리는 "허용 된 답을 옮겼다"는 것을 알 수있을 것이다. 이 방법을 사용하는 "이유"에 대한 실제 대답은 페이지의 반쯤입니다. 나는 rep boost를 좋아하지만이 대답에서 일주일에 한 번 정도를 얻습니다.
Kibbee

@ Kibbee-답변을 보내 주셔서 감사합니다. 적합하다고 생각되는대로 수락 된 답변을 변경하는 것이 OP에 달려 있다고 생각합니까?
Ostemar

더 나은 알고리즘임을 알리기 위해 -1입니다. -뱅커의 반올림을 사용하는 임의의 숫자 샘플이 주어지면 홀수 위치보다 짝수 위치에 더 많은 숫자가 생깁니다. -당신이 원래 분포와 비슷한 스프레드를 다시 얻는 숫자를 평균 한 후에야. 그러나 예를 들어이 데이터를 산점도로 플롯하면 인공 그룹화가 표시 될 수 있습니다.
paul23

437

다른 하나는 Banker의 알고리즘 ( 반올림에서 짝수로 )이 좋은 선택 인 이유에 대한 대답입니다 . 대부분의 합리적인 분포 에서 0의 방법을 반올림 하는 것만 큼 음의 또는 양의 바이어스를 겪지 않습니다 .

그러나 문제는 .NET이 Banker의 실제 반올림을 기본값으로 사용하는 이유였습니다. 그 대답은 Microsoft가 IEEE 754 표준을 따랐다는 것입니다. 이것은 MSDN의 Math.Round for Remarks 에도 언급되어 있습니다.

또한 .NET은 MidpointRounding열거 를 제공하여 IEEE에서 지정한 대체 방법을 지원합니다 . 물론 관계를 해결하는 데 더 많은 대안 을 제공 할 수는 있지만 IEEE 표준 만 충족하기로 선택합니다.


17
그렇다면 왜 IEEE 754가 은행가 반올림을 따르는가? 이 (아직 좋은) 대답은 양동이를 통과합니다.
Henk Holterman

4
@HenkHolterman 아마도 다른 답변에서 언급 한 것 (및 요약 한대로); 그것은 부정적이거나 긍정적 인 편견 때문에 (너무 많이) 고통받지 않기 때문에 대부분의 분포와 문제 영역에서 더 공명 할 수 있습니다.
Ostemar


IEEE 754가 Decimal이 아닌 부동 소수점 숫자의 표준이기 때문에 흥미 롭습니다. 아마도 IEEE 754를 따르므로 Double과 Decimal을 반올림하는 데 동일한 알고리즘이 사용됩니다.
Brandon Barkley

1
@BrandonBarkley 10 진수 또는 10 진수 부동 소수점 숫자이며 IEEE 754 에는 10 진수 부동 소수점 숫자 가 포함 됩니다.
Pablo H

88

"Microsoft 디자이너가 왜 이것을 기본으로 선택 했습니까?"라는 질문에 대답 할 수 없지만 추가 기능이 필요하지 않다는 점을 지적하고 싶습니다.

Math.Round당신이 지정할 수 있습니다 MidpointRounding:

  • 짝수-숫자가 다른 두 숫자의 중간에 있으면 가장 가까운 짝수로 반올림됩니다.
  • AwayFromZero-숫자가 다른 두 숫자의 중간에 있으면 0에서 가장 가까운 숫자로 반올림됩니다.

8
그리고 관련 스레드에서 언급했듯이 반올림에서 일관성을 유지하십시오. 때때로 데이터베이스에서 반올림하고 때로는 .net에서 반올림하면 몇 주가 걸리는 이상한 1 센트 오류가 발생합니다 알아 내십시오.
chris mar

59
한 고객이 나에게 40,000 달러 이상을 지불하여 두 개의 숫자 사이에서 0.11 달러의 반올림 오류를 추적했습니다. 0.11 달러는 메인 프레임과 SQL Server의 8 자리 반올림 오류 차이로 인한 것입니다. 완벽 주의자에 대해 이야기하십시오!
EJ 브레넌


12
@EJ Brennan : 알아 내기 위해 4 천 달러가 걸렸나요? 나는 항상 이와 같은 문제를 보았습니다. 반올림은 원인 # 1, 이중 / 부동 정규화는 # 2, 프로그래머 오류 # 3-# 3은 사전 정의 된 테스트 사례가 없으면 즉시 # 1로 설정할 수 있습니다. btw 당신이 나를 당신의 억만 장자 고객과 접촉하게 해줄 수 있습니까? 나는 그의 시스템에서도 40 만 달러 이상의 버그를 발견 할 수 있다고 생각합니다! : D

3
@seanxe : 또는 Office Space를 본 적이 있다면. 진지하게, 돈에 신비 롭고 작은 부정확성이 보일 때마다 그것이 어떻게 일어나는지에 대한 신비를 해결하는 것은 거의 항상 좋은 생각입니다. 버그를 고치지 않기로 결정할 수도 있지만 근본적인 원인을 여전히 알고 있다는 것은 가치가 있습니다. 나는 돈으로 일하는 많은 사람들이 아주 작은 부정확 함을 알게되어 기쁘다 고 확신합니다.
Brian

22

십진법은 주로 돈으로 사용됩니다 . 은행가의 반올림은 돈을 다룰 때 일반적 입니다. 아니면 말할 수 있습니다.

대부분 십진법이 필요한 은행가입니다. 따라서“은행가의 반올림”

은행 반올림은 다음과 같은 경우 평균적으로 동일한 결과를 얻을 수 있다는 이점이 있습니다.

  • "송장 라인"세트를 추가하기 전에 반올림하십시오.
  • 또는 합산 한 다음 합계

추가하기 전에 반올림하면 컴퓨터 이전의 일에 많은 작업이 절약되었습니다.

(영국에서 우리가 10 진수 은행을 갔을 ​​때 반 펜스를 다루지 않았지만 수년 동안 여전히 반 펜스 동전이 있었고 상점은 종종 반 펜스로 끝나는 가격을 가졌습니다. 너무 많은 반올림)


8
"소수는 주로 돈으로 사용됩니다"... 그리고 정수가 아닌 다른 모든 것.
John Tyree

3
@JohnTyree, double / float가 정수가 아닌 경우 대부분의 경우에 해당되지 않습니다. 참조 stackoverflow.com/questions/2545567/...
이안 Ringrose

3
와. 내 우스운 실수. Decmials, 그렇습니다. 소수 후손을 위해, 나는 원래의 정서에 동의합니다.
John Tyree

은행원은 은행원의 반올림을 좋아할 수도 있지만, 장부업자는 팬이 아닐 수도 있지만, 0.005의 차이는 홀수인지 짝수인지에 상관없이 0.01로 반올림해야한다고 말합니다.
JustAMartin

0

다음과 같이 Round 함수의 다른 과부하를 사용하십시오.

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

3 을 출력 합니다. 그리고 당신이 사용하는 경우

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

당신은 은행가의 반올림을 얻을 것입니다.


4
이것은 Banker 's Rounding이 기본으로 선택 되었는지에 대한 질문에는 대답하지 않습니다 .
shortstuffsushi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.