Software Architect/C#
  • 닷넷기반의 언어 혹은 일반적인 프로그래밍 언어에서 '실수 연산'을 다룰 때에는 예상하지 못한
    여러가지 다른 결과가 출력 될 수 있습니다.

       

  • Casting의 문제

       

float f = 0.55f;

double d = (double)f;

double d2 = 0.55;

decimal dec = 0.55m;

Console.WriteLine(d2 + d2);

Console.WriteLine(f + 0.12);

Console.WriteLine(d2 + 0.12);

   

   

  • 위의 연산 결과는 예측된 결과와 전혀 다른 값을 보여줍니다.
    • c# 내부에서 소수의 접미사에 f를 붙이지 않을 경우 자동으로 double로 casting 되어 연산되는 문제와
    • float과 double의 casting시 예상하지 못한 결과가 나오는 문제가 있습니다.

         

  • 계산 방식의 문제
    • 실수 연산에서 위와같이 정확하지 않은 결과가 나오는 이유는
      • 프로그램(컴퓨터)는 사람이 생각하는 계산방식과 다르다는 점에 있습니다.

         

double a = 11.22;

double b = 11.10 + 0.12;

Console.WriteLine("{0:e16}", a);

Console.WriteLine("{0:e16}", b);

   

   

  • 위의 결과와 같이 컴퓨터는 실수를 표현하는 부동 소수점 방식은 특정한 식에 의해
    최대한의 근사치 만을 표현하기 떄문에 다른 결과가 나올 수 있습니다.
    • 돈 혹은 소수점 자리에 민감한 숫자의 경우 실수를 이용한 정확한 연산 결과가 보장되어야 합니다.
      • 그러나 부동소수점(float / double)을 이용한 연산 결과는 정확하지 않습니다.
  • 그러므로 정확한 소수점 연산이 필요할 시에는 부동소수점을 사용하면 문제가 발생 할 수 있습니다.

       

  • 정확한 계산을 위한 몇 가지 해결 방법
    • Decimal
      • 정확한 계산이 필요할 시에는 decimal 데이터 타입을 사용하라고 아래와 같이 MSDN은 권고하고 있습니다.
        • 'Single Double에서는 정확하지 않는 숫자가 Decimal에서는 정확하게 표시되는 경우 있습니다(: 0.2, 0.3). Decimal에서는 부동 소수점에서보다 산술 연산이 느리지만 정확한 결과 나타나므로 성능 감소를 감내할 만한 가치가 있습니다'
          • 'Decimal 데이터 형식은 모든 숫자 형식 가장 느린 형식입니다. 데이터 형식을 선택하기 전에 정밀도와 성능 중 무엇이 중요한지를 충분히 검토해야 합니다'
        • 단, 위의 문구와 같이 Decimal은 모든 숫자 타입의 형식 중에가서 가장 느리기 때문에
          성능과 정확도 중에서 어느 부분을 기준으로 처리해야 할 지 검토해야 합니다.
    • 내결함성 허용
      • decimal을 사용하지 않고도 실수 연산의 결과가 보장되어야 하는 경우
        • 부동 소수점 실수(float/double)를 사용하고 허용하는 범위 내에서 결과를 보장해야 한다라는 내결함성 허용의 조건에 만족한다면 궂이 느린 타입의 decimal을 사용할 필요는 없습니다.

             

double difference = a * 0.0001; // 0.1% 오차범위는 허용합니다.

bool result = Math.Abs(a - b) <= difference; // true 값으로 반환됩니다.

Console.WriteLine(result);

Console.WriteLine("{0:e16}", a);

Console.WriteLine("{0:e16}", b);

   

  •    

신고
1 0