2014-08-27 5 views
1

C#에서 반올림 문제가 발생했습니다. 나는 소수점 이하 4 자리까지 계산 결과를 반올림하고 싶습니다. Math.Round (변수, ...)를 사용하면 수동으로 결과를 입력하면 반올림됩니다 .. 이유가 없습니다 ..C#에서 반올림 버그?

무엇이 잘못 되었나요? 아래 코드의 결과는 다음과 같습니다 둥근 : 591.24575 591.2457-591.2458

double number1 = 1136.81; 
double number2 = 4.00; 
double number3 = 2182.257; 
double result = (number1 * number2 - number3)/4; 
Console.WriteLine("Rounded: " +result+" " + Math.Round(result, 4, MidpointRounding.AwayFromZero) + " - " + Math.Round(591.24575, 4, MidpointRounding.AwayFromZero)); 
Console.ReadLine(); 
+4

'double'은 (Round, Floor 등을 사용하여) 10 진수로 /에서 10 진수로 변환 할 때 100 % 정확하지 않은 2 진 부동 소수점 데이터 유형이기 때문입니다. base-10의 정밀도가 필요하다면'decimal'을 사용하십시오. –

+3

프레임 워크 나 C#에 누군가가 기대하는 방식으로 작동하지 않는 버그가 있다는 가정을 언제나 매료시킵니다. –

+1

@DanielKelley 공정하게 말하자면 사용자는 "나는 * 내가 * 잘못 했나요?"라고 말했습니다. – LarsTech

답변

3

result가 정확히 591.24575, 그것은 591.24575 매우 가까운 일부 수는 있지만,의 라인을 따라 뭔가 단지 약간 작은 591.24574999999999의 결과로, 기수 10의 유한 자릿수가있는 특정 숫자는 기수 2의 유한 자릿수로 표현 될 수 없습니다. 숫자를 정확히 설정하면 double이 1로 설정되는 것을 피할 수 있습니다 그 값들을 계산의 중간 값으로 사용하십시오.

알려진 10 진수의 고정 숫자가있는 숫자를 처리하는 경우 이러한 정밀도 오류가없는 것이 중요하므로이 문맥에서는 Decimal을 사용하는 것이 적절할 수 있습니다.

+0

아, 30 분에 맞춰서 :) – Stijn

+0

앞으로이 문제를 해결하기 위해 할 수있는 일이 있다면 결과에 할당 한 직후에 코드에 중단 점을 넣는 것입니다. . 앱 및 마우스 오버 결과를 디버그하여 실제 값보기 – Kritner

4

을 내 DoubleConverter를 사용하는 경우 result정확한 값을 볼 수 있습니다

Console.WriteLine(DoubleConverter.ToExactString(result)); 

을 그 인쇄물 :

591.2457499999999299689079634845256805419921875 

... 소수점 네 자리로 반올림하면 591.2457로 반올림됩니다. result을 인쇄 할 때 이미 소수점 이하 자리수로 반올림되어 있으므로 , (정신적으로) 4 DP로 반올림 한 경우 결과에 영향을 줄 수 있습니다.

이진 부동 소수점의 "정상적인"기이함이 없어도이를 볼 수 있습니다. 그러나 당신이 정신적으로 result (591.24575)의 출력 값을 취함으로써 그렇게 당신이 할이 걸릴 수 있습니다 가정했다 - 당신이 실제로 "두 라운딩을"수행되지 않은 코드에

decimal exact = 1.2345m; 
decimal rounded2 = Math.Round(exact, 2, MidpointRounding.AwayFromZero); 
decimal rounded3 = Math.Round(exact, 3, MidpointRounding.AwayFromZero); 
decimal rounded3Then2 = Math.Round(rounded3, 2, MidpointRounding.AwayFromZero); 
Console.WriteLine(rounded2); // 1.23 
Console.WriteLine(rounded3); // 1.235 
Console.WriteLine(rounded3Then2); // 1.24 

:이 코드를 고려 그것을 더 멀리두기 위해 정확한.