14 저수준 연산 함수들


14. 1 "숫자가 아닌" 값들

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

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

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] 에서 hypot 함수를 참조하라. )
그 값은 : sqrt (z. real*z. real + z. imag*z. imag)


14. 4 표준화 함수들

이 절에서 설명된 함수들은, 내부적으로 2진 기수(binary radix)를 사용하여 표현되는, 플로팅 포인트에서 일어나는 저-수준 동작들을 효율적으로 수행하기 위한 방법을 제공한다; A. 5. 3. 1절 [Floating Point Comcepts] 참조. 이들 함수들은 만일 어떤 표현이 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] 에서 다양한 라운딩모드들에 대한 정보를 참조하라. 디폴트 라운딩 모드는 가장 근접한 수로 만드는 것이다. 어떤 기계에서는 다른 모드를 지원하지만, 가장 근접한수로의 라운딩(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] 참조. 당신이 직접 문자열에서 토큰을 분리해 내는 것이 더 안정된 프로그램을 만드는 경우도 있겠지만, 그러면 그때는 하나씩 그 토큰을 숫자로 변경해야만 한다.

14. 7. 1 정수의 파싱

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

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

strtol ("스트링에서 long 으로 ") 함수는 문자열의 처음부분을 long int형으로 반환된 부호화된 정수로 바꾼다. 이 함수는 다음과 같이 문자열을 분해하려 시도한다.
공백문자(whitespace characters)의 열. 공백문자는 isspace 함수로 알아낼 수 있다( 4. 1절 [Classification of Characters] 참조. ). 이들 공백문자는 버려진다.
임의의 플러스 또는 마이너스 부호('+' 또는 '-').
기수가 정해진, 아무런 공백이 없는 숫자들의 열. 만일 기수가 0이면, '0'( 8진수로 정하기 ) 또는 '0x' 나 '0X'( 16진수 ) 로 시작하는 숫자열이 아니한, 십진수로 가정한다. 즉, 같은 구문을 C에서 정수 상수를 위해 사용한다. 그렇지 않다면 기수는 반드시 2와 35 사이여야만 한다. 만일 기수가 16이면, 그 숫자는 '0x' 나 '0X' 로 시작될 것이다.
문자열에서 남은 나머지 문자들. 만일 tailptr이 널 포인터가 아니라면, strcol은 *tailptr에 tail을 가리키는 포인터를 저장한다.
만일 그 문자열이 오직 공백으로만 되어 있거나, 정해진 기수의 정수가 가져야하는 처음의 부문자열을 포함하지 않는다면, 아무런 변환이 수행되지 않는다. 이 경우, strcol은 0을 반환하고, *tailptr에 저장된 값은 스트링의 값이다.
표준 "C" 지역이 아닌 다른 지역에서, 이 함수는 그 지역의 구문에 의존되는 부가적인 동작을 인식할 것이다. 만일 그 문자열이 정수에 맞는 구문을 갖고 있지만 오버플로우 때문에 표현할 수 없다면, strtol은 그 값의 부호에 알맞은 LONG_MAX 또는 LONG_MIN을 반환한다(A. 5. 2절 [Range of Type] 참조. ) 또한 오버플로우가 났음을 알리기 위해서 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] 참조. )

함수 : 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형을 가진 플로팅-포인트 수로 변환한다. 이 함수는 다음의 경우에 문자열을 분해하려 시도한다.
연속적인 공백문자들. 공백문자(whitespace characters)들은 isspace 함수( 4. 1절 [Classification of Characters] 참조. ) 의 사용으로 알아낼 수 있다. 공백은 버려진다.
임의의 플러스나 마이너스 부호 ( '+' 또는 '-') , 소수점(보통 '. ')을 포함하고 있는 공백 없는 숫자열, 그러나 소수점의 위치에 의존한다. (19. 6절 [Numeric Formatting] 참조. )
문자 임의의 부호 'e' 또는 'E', 그리고 숫자들의 열로 구성된 지수부분.
문자열의 나머지 문자. 만약 tailptr이 널 포인터가 아니라면, 스트링의 tail 포인터를 *tailptr에 저장된다.
만일 그 문자열이 비어있거나, 오직 공백만 있거나, 또는 플로팅-포인트로 판단할만한 문자열을 포함하지 않다면, 아무런 변환이 일어나지 않는다. 이 경우, strtod는 0을 반환하고, *tailptr에 반환된 값은 문자열의 값이다.
표준 "C" 와는 다른 지역이라면, 이 함수는 그 지역의 구문에 의존하는 부가적 작동들을 인식할 것이다.
만일 그 문자열이 플로팅-포인트 숫자를 이루기 위한 유용한 구문을 갖고 있지만, 그 값을 오버플로우 때문에 표현할 수 없다면, strtod는 그 값의 부호에 의존해서, 음이나 양의 HUGE_VAL을 반환한다. ( 13장. [Mathematics] 참조. ). 유사하게, 만일 그 값이 언더플로우(underflow) 때문에 표현할 수 없다면, strtod는 0을 반환한다. 그것은 또한 오버플로우나 언더플로우의 경우에 errno를 ERANGE 로 설정한다.

함수 : double atof (const char *string)

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