[ 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장, 부록A, 부록B,C, 부록D, GNU C 라이브러리 목록 ]

이글은 하이텔 소프트웨어동호회의 소모임인 직장인을 위한 씨모임에서 장장 2년간의 대장정으로 번역되어진 문서입니다. 지금은 직씨장을 지내고 있는 김소영(flpigy)님과 조원봉(thirnine)님, 고석갑님(sukgab)의 공동번역입니다.

14.저-수준 연산 함수들.

14.1 "숫자가 아닌" 값들.

대부분의 현대적 컴퓨터들에서 사용되는 IEEE 플로팅 포인트 형식은 "숫자가 아닌" 값들도 지원한 다. 이들 값들은 NaNs 라고 불린다. "숫자가 아닌" 값들은 0을 0으로 나누거나 또는 무한대를 무 한대로 나누는 것과 같이, 아무런 의미없는 숫자 결과를 갖는 어떤 명령들로부터의 결과이다.

NaNs의 주목할 만한 특성중의 하나가 그들은 그들 자신과 동등하지 않다는 것이다. 그래서, x == x 식에서 만일 x가 NaN 이라면 그 결과는 0이 될 수 있다. 당신은 어떤 값이 NaN 인지 아닌지를 테스트하기 위해서 이것을 사용할 수 있다: 만일 그것이 그 자신과 같지 않다면, 그것은 NaN이다. 그러나 NaN 인지를 테스트 하기위한 권장할 만한 방법으로는 isnan 함수가 있다. ( 14.2절 [Predicates on Floats], 209 페이지 참조.)

NaN을 한 인수로 사용한 거의 모든 연산 명령들에서는 역시 NaN이 리턴된다.

매크로 : double NAN

"숫자가 아닌" 값들은 표현하는데 사용. 이 매크로는 GNU 확장으로, IEEE 플로팅 포인트를 지원하 는 모든 기계상에서, 그들이 말하는, 즉, "숫자가 아닌" 값들은 지원하는 기계상에서만 유용하다.

당신은 그 기계가 NaNs 를 지원하는지의 여부를 알아보기 위해서 '#ifdef NAN'을 사용할 수 있다. (물론, 당신은 _GNU_SOURCE로 정의해서, GNU 확장으로 정리를 해야 하고, 또한 'math.h'를 포함 해야만한다.)

14.2 플로트의 술어(Predrcates).

이 절은 doubles 의 잡다한 테스트 함수들을 설명한다. 이 함수들을 위한 프로토타입은 'math.h' 에 있다. 그것들은 BSD 함수로 당신이 _BSD_SOURCE 또는 _GNU_SOURCE라고 정의했을 때 유 용하다.

함수 : int isinf (double x)

이 함수는 x 가 무한대의 음수라면 -1을 리턴하고, x 가 무한대의 양수이면 1을 리턴하고, 그렇지 않으면 0을 리턴한다.

함수 : int isnan (double x)

이 함수는 만일 x가 "숫자가 아닌" 것이라면 0이 아닌값을 리턴하고, 그렇지 않으면 0을 리턴한다. ( 당신은 같은 결과를 얻기위해서 x != x 도 사용할 수 있다.)

함수 : int finite (double x)

이 함수는 만일 x 가 한정된 값이거나, "숫자가 아닌" 값이라면 0이 아닌 값을 리턴하고, 그렇지 않 다면 0을 리턴한다.

함수 : double infnan (int error)

이 함수는 BSD 와의 호환성을 위해 제공되었다. 다른 수학적 함수들이 에러가 무엇 때문에 발생했 는지를 알기위해서 infan을 사용한다. 인수로는 EDOM 이나 ERANGE 같은 에러 코드를 사용하고; 이때 infan은 이 에러에 적당한 값을 리턴한다.

-ERANGE

이것 또한 인수로써 받아들여지고, -HUGE_VAL에 해당한다. BSD라이브러리로는, 어떤 기계상에 서, infnan 함수는 모든 경우에 심각한 신호를 발생시킨다. GNU 라이브러리는 ANSI C 규격에 맞 지 않기 때문에 이러한 일을 하지 않는다.

이식성 노트 : 이 절에서 설명된 함수들은 BSD 확장이다.

14.3 절대값.

이들 함수들은 한 숫자의 절대값( 크기가 아닌 )을 얻기위해서 제공된다. 실수 x 의 절대값은 x 가 양의 수라면 x 이고, x 가 음의 수라면 -x 가 된다. 복소수 z 에서, 그 수의 실수부 x 와 허수부 y 가 있다면, 그때 그 수의 절대값은 sqrt(x*x + y*y) 이다.

abs 와 labs 는 'stdlib.h'의 프로토타입은 갖고; fabs 와 cabs는 'math.h'에 선언되어 있다.

함수 : int abs (int number)

이 함수는 수의 절대값을 리턴한다. 대부분의 컴퓨터는 2의 보수(two's complement) 정수 표현을 사용한다. 하지만 2의 보수는 INT_MIN ( 가능한 가장작은 int )의 절대값은 표현 할 수 없기 때문 에; 그래서, abs (INT_MIN)은 정의되지 않았다.

함수 : long int labs (long int number)

이 함수는 abs가 int 형을 사용하는 대신, 인수와 결과값에 long int 형을 사용한다는 점을 제외하고 는 abs와 유사하다.

함수 : double fabs (double number)

이 함수는 플로팅-포인트 수의 절대값을 리턴한다.

함수 : double cabs (struct { double real, imag; } z)

cabs 함수는 실수부로 z.read 과 허수부로 z.imag를 갖고 있는, 복소수 z 의 절대값을 리턴한다. ( 13.4절 [Exponents and Logarithm] 205 페이지에서 hypot 함수를 참조하라. ) 그 값은 :

sqrt (z.real*z.real + z.imag*z.imag)

14.4 표준화 함수들.

이 절에서 설명된 함수들은, 내부적으로 2진 기수(binary radix)를 사용하여 표현되는, 플로팅 포인 트에서 일어나는 저-수준 동작들을 효율적으로 수행하기 위한 방법을 제공한다; A.5.3.1절 [Floating Point Comcepts] 389 페이지 참조. 이들 함수들은 만일 어떤 표현이 2진수를 사용하지 않을 때라도 같은 동작을 하도록 할 필요가 있지만, 물론 그들은 그 경우에 특별히 효율적이게 보이지는 않는다.

이들 함수들 모두는 'math.h'에 선언되어 있다.

함수 : double frexp (double value, int *exponent)

frexp 함수는 숫자를 가수부과 지수부로 분리하는데 사용된다. 만일 그 인수가 0이 아니면, 리턴값 은 가수부의 값이 리턴되고, 그것은 항상 1/2 (포함) 에서 1(제외)의 범위안에 있다. 지수부는 *exponent 에 저장된다; 리턴값에 이 2의 지수승을 곱하면 하면 원래의 숫자값과 같다.

예를들어, frexp (12.8, &exponent) 는 0.8 을 리턴하고 exponent 에 4를 저장한다. 만일 값이 0 이면, 리턴값은 0이고 *exponent에 0이 저장되어 진다.

함수 : double ldexp (double value, int exponent)

이 함수는 2의 exponent승의 값에다, 플로팅 포인트값인 value를 곱한 결과를 리턴한다. ( 그것은 frexp에 의해 떨어지게 되었던 플로팅-포인트의 값을 붙이는데 사용될 수 있다. )

예를 들어, ldexp (0.8, 4) 는 12.8 을 리턴한다.

다음 함수들은 BSD를 위한 함수들로 ldexp 와 frexp 와 동등하다.

함수 : double scalb (double value, int exponent)

scalb 함수는 BSD용 ldexp이다.

함수 : double logb (double x)

이 BSD 함수는 2를 밑으로 하는 로그 x 값에서 정수 부분을 double형으로 리턴한다. 이것은 x 에 포함된 2의 가장 높은 정수 승이다. x의 부호는 무시된다. 예를 들어, logb (3.5) 는 1.0 이고 logb(4.0)은 2.0 이다.

역자주 : 즉 3.5는 2 + 1.5 가 되므로... 2의 가장 높은 정수승이라면 1.0이 되는것이고, 4.0 은 2 의 2승이므로 2.0이 된답니다.

그 결과값은 2의 지수로 한 값이 x 로 나뉘어질 때, 그것은 1 (포함)과 2 (제외) 사이의 값이 주어진 다. 만일 x 가 0이면, 그값은 음의 무한대이고,(만일 그 기계가 그와같은 값을 지원한다면 ), 아니 면, 매우 작은 값이된다. 만일 x 가 무한대이면, 그 값도 무한대이다. logb에 리턴된 값은 frexp가 *exponent에 저장한 값보다 하나가 적다.

함수 : double copysign (double value, double sign)

copysign 함수는 value의 절대값을 리턴하고, sign은 그 수의 부호와 일치시킨다. 이것은 BSD 함수 이다.

14.5 라운딩과 나머지 함수들.

역자주: Rounding(라운딩): 라운딩이란 원래 수학에서 수치를 표현 하기 위해서 유효자리 숫자의 크기를 유지하는 방법인데..이곳에서는 플로팅-포인트를 정수화 하는 여러 가지 방법들을 통틀어 라운딩이라고 표현했습니다.

이곳에서 설명된 함수들은 플로팅 포인트의 나누기에서, 라운딩, 절단, 그리고 나머지와 같은 동작 을 수행하는 함수들이다. 이들 함수중 어떤 것은 플로팅 포인트 숫자들은 정수값으로 변경한다. 그 들은 모두 'math.h'에 선언되어 있다.

당신은 또한 플로팅-포인트 숫자를 int 로 간단히 캐스트(casting) 함으로써 정수로 변경할 수 있 다. 이것은 소수부를 버린다. 하지만, 이것은 그 결과값이 실제로 int 로써 표현가능할 때 작업하고_

아주 매우 큰 수의 경우에는 불가능하다. 이 절에 있는 함수들은 이러한 문제를 유도하는 대신에 double형으로 리턴한다.

함수 : double ceil (double x)

ceil 함수는 근접한 정수로 x를 올림을 하고 그 값을 double형으로 리턴한다. 그래서, ceil (1.5)는 2.0이다.

함수 : double floor (double x)

ceil 함수는 근접한 정수로 x를 내림을해서, 그 값을 double형으로 리턴한다. 그래서, floor (1.5)는 1.0 이고, floor(-1.5)는 -2.0이다.

함수 : double rint (double x)

이 함수는 현재의 라운딩의 모드에 따라서 x를 정수값으로 만든다. A.5.3.2절 [Floating Point Parameters] 390 페이지에서 다양한 라운딩모드들에 대한 정보를 참조하라. 디폴트 라운딩 모드는 가장 근접한 수로 만드는 것이다. 어떤 기계에서는 다른 모드를 지원하지만, 가장 근접한수로의 라 운딩(round-to-nearest)은 당신이 명시적으로 다른 것을 선택할지라도 항상 사용된다.

함수 : double modf (double value, double *integer_part)

이 함수는 인수 value를 정수부분과 소수부분( -1과 1을 제외한 그 사이의 값)으로 분해한다. 그들 의 합은 value와 같다. 그 각 부분들은 value와 같은 부호를 갖기 때문에, 정수부분의 라운딩은 0을 올림과 같다. modf는 *integer`part에 정수부분을 저장하고, 소수부분을 리턴한다. 예를 들어, modf (2.5, &intpart) 는 0.5를 리턴하고, intpart에 2.0을 저장한다.

함수 : double fmod (double numerator, double denominator)

이 함수는 denominator로 numerator를 나눈것의 나머지값을 계산한다. 특별히, n이 denominator 로 numerator을 나눈 몫일 때, 그 몫을 정수로 소수점 뒤를 버리고, 그 리턴값은 numerator-n*denominator 이다. 그래서, fmod(6.5, 2.3)의 리턴값은 6.5에서 4.6을 뺀, 1.9가 된다.

역자주 : 즉...6.5-(6.5/2.3)*2.3 = 6.5-2*2.3 = 6.5-4.6이 된다 이거죠..왜 이렇게 어렵게 할깡~

그 결과는 numerator과 같은 부호를 갖고 denominator의 magnitude 보다 적은 magnitude 를 갖는 다. 만일 denominator이 0이면, fmod는 실패하고 errno를 EDOM으로 설정한다.

함수 : double drem (double numerator, double denominator)

drem 함수는 소수점 이하의 수를 버리는 대신 가장 가까운 정수로 몫 n을 라운딩을 한다는 것을 제 외하고는 fmod와 같다. 예를들어, drem ( 6.5, 2.3) 은 6.5-6.9 이므로 -0.4 를 리턴한다. 결과의 절 대값은 denominator의 절대값의 반과 같거나 더 적다. fmod (numerator, denominator) 과 drem (numerator, denominator) 과의 차이가 denominator, minus denominator, 또는 0 이거나 항상 존재 한다. 만일 denominator 이 0이면, drem 은 실패하고, errno를 EDOM으로 설정한다.

14.6 정수 나누기.

이 절은 정수 나눗셈을 수행하기 위한 함수들을 설명한다. GNU C 라이브러리에 있는 함수들에서 '/' 연산자는 항상 소수점 이하를 버리는 방식으로 버림(round)을 행하지만, 다른 C 에서 '/' 는 음 의 인수에는 다르게 버림(round)를 행할 것이다. div 와 ldiv 는 어떻게 몫에 버림(round)을 할것인 지를 정하기 때문에 유용하다: 소수점 이하를 버린다. 나머지는 numeraotr 과 같은 부호를 갖는다.

이들 함수들은 r.quot*denominator + r.rem 은 numerator 과 같도록 리턴값 r 을 정한다. 이들을 사용하기 위해서, 당신은 당신의 프로그램에 헤더파일 'stdlib.h'를 포함시켜야 한다.

데이터 타입 : div__t

이것은 div 함수에 의해 리턴된 결과를 저장하기 위해 사용되는 구조체형이다. 이것은 다음과 같은 멤버들을 갖는다.

int quot 나눗셈의 몫

int rem 나눗셈의 나머지

함수 : div_t div (int numerator, int denominator)

div함수는 numerator 을 denominator 로 나눈것에서 몫과 나머지를 구하고, 그 결과를 구조체 div_t 에 저장하여 리턴한다. 만일 그 결과가 표현될 수 없다면( 영으로 나누는 것 처럼), 그 결과는 정의 되지 않았다.

유용한 것은 아니지만, 하나의 예를 들면...

div_t result;

result = div (20, -6);

이것의 결과로 나온 result.quot 는 -3 이고 result.rem 은 2이다.

데이터 타입 : ldiv__t

이것은 ldiv 함수에 의해 리턴된 결과를 저장하기 위해 사용되는 구조체이다. 이것은 다음과 같은 멤버들을 갖는다.

long int quot 나눗셈의 몫

long int rem 나눗셈의 나머지

( 이것은 구조체 요소들이 int 형이 아니라 long int 라는 점을 제외하면, div_t 와 동일하다. )

함수 : ldiv_t ldiv (long int numerator, long int denominator)

ldiv 함수는 인수가 long int 형이고, 그 결과가 ldiv 형의 구조체에 리턴된다는 점을 제외하고는, div 함수와 유사하다.

14.7 숫자의 파싱(구문해석 : parsing)

이 절은 문자열로부터 정수와 플로팅 포인트 숫자를 "읽기" 위한 함수들을 설명한다. 그것은 sscanf 또는 그 함수와 연관된 어떤것보다, 어떤 경우에는 사용하기 더 편리할 것이다; 7.11절 [Formatted Input] 85 페이지 참조. 당신이 직접 문자열에서 토큰을 분리해내는 것이 더 안정된 프로 그램을 만드는 경우도 있겠지만, 그러면 그때는 하나하나씩 그 토큰을 숫자로 변경해야만 한다.

14.7.1 정수의 파싱.

이들 함수들은 'stdlib.h'에 선언되어 있다.

함수 : long int strtol (const char *string, char **tailptr, int base)

strtol ("스트링에서 long 으로 ") 함수는 문자열의 처음부분을 long int형으로 리턴된 부호화된 정수 로 바꾼다. 이 함수는 다음과 같이 문자열을 분해하려 시도한다.

o 공백문자(whitespace characters)의 열. 공백문자는 isspace 함수로 알아낼 수 있다( 4.1절 [Classification of Characters] 41 페이지 참조.). 이들 공백문자는 버려진다.

o 임의의 플러스 또는 마이너스 부호('+' 또는 '-').

o 기수가 정해진, 아무런 공백이 없는 숫자들의 열. 만일 기수가 0이면, '0'( 8진수로 정하기 ) 또는 '0x' 나 '0X'( 16진수 ) 로 시작하는 숫자열이 아니한, 십진수로 가정한다. 즉, 같은 구문을 C에서 정 수 상수를 위해 사용한다. 그렇지 않다면 기수는 반드시 2와 35 사이이여야만 한다. 만일 기수가 16 이면, 그 숫자는 '0x' 나 '0X' 로 시작될 것이다.

o 문자열에서 남은 나머지 문자들. 만일 tailptr이 널 포인터가 아니라면, strcol은 *tailptr에 tail을 가 리키는 포인터를 저장한다.

만일 그 문자열이 오직 공백으로만 되어 있거나, 정해진 기수의 정수가 가져야하는 처음의 부문자열 을 포함하지 않는다면, 아무런 변환이 수행되지 않는다. 이 경우, strcol은 0을 리턴하고, *tailptr에 저장된 값은 스트링의 값이다.

표준 "C" 지역이 아닌 다른 지역에서, 이 함수는 그 지역의 구문에 의존되는 부가적인 동작을 인식 할 것이다. 만일 그 문자열이 정수에 맞는 구문을 갖고 있지만 오버플로우 때문에 표현할 수 없다 면, strtol은 그 값의 부호에 알맞는 LONG_MAX 또는 LONG_MIN을 리턴한다(A.5.2절 [Range of Type], 388 페이지 참조.) 또한 오버플로우가 났음을 알리기 위해서 errno를 ERANGE로 설정한다. 이것에 대한 예는 이 절의 마지막에 있다.

함수 : unsigned long int strtoul (const char *string, char **tailptr, int base)

strtoul (" 문자열을 unsigned long 으로 ") 함수는 unsigned long int 형으로 그 값을 리턴한다는 것 을 제외하고는 strtol함수와 같다. 오버플로우가 발생할 경우에 리턴되는 값은 ULONG_MAX 이다 (A.5.2 절 [Range of Type] 388 페이지 참조.)

함수 : long int atol (const char *string)

이 함수는 오버플로우 에러를 검출할 필요가 없다는 점을 제외하고, base 인수로 10을 사용한 strtol 함수와 유사하다. atol 함수는 현존하는 코드와의 호환성을 위해서 제공되었다; strtol이 더 안정적 이다.

함수 : int atoi (const char *string)

이 함수는 long int 가 아닌 int 형으로 값을 리턴한다는 점을 제외하고, atol 함수와 같다. atoi 함 수는 또한 오래된 함수로 간주되므로; strtol 을 대신 사용하라.

이것은 정수로 이어진 문자열을 분석하고 그들의 합을 구하는 함수이다.

int

sum_ints_from_string (char *string)

{

int sum = 0;

while (1) {

char *tail;

int next;

/* 앞이 공백으로 되어 있는 것을 건너뛴다. */

while (isspace (*string)) string++;

if (*string == 0)

break;

/* 공백이 제거되었으므로 숫자로 변경하자 */

errno = 0;

/* 그것을 분석한다. */

next = strtol (string, &tail, 0);

/* 만일 오버플로우가 발생하지 않았다면, 그것을 더해라 */

if (errno)

printf ("Overflow\n");

else

sum += next;

/* 다음 분석을 위해서 지금 현재까지 분석한 위치를 저장해놓는다. */

string = tail;

}

return sum;

}

14.7.2 플로트의 파싱.

이곳에 있는 함수들은 'stdlib.h'에 선언되어 있다.

함수 : double strtol (const char *string, char **tailptr)

strtol ("문자열을 double 로") 함수는 문자열의 처음부분을 double형을 가진 플로팅-포인트 수로 변 환한다. 이 함수는 다음의 경우에 문자열을 분해하려 시도한다.

o 연속적인 공백문자들. 공백문자(whitespace characters)들은 isspace 함수( 4.1절 [Classification of Characters] 41 페이지 참조. ) 의 사용으로 알아낼 수 있다. 공백은 버려진다.

o 임의의 플러스나 마이너스 부호 ( '+' 또는 '-')

o 소수점(보통 '.')을 포함하고 있는 공백없는 숫자열, 그러나 소수점의 위치에 의존한다. (19.6절 [Numeric Formatting] 262페이지 참조.)

o 문자 임의의 부호 'e' 또는 'E', 그리고 숫자들의 열로 구성된 지수부분.

o 문자열의 나머지 문자. 만약 tailptr이 널 포인터가 아니라면, 스트링의 tail 포인터를 *tailptr에 저 장된다.

만일 그 문자열이 비어있거나, 오직 공백만 있거나, 또는 플로팅-포인트로 판단할만한 문자열을 포 함하지 않다면, 아무런 변환이 일어나지 않는다. 이 경우, strtod는 0을 리턴하고, *tailptr에 리턴된 값은 문자열의 값이다.

표준 "C" 와는 다른 지역이라면, 이 함수는 그 지역의 구문에 의존하는 부가적 작동들을 인식할 것 이다.

만일 그 문자열이 플로팅-포인트 숫자를 이루기 위한 유용한 구문을 갖고 있지만, 그 값을 오버플로 우 때문에 표현할 수 없다면, strtod는 그 값의 부호에 의존해서, 음이나 양의 HUGE_VAL을 리턴 한다. ( 13장. [Mathematics] 203 페이지 참조.). 유사하게, 만일 그 값이 언더플로우(underflow) 때 문에 표현할 수 없다면, strtod는 0을 리턴한다. 그것은 또한 오버플로우나 언더플로우의 경우에 errno를 ERANGE 로 설정한다.

함수 : double atof (const char *string)

이 함수는 오버플로우와 언더플로우 에러를 검출할 필요가 없다는 점을 제외하고는, strtod 함수와 유사하다. atof 함수는 현존하는 코드와의 호환성을 위해서 제공된다; strtod를 사용하는 것이 더 안전성이 있다.