소수 자리 숫자들의 사칙연산

커뮤니티에 올라온 질문 중에 소수자리 숫자에 대한 덧셈 계산의 결과가 이상하다는 내용이 있어 정리해 봅니다.
질문에 올라온 코드는 아래와 같습니다.
[code]
double a = 35147.464;
double b = 73823.828;
double c= a+b;
System.out.println("a+b=" + (a+b));
System.out.println("c=" + c);

double d = 587350.504;
double e = 63354.488;
double f= d+e;
System.out.println("d+e=" + (d+e));
System.out.println("f=" + f );
[/code]

실행한 결과는 아래와 같습니다.
[code]
a+b=108971.29199999999
c=108971.29199999999
d+e=650704.992
f=650704.992
[/code]

왜 똑같이 소수점 세 자리 숫자를 더했는데 어떤 때는 소수점 아래 자릿수가 늘고 어떤 때는 세 자리로
출력되었을까요?

소수자리 숫자는 인간이 생각하는 10진수의 개념으로 접근 하면 안되기 때문인데요..
알고있듯이 컴퓨터는 0,1 로 모든 연산을 처리하는데 int, long 같은 정수라면 0,1로 표현할 수 있지만
float, double 같은 소수자리 수는 IEEE 754 표준에 의한 binary의 일부(fractions)로  표현하게 됩니다.
( http://www.math.byu.edu/~schow/work/IEEEFloatingPoint.htm 참조하시면 됩니다만 제게는 참.. 어렵네요.)
어쨌거나 저쨌거나 결과만 놓고 보면 '소수자리 숫자는 컴퓨터는 근사값 밖에 알 수 없다.' 인데요.

그럼, 저렇게 계산되도록 놔둬야 하느냐? 그렇지는 않습니다.
위 같은 경우는 DecimalFormat.parse() 메소드를 이용하면 됩니다.
맨 처음 코드를 아래와 같이 다시 작성해 볼 수 있겠지요.
[code]
java.text.DecimalFormat format = new java.text.DecimalFormat(".###");

double a = 35147.464d;
double b = 73823.828d;
double c= a+b;
System.out.println("a+b=" + format.parse( format.format(a+b) ) );
System.out.println("c=" + format.parse( format.format(c) ) );

double d = 587350.505d;
double e = 63354.491d;
double f= d+e;
System.out.println("d+e=" + format.parse( format.format(d+e) ) );
System.out.println("f=" + format.parse( format.format(f) ) );
[/code]


그럼 결과는 아래와 같이 원하는 대로 출력이 될 겁니다.
[code]
a+b=108971.292
c=108971.292
d+e=650704.996
f=650704.996
[/code]


한가지 유의해야 할 점은 저런 방식의 처리를 정확성을 요구하는 금융이나, 계측 분야에 적용 할 때는
계산결과의 정밀도가 충분히 받아들여질 만한 것인지를 다시 한 번 고민해야 한다는 겁니다.

금융과 같이 double이 허용하는 것보다 큰 숫자가 필요로 할 때는 BigDecimal을 이용해야 합니다.
( http://www.yunsobi.com/blog/227 BigDecimal의 필요성 참조 )

2010/05/14 19:54 2010/05/14 19:54
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다