.NET가 Banker의 반올림을 기본값으로 사용하는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/311696

  •  10-07-2019
  •  | 
  •  

문제

문서에 따르면 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를 얻습니다.

도움이 되었습니까?

해결책

아마도 더 나은 알고리즘이기 때문일 것입니다. 많은 반올림이 진행되는 동안, 당신은 평균 .5가 똑같이 위아래로 반올림된다는 평균을 얻을 것입니다. 예를 들어 둥근 숫자를 추가하는 경우 실제 결과를 더 잘 추정합니다. 나는 그것이 어떤 사람들이 기대할 수있는 것이 아니지만 아마도 더 정확한 일이라고 말할 것입니다.

다른 팁

다른 사람은 은행가의 알고리즘 (일명 반쪽에서 짝수) 좋은 선택은 꽤 정확합니다. 그것은 0에서 반쪽으로 떨어져 있습니다 대부분의 합리적인 분포에 대한 방법.

그러나 문제는 .NET가 Banker의 실제 반올림을 기본값으로 사용하는 이유였습니다. 대답은 Microsoft가 IEEE 754 기준. 이것은 또한 언급되어 있습니다 수학을위한 MSDN 발언 아래.

또한 .NET은 IEEE가 지정한 대체 방법을 지원합니다. MidpointRounding 열거. 그들은 물론 제공 할 수있었습니다 더 많은 대안 유대를 해결하기 위해서는 IEEE 표준을 충족하기로 선택합니다.

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

Math.Round a를 지정할 수 있습니다 MidpointRounding:

  • TOEVEN- 숫자가 다른 두 마리 사이의 중간에 있으면 가장 가까운 짝수 숫자로 반올림됩니다.
  • AWAYZERO- 숫자가 다른 두 개 사이의 반쯤되면 0에서 멀리 떨어진 가장 가까운 숫자로 반올림됩니다.

데시 말은 주로 사용됩니다 ; 은행가의 반올림은 함께 일할 때 일반적입니다 . 또는 당신은 말할 수 있습니다.

소수점 유형이 필요한 것은 대부분 은행가입니다. 따라서“은행가의 반올림”을합니다.

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

  • 추가하기 전에“송장 라인”세트를 반올림하고
  • 또는 추가 한 다음 전체를 반올림하십시오

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

(영국에서 우리가 소수점 은행은 절반 펜스를 다루지 않을 것이지만, 수년 동안 여전히 절반의 펜스 코인이 있었고 상점은 종종 반 펜스로 끝나는 가격이 너무 많았습니다. 너무 많은 반올림).

다음과 같은 다른 둥근 기능을 사용하십시오.

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

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

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

은행가의 반올림을 얻을 수 있습니다.

또한 형식 문자열 (예 : "0")을 통한 "Rounding"은 "math.round ()"과 다른 결과를 생성합니다. 즉, 그 5, .5 등은 항상 반올림됩니다.

let d, d' = 2.5, 3.5

Debug.WriteLine(Math.Round(d))      // 2.5 -> 2
Debug.WriteLine(d.ToString("0"))    // 2.5 -> 3

Debug.WriteLine(Math.Round(d'))     // 3.5 -> 4
Debug.WriteLine(d'.ToString("0"))   // 3.5 -> 4


let dd, dd' = 2.25, 2.35

Debug.WriteLine(Math.Round(dd, 1))     // 2.25 -> 2.2
Debug.WriteLine(dd.ToString("0.0"))    // 2.25 -> 2.3

Debug.WriteLine(Math.Round(dd', 1))    // 2.35 -> 2.4
Debug.WriteLine(dd'.ToString("0.0"))   // 2.35 -> 2.4
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top