-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfloats.tex
237 lines (203 loc) · 8.74 KB
/
floats.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
\chapter{Floating Point} \label{chap:float}
% chapter 14: floats
Floating point(실수) 계산은 때때로 문제가 되며, 신비스럽게 보이기도 합니다.
게다가 C 언어는 원래 floating point를 주로 쓸 목적이 아니었기 때문에 더욱
문제가 됩니다.
\begin{faq}
\Q{14.1}
\TT{float} 타입의 변수에 3.1을 넣고 \TT{printf}로 출력해보니
3.09999999가 나옵니다. 왜 그럴까요?
\A
대부분의 컴퓨터는 실수를 표현할 때, 내부적으로 2 진수로 기록합니다.
2 진수에서는 0.1은 무리수로 (0.0001100110011\ldots)
표현됩니다. 따라서 3.1과 같은 수는 (10 진수로 볼 때에는 유리수이지만)
2 진수에서는 유한한 수치로 표현될 수 없습니다. 여러분의 시스템에서
10 진수를 2 진수로 변환하는 루틴이 어떻게 작성되었느냐에 따라
다르겠지만, (특히 정밀도가 낮은 \TT{float}을 쓸 경우) 대입한 수치와
출력 결과가 약간 다를 수 있습니다. \seealso{\ql{14.6}}
\end{faq}
\begin{faq}
\Q{14.2}
제곱근을 (square root) 구하려 하는데, 이상한 값만 나옵니다.
\A
먼저 \verb+<math.h>+를 포함시켰는지 검사해 보고, 함수들이
\TT{double}을 리턴하도록 선언되었는지 체크해보기 바랍니다.
(\TT{atof()} 함수는 \verb+<stdlib.h>+에 선언되어 있음을 주의하기
바랍니다.) \seealso{\ql{14.3}}
\R
\cite{ctp} \S\ 4.5 \Page{65--6}
\end{faq}
\begin{faq}
\Q{14.3}
삼각 함수를 쓰려고 하는데 \verb+<math.h>+를 포함시켰는데도
컴파일러는 ``undefined: sin''이라는 컴파일 에러를 출력합니다.
\A
수학 라이브러리를 포함시켰는지 체크하기 바랍니다.
예를 들어 UNIX 시스템에서는 `-lm' 옵션을 컴파일할 때 마지막 인자로
주어야 합니다. \seealso{\ql{13.25}, \ql{13.26}, \ql{14.2}}
\end{faq}
\begin{faq}
\Q{14.4}
제가 만든 실수 계산 루틴은 매우 이상한 결과를 출력하고, 또
컴퓨터가 다르면 다른 결과가 나옵니다.
\A
먼저 질문 \ql{14.2}를 읽어보기 바랍니다.
문제가 간단하지 않겠지만, 디지털 컴퓨터에서 실수 처리는
정확하지 않을 수도 있다는 것을 알아두셔야 합니다.
언더플로우(underflow)가 일어날 수도 있으며, 오차가 점점 누적될
수도 있습니다.
따라서 실수 연산이 정확하지 않다는 것을 기억하기 바라며,
같은 이유로 두 실수가 같은지 비교하는 것은 좋지 않습니다.
(Don't throw haphazard ``fuzz factors'' in, either; 질문 \ql{14.5}를
참고하기 바랍니다.)
% TODO: 위 문장 번역
이런 문제는 꼭 C 언어에만 국한된 것이 아니고, 모든 프로그래밍
언어에서 발생할 수 있습니다. 실수에 대한 어떤 부분들은 대개
``프로세서가 어떻게 처리하느냐''에 따라 다릅니다
(\seealso{\ql{11.34}}), 그렇지 않는 경우라면 적절한 기능을 수행할 수 있게
하기 위해 댓가가 큰 에뮬레이션을 사용합니다.
안타깝게도 이 문서는 이런 실수 연산에 대한 단점이나 해결책을 위한
것이 아닙니다. 좋은 수치 프로그래밍에 (numerical programming) 대한
책들이 여러분을 도와줄 겁니다. 아래 참고 문헌에 나온 책들을
보시면 좋습니다.
\R
\cite{elemprog} \S\ 6 \Page{115--8} \\
\cite{knuth} Vol.\ 2 Chap.\ 4 \\
\cite{fpoint}
\end{faq}
\begin{faq}
\Q{14.5}
그럼 ``아주 가까운'' 두 실수를 비교하는 방법이 있을까요?
\A
실수의 절대값이 정의에 의하면 `magnitude'에 따라 달라질 수 있으므로,
두 실수를 비교하려면 다음과 같이, 오차가 상대적으로 무시할 수 있는
작은 값인지를 검사하는 것이 좋습니다. 즉 다음과 같이 할 것이 아니라:
\begin{verbatim}
double a, b;
...
if (a == b) /* WRONG */
\end{verbatim}
\noindent 이렇게 합니다:
\begin{verbatim}
#include <math.h>
if (fabs(a - b) <= epsilon * fabs(a))
\end{verbatim}
... TODO ...
% \noindent (`\TT{a}'이 0이 아닌 한) epsilon에 가까운 수치를 쓰는
% 것이 좋습니다.
% TODO: 원서 내용 채워넣기
\R
\cite{knuth} \S\ 4.2.2 \Page{217--8}
\end{faq}
\begin{faq}
\Q{14.6}
수치를 반올림하는 (round) 방법을 알려주세요.
\A
가장 간단하고 직관적인 방법은 다음과 같은 코드를 쓰는 것입니다:
\begin{verbatim}
(int)(x + 0.5)
\end{verbatim}
\noindent 단, 이 기법은 음수에는 쓸 수 없습니다. 음수에는
다음과 같은 코드를 써야 할 것입니다:
\begin{verbatim}
(int)(x < 0 ? x - 0.5 : x + 0.5)
\end{verbatim}
\end{faq}
\begin{faq}
\Q{14.7}
왜 C 언어에는 지수를 (exponentiation) 계산하는 연산자가 없을까요?
\A
대부분 프로세서에는 지수를 계산하는 명령(instruction)이 없기
때문입니다. 대신 C 언어는 \TT{pow()}라는 함수를 제공합니다.
이 함수는 \verb+<math.h>+에 선언되어 있습니다.
크기가 작고 0보다 큰 정수를 곱하는 것이 이 함수를 쓰는 것보다
더 효과적일 수도 있습니다.
\R
\cite{c89} \S\ 7.5.5.1 \\
\cite{hs} \S\ 17.6 \page{393}
\end{faq}
\begin{faq}
\Q{14.8}
제 시스템의 \verb+<math.h>+에는 매크로 \verb+M_PI+가 정의되어
있지 않습니다.
\A
이 매크로 상수는 (이 매크로의 값은 pi이며, 정밀도는 각 시스템에
따라 다릅니다) 표준이 아닙니다.
`pi' 값이 필요하다면, 여러분이 직접 정의하거나 \verb+4 * atan(1.0)+으로
계산해야 합니다.
\R
\cite{pcs} \S\ 13 \page{237}
\end{faq}
\begin{faq}
\Q{14.9}
IEEE NaN과 같은 특수한 값을 검사하려면 어떻게 하면 되죠?
\A
고품질의 IEEE 실수 구현 방법을 제공하는 대부분의 시스템에서는
(미리 정의된 상수와 \TT{isnan()}과 같은 함수를 제공하며, 이들은
표준이 아닙니다. 또 \verb+<math.h>+나 \verb+<ieee.h>+, \verb+<nan.h>+에
선언되어 있을 수 있습니다.) 이런 값들을 다루기 위한 함수들을 제공합니다.
그리고 이런 기능들을 지금 표준화하려고 하고 있답니다.
NaN을 검사하는 가장 거칠고(crude) 간단한 방법은 다음과 같습니다.
\begin{verbatim}
#define isnan(x) ((x) != (x))
\end{verbatim}
IEEE를 생각하지 않은 컴파일러는 이런 테스트를 최적화 단계에서
없애버릴 수도 있습니다\footnote{although non-IEEE-aware compilers
may optimize the test away}.
\cite{c9x}는 \TT{isnan()}, \TT{fpclassify()} 등과 다른 종류 함수들을
제공합니다.
또 하나의 방법은 이 실수를 \TT{sprintf()}와 같은 루틴을 써서 포맷화시켜
보는 것입니다. 많은 시스템이 이런 경우 ``NaN''이나 ``Inf''와 같은
문자열을 만들어 줄 겁니다.
\seealso{\ql{19.39}}
\R
\cite{c9x} \S\ 7.7.3
\end{faq}
\begin{faq}
\Q{14.11}
복소수\footnote{complex number}를 C 언어에서 구현하려면
어떤 방법이 제일 좋을까요?
\A
가장 쉬운 방법은 간단한 구조체를 만들고 이 구조체에 대해 연산할 수
있는 함수를 만드는 것입니다. \cite{c9x}는 `\TT{complex}'라는 표준 데이터
타입을 지원하려 합니다. \seealso{\ql{2.7}, \ql{2.10}, \ql{14.12}}
\R
\cite{c9x} \S\ 6.1.2.5, \S\ 7.8
\end{faq}
\begin{faq}
\Q{14.12}
I'm looking for some code to do:
Fast Fourier Transforms (FFT's),
matrix arithmetic (multiplication, inversion, etc.),
complex arithmetic?
\A
Ajay Shah has prepared a nice index of free numerical
software which has been archived pretty widely; one URL
is \\ \TT{ftp://ftp.math.psu.edu/pub/FAQ/numcomp-free-c}.
\noindent \seealso{\ql{18.13},\ql{18.15c}, \ql{18.16}}
\end{faq}
\begin{faq}
\Q{14.13}
Turbo C를 사용하고 있습니다. 그런데 프로그램을 실행하면
``floating point format not linked''라는 메시지를 출력하고
종료해버립니다.
\A
Borland사의 컴파일러를 포함한 (Ritchie씨의 오리지널 PDP-11 컴파일러도)
규모가 작은 시스템의 어떤 컴파일러들은 실수 처리 부분이 필요없다고
판단되면 실수 처리 루틴을 포함시키지 않습니다.
특히 실수를 처리하지 않는 (즉 \TT{\%f}, \TT{\%e}를
쓰지 않는) \TT{printf()}나 \TT{scanf()}는 많은 공간을 줄일 수 있습니다.
아마도 여러분의 컴파일러에서는 실수 처리 부분이 필요없다고 생각되어
빠진 것 같습니다. 이럴 때에는 간단한 dummy call을 사용하면 됩니다.
즉, \TT{sqrt()}와 같은 함수를 한 번 불러주면, 실수 처리 루틴이
포함될 것입니다. (자세한 것은 \TT{comp.os.msdos.programmer}의
FAQ를 읽어 보시기 바랍니다.)
\R
\cite{hs5} \S\ 6.2.5 \page{40},
\end{faq}
%
% Local Variables:
% coding: utf-8
% fill-column: 78
% End:
%