Floating point(실수) 계산은 때때로 문제가 되며, 신비스럽게 보이기도 합니다.
게다가 C 언어는 원래 floating point를 주로 쓸 목적이 아니었기 때문에 더욱
문제가 됩니다.
Q 14.1
float 타입의 변수에 3.1을 넣고 printf로 출력해보니
3.09999999가 나옵니다. 왜 그럴까요?
Answer
대부분의 컴퓨터는 실수를 표현할 때, 내부적으로 2 진수로 기록합니다.
2 진수에서는 0.1은 무리수로 (0.0001100110011...)
표현됩니다. 따라서 3.1과 같은 수는 (10 진수로 볼 때에는 유리수이지만)
2 진수에서는 유한한 수치로 표현될 수 없습니다. 여러분의 시스템에서
10 진수를 2 진수로 변환하는 루틴이 어떻게 작성되었느냐에 따라
다르겠지만, (특히 정밀도가 낮은 float을 쓸 경우) 대입한 수치와
출력 결과가 약간 다를 수 있습니다. 덧붙여 질문 14.6도 참고하시기 바랍니다.
Q 14.2
제곱근을 (square root) 구하려 하는데, 이상한 값만 나옵니다.
Answer
먼저 <math.h>를 포함시켰는지 검사해 보고, 함수들이
double을 리턴하도록 선언되었는지 체크해보기 바랍니다.
(atof() 함수는 <stdlib.h>에 선언되어 있음을 주의하기
바랍니다.) 덧붙여 질문 14.3도 참고하시기 바랍니다.
삼각 함수를 쓰려고 하는데 <math.h>를 포함시켰는데도
컴파일러는 ``undefined: sin''이라는 컴파일 에러를 출력합니다.
Answer
수학 라이브러리를 포함시켰는지 체크하기 바랍니다.
예를 들어 UNIX 시스템에서는 `-lm' 옵션을 컴파일할 때 마지막 인자로
주어야 합니다. 덧붙여 질문 13.25, 13.26, 14.2도 참고하시기 바랍니다.
Q 14.4
제가 만든 실수 계산 루틴은 매우 이상한 결과를 출력하고, 또
컴퓨터가 다르면 다른 결과가 나옵니다.
Answer
먼저 질문 14.2를 읽어보기 바랍니다.
문제가 간단하지 않겠지만, 디지털 컴퓨터에서 실수 처리는
정확하지 않을 수도 있다는 것을 알아두셔야 합니다.
언더플로우(underflow)가 일어날 수도 있으며, 오차가 점점 누적될
수도 있습니다.
따라서 실수 연산이 정확하지 않다는 것을 기억하기 바라며,
같은 이유로 두 실수가 같은지 비교하는 것은 좋지 않습니다.
(Don't throw haphazard ``fuzz factors'' in, either; 질문 14.5를
참고하기 바랍니다.)
이런 문제는 꼭 C 언어에만 국한된 것이 아니고, 모든 프로그래밍
언어에서 발생할 수 있습니다. 실수에 대한 어떤 부분들은 대개
``프로세서가 어떻게 처리하느냐''에 따라 다릅니다
(덧붙여 질문 11.34도 참고하시기 바랍니다.), 그렇지 않는 경우라면 적절한 기능을 수행할 수 있게
하기 위해 댓가가 큰 에뮬레이션을 사용합니다.
안타깝게도 이 문서는 이런 실수 연산에 대한 단점이나 해결책을 위한
것이 아닙니다. 좋은 수치 프로그래밍에 (numerical programming) 대한
책들이 여러분을 도와줄 겁니다. 아래 참고 문헌에 나온 책들을
보시면 좋습니다.
단, 이 기법은 음수에는 쓸 수 없습니다. 음수에는
다음과 같은 코드를 써야 할 것입니다:
(int)(x < 0 ? x - 0.5 : x + 0.5)
Q 14.7
왜 C 언어에는 지수를 (exponentiation) 계산하는 연산자가 없을까요?
Answer
대부분 프로세서에는 지수를 계산하는 명령(instruction)이 없기
때문입니다. 대신 C 언어는 pow()라는 함수를 제공합니다.
이 함수는 <math.h>에 선언되어 있습니다.
크기가 작고 0보다 큰 정수를 곱하는 것이 이 함수를 쓰는 것보다
더 효과적일 수도 있습니다.
고품질의 IEEE 실수 구현 방법을 제공하는 대부분의 시스템에서는
(미리 정의된 상수와 isnan()과 같은 함수를 제공하며, 이들은
표준이 아닙니다. 또 <math.h>나 <ieee.h>, <nan.h>에
선언되어 있을 수 있습니다.) 이런 값들을 다루기 위한 함수들을 제공합니다.
그리고 이런 기능들을 지금 표준화하려고 하고 있답니다.
NaN을 검사하는 가장 거칠고(crude) 간단한 방법은 다음과 같습니다.
#define isnan(x) ((x) != (x))
IEEE를 생각하지 않은 컴파일러는 이런 테스트를 최적화 단계에서
없애버릴 수도 있습니다14.1.
I'm looking for some code to do:
Fast Fourier Transforms (FFT's),
matrix arithmetic (multiplication, inversion, etc.),
complex arithmetic?
Answer
Ajay Shah has prepared a nice index of free numerical
software which has been archived pretty widely; one URL
is
ftp://ftp.math.psu.edu/pub/FAQ/numcomp-free-c.
덧붙여 질문 18.13,18.15c, 18.16도 참고하시기 바랍니다.
Q 14.13
Turbo C를 사용하고 있습니다. 그런데 프로그램을 실행하면
``floating point format not linked''라는 메시지를 출력하고
종료해버립니다.
Answer
Borland사의 컴파일러를 포함한 (Ritchie씨의 오리지널 PDP-11 컴파일러도)
규모가 작은 시스템의 어떤 컴파일러들은 실수 처리 부분이 필요없다고
판단되면 실수 처리 루틴을 포함시키지 않습니다.
특히 실수를 처리하지 않는 (즉 %f, %e를
쓰지 않는) printf()나 scanf()는 많은 공간을 줄일 수 있습니다.
아마도 여러분의 컴파일러에서는 실수 처리 부분이 필요없다고 생각되어
빠진 것 같습니다. 이럴 때에는 간단한 dummy call을 사용하면 됩니다.
즉, sqrt()와 같은 함수를 한 번 불러주면, 실수 처리 루틴이
포함될 것입니다. (자세한 것은 comp.os.msdos.programmer의
FAQ를 읽어 보시기 바랍니다.)
Next: 15. Variable-Length Argument Lists Up: C Programming FAQs Previous: 13. Library Functions
14. Floating Point
Floating point(실수) 계산은 때때로 문제가 되며, 신비스럽게 보이기도 합니다. 게다가 C 언어는 원래 floating point를 주로 쓸 목적이 아니었기 때문에 더욱 문제가 됩니다.
<math.h>
를 포함시켰는지 검사해 보고, 함수들이 double을 리턴하도록 선언되었는지 체크해보기 바랍니다. (atof() 함수는<stdlib.h>
에 선언되어 있음을 주의하기 바랍니다.) 덧붙여 질문 14.3도 참고하시기 바랍니다.<math.h>
를 포함시켰는데도 컴파일러는 ``undefined: sin''이라는 컴파일 에러를 출력합니다.문제가 간단하지 않겠지만, 디지털 컴퓨터에서 실수 처리는 정확하지 않을 수도 있다는 것을 알아두셔야 합니다. 언더플로우(underflow)가 일어날 수도 있으며, 오차가 점점 누적될 수도 있습니다.
따라서 실수 연산이 정확하지 않다는 것을 기억하기 바라며, 같은 이유로 두 실수가 같은지 비교하는 것은 좋지 않습니다. (Don't throw haphazard ``fuzz factors'' in, either; 질문 14.5를 참고하기 바랍니다.)
이런 문제는 꼭 C 언어에만 국한된 것이 아니고, 모든 프로그래밍 언어에서 발생할 수 있습니다. 실수에 대한 어떤 부분들은 대개 ``프로세서가 어떻게 처리하느냐''에 따라 다릅니다 (덧붙여 질문 11.34도 참고하시기 바랍니다.), 그렇지 않는 경우라면 적절한 기능을 수행할 수 있게 하기 위해 댓가가 큰 에뮬레이션을 사용합니다.
안타깝게도 이 문서는 이런 실수 연산에 대한 단점이나 해결책을 위한 것이 아닙니다. 좋은 수치 프로그래밍에 (numerical programming) 대한 책들이 여러분을 도와줄 겁니다. 아래 참고 문헌에 나온 책들을 보시면 좋습니다.
[Knuth] Vol. 2 Chap. 4
[Goldberg]
이렇게 합니다:
<math.h>
에 선언되어 있습니다. 크기가 작고 0보다 큰 정수를 곱하는 것이 이 함수를 쓰는 것보다 더 효과적일 수도 있습니다.[H&S] § 17.6 p. 393
<math.h>
에는 매크로M_PI
가 정의되어 있지 않습니다.4 * atan(1.0)
으로 계산해야 합니다.<math.h>
나<ieee.h>
,<nan.h>
에 선언되어 있을 수 있습니다.) 이런 값들을 다루기 위한 함수들을 제공합니다. 그리고 이런 기능들을 지금 표준화하려고 하고 있답니다. NaN을 검사하는 가장 거칠고(crude) 간단한 방법은 다음과 같습니다.[C9X]는 isnan(), fpclassify() 등과 다른 종류 함수들을 제공합니다.
또 하나의 방법은 이 실수를 sprintf()와 같은 루틴을 써서 포맷화시켜 보는 것입니다. 많은 시스템이 이런 경우 ``NaN''이나 ``Inf''와 같은 문자열을 만들어 줄 겁니다.
덧붙여 질문 19.39도 참고하시기 바랍니다.
ftp://ftp.math.psu.edu/pub/FAQ/numcomp-free-c.
덧붙여 질문 18.13, 18.15c, 18.16도 참고하시기 바랍니다.
Next: 15. Variable-Length Argument Lists Up: C Programming FAQs Previous: 13. Library Functions
All rights reserved. Copyright © 2004-2006 Seong-Kook Shin (신성국)
Return to my homepage
2006-08-30
Recent Posts
Archive Posts
Tags