2017-12-26 10 views
0

10 진수 시간 초과 근무를 계산하는 작은 소프트웨어를 C#으로 만들었습니다. 나는 항상 가장 가까운 1/10 시간으로 반올림되도록 디자인했다. 내가 가지고있는 문제는 정확하게 2 시간 12 분 또는 3 시간 12 분인 시간을 계산하려고 할 때 잘못된 결과를 얻는다는 것입니다. 관련 코드는 다음과 같습니다TimeSpan 계산 오류

DateTime start = new DateTime(
         dtpDateStart.Value.Year, 
         dtpDateStart.Value.Month, 
         dtpDateStart.Value.Day, 
         dtpTimeStart.Value.Hour, 
         dtpTimeStart.Value.Minute, 
         0); 

     DateTime end = new DateTime(
      dtpDateEnd.Value.Year, 
      dtpDateEnd.Value.Month, 
      dtpDateEnd.Value.Day, 
      dtpTimeEnd.Value.Hour, 
      dtpTimeEnd.Value.Minute, 
      0); 

     TimeSpan subtotal = end - start; 

     double subtotalRounded = subtotal.TotalHours; 
     subtotalRounded = (Math.Floor(subtotalRounded * 10)/10); 

dtpDateStart, dtpTimeStart, dtpDateEnddtpTimeEnd가 승리 양식 프로젝트의 모든 날짜 시간 선택기 컨트롤입니다.

이 코드를 디버깅 할 때 반환 값이 subtotalRounded 인 경우 2.2 및 3.2 대신 2.1999999999999997 또는 3.1999999999999997입니다. 이 값은 4 시간 12 분 이상 또는 1 시간 12 분 이하의 값으로는 발생하지 않습니다.

어쨌든, 왜이 두 값만 반올림 오류가 발생하는지 완전히 왜곡되었습니다. 누구든지 제안이나 의견이 있습니까? 방법을 잘못 사용하고 있습니까? 아니면이를 수행하는 더 좋은 방법이 있습니까?

+3

이것은 부동 소수점 "오류"(의도적 인 인용 부호)처럼 보입니다.반올림 문제 (특히 소수점 이하 자릿수)를 원하지 않는 경우 : double을 사용하지 마십시오. 몇 분 (또는 초 또는 원하는 정밀도)으로 정수로 작업하거나, 십진법은 다음과 같습니다. 분 (초, 무엇이든)에서 십진수로 변환 –

답변

0

이것은 단순히 부동 소수점 값이 작동하는 방식이며 일반적으로 계산할 때보다는 표시 할 때 처리합니다. 그 때 문자열을 할 때입니다. 형식 ("{0 : f2}", 값) 그것은 원하는 자릿수로 반올림됩니다.

+3

부분적으로 올바르지 않습니다. 형식이 반올림되지 않습니다. 남은 자릿수 만 잘라냅니다. 반올림은 컷오프보다 큰 값을 가질 수 있으므로 매우 중요한 차이입니다. – Christopher

2

십진수 표현이 아닌 비트 표현에서 정확한 double을 사용합니다. 대신 데이터 유형 decimal을 사용하십시오. Microsoft 상태이 :

하지 마십시오 사용 플로트 또는 실제 열이 WHERE 절 검색 조건, 특히 = 및 <> 운영자. float 및 실제 열을> 또는 < 비교로 제한하는 것이 가장 좋습니다.

변경이 두 개의 코드 라인이에

double subtotalRounded = subtotal.TotalHours; 
subtotalRounded = (Math.Floor(subtotalRounded * 10)/10); 

:

decimal subtotalRounded = subtotal.TotalHours; // See data type! 
subtotalRounded = (Math.Floor(subtotalRounded * 10)/10); 

또는 짧은이 :

decimal subtotalRounded = = (Math.Floor(subtotal.TotalHours * 10)/10); 
당신은 적절한 데이터 형식 변환을 수행해야 할 수 있습니다

. 그렇다면 Convert 클래스의 도우미 메서드를 사용할 수 있습니다.

+1

그것은 실제로 오래된 부동 소수점 오해와 같은 소리입니다. 이 동영상에서는 다음 내용을 잘 설명합니다. https://www.youtube.com/watch?v=PZRI1IfStY0 기본적으로 정밀도가 필요한 경우 플로트를 사용할 수 없습니다. – Christopher

0

특정 숫자는 double에 정확하게 표시 할 수 없습니다. decimal을 사용하거나 분 단위로 (바람직하게) 작업 한 다음 출력시 decimal을 사용하여 60으로 나누어야합니다.

0

당신은 부동 소수점에 대해 괜찮습니다. 나는 모든 것을 10 진수로 변환했으며 이제는 작동한다. 여기에 좀 더 우아한 방법이 있지만 여기에 내 코드가 있습니다.

 DateTime start = new DateTime(
         dtpDateStart.Value.Year, 
         dtpDateStart.Value.Month, 
         dtpDateStart.Value.Day, 
         dtpTimeStart.Value.Hour, 
         dtpTimeStart.Value.Minute, 
         0); 

     DateTime end = new DateTime(
      dtpDateEnd.Value.Year, 
      dtpDateEnd.Value.Month, 
      dtpDateEnd.Value.Day, 
      dtpTimeEnd.Value.Hour, 
      dtpTimeEnd.Value.Minute, 
      0); 

     TimeSpan subtotal = end - start; 

     decimal decSubtotalMinutes = Convert.ToDecimal(subtotal.TotalMinutes); 
     decSubtotalMinutes = decSubtotalMinutes/60; 
     decSubtotalMinutes = (Math.Floor(decSubtotalMinutes * 10)/10); 

10 진수를 사용하면 계산이 올바르게 이루어집니다. double을 사용하면 부동 소수점 오류가 발생한다는 것을 알지 못했습니다. 새로운 프로그래머를 도와 주신 모든 분들께 감사드립니다!