Deklaracja
edytujint fpclassify(floating-type x); int isfinite (floating-type x); int isinf (floating-type x); int isnan (floating-type x); int isnormal (floating-type x); int signbit (floating-type x); #define FP_INFINITE wartość #define FP_NAN wartość #define FP_NORMAL wartość #define FP_SUBNORMAL wartość #define FP_ZERO wartość
// from /usr/include/math.h
/* ISO C99 defines some generic macros which work on any data type. */
#ifdef __USE_ISOC99
/* All floating-point numbers can be put in one of these categories. */
enum
{
FP_NAN =
# define FP_NAN 0
FP_NAN,
FP_INFINITE =
# define FP_INFINITE 1
FP_INFINITE,
FP_ZERO =
# define FP_ZERO 2
FP_ZERO,
FP_SUBNORMAL =
# define FP_SUBNORMAL 3
FP_SUBNORMAL,
FP_NORMAL =
# define FP_NORMAL 4
FP_NORMAL
};
Plik nagłówkowy
edytujArgumenty
edytuj- x
- wartość do sprawdzenia
Opis
edytujFunkcje (w zasadzie makra) klasyfikują wartość podaną jako argument. Są to makra, które przyjmują jako argumenty zmienne dowolnych typów zmiennoprzecinkowych.
Stałe FP_* określają wartości zwracane przez funkcję fpclassify. Konkretne implementacje mogą definiować własne stałe zaczynające się od FP_ i wielkiej litery określające inne klasyfikacje liczb.
Wartość zwracana
edytuj- fpclassify - klasyfikuje wartość argumentu i zwraca jedną z wartości określonych przez makra FP_INFINITE, FP_NAN, FP_NORMAL, FP_SUBNORMAL, FP_ZERO lub inne makra FP_* zależne od implementacji,[1]
- isfinite - zwraca wartość niezerową jeżeli argument jest liczbą skończoną,
- isinf - zwraca wartość niezerową jeżeli argument jest liczbą nieskończoną,[2]
- isnan - zwraca wartośc niezerową jeżeli argument reprezentuje wartość NaN,
- isnormal - zwraca wartość niezerową jeżeli argument reprezentuje zwykłą liczbę rzeczywitą,
- signbit - zwraca wartość niezerową jeżeli znak argumentu jest ujemny.
Przykład użycia
edytujisnan
edytujSprawdzanie zakresu :
double x, r;
if (isnan(x) || islessequal(x, 0))
{ /* Deal with NaN / pole error / domain error */ }
r = log(x);
Klasyfikacja liczb
edytujProgram klasyfikuje liczby zmiennoprzecinkowe podane w formie binarnej jako argumenty.
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
void wyswietl_liczbe(char* s) {
union {
uint32_t bin; /* binarna reprezentacja */
float zmiennoprzecinkowa; /* liczby zmiennoprzecinkowej */
} liczba;
liczba.bin = 0;
liczba.bin = strtoul(s, NULL, 0); /* tutaj bez sprawdzania błędów, domyślnie zero */
switch (fpclassify(liczba.zmiennoprzecinkowa)) {
case FP_NAN:
printf("0x%08x => NaN (nie liczba)\n", liczba.bin);
break;
case FP_INFINITE:
printf("0x%08x => nieskończoność\n", liczba.bin);
break;
case FP_ZERO:
printf("0x%08x => zero\n", liczba.bin);
break;
case FP_SUBNORMAL:
printf("0x%08x => liczba zdenormalizowana\n", liczba.bin);
break;
case FP_NORMAL:
printf("0x%08x => liczba o wartości %f\n",
liczba.bin,
liczba.zmiennoprzecinkowa
);
break;
}
}
int main(int argc, char* argv[]) {
int i;
if (argc < 2) {
fprintf(
stderr,
"Podaj liczby szesnastkowe, które zostaną zainterpretowane jako "
"liczba zmiennoprzecinkowa pojedynczej precyzji\n"
);
return EXIT_FAILURE;
}
else
for (i=1; i < argc; i++)
wyswietl_liczbe(argv[i]);
return EXIT_SUCCESS;
}
Przykład działania:
$ program 0 0x7f800000 0x7fc00000 0xbadcafe0 0xdeedbeef 1 0x00000000 => zero 0x7f800000 => nieskończoność 0x7fc00000 => NaN (nie liczba) 0xbadcafe0 => liczba o wartości -0.001684 0xdeedbeef => liczba o wartości -8565696407921491968.000000 0x00000001 => liczba zdenormalizowana
Sprawdzanie typu i znaku
edytuj/*
http://homepages.cs.ncl.ac.uk/nick.cook/csc2025/minix/3.2.1/usr/src/test/test47.c
by Nick Cook
gcc f.c -Wall -lm
./a.out >r.txt
*/
#include <math.h> // fpclassify
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
/* Maximum normal double: (2 - 2^(-53)) * 2^1023 */
#define NORMAL_DOUBLE_MAX DBL_MAX // = 1.797693134862315708145274237317e+308
/* Minimum normal double: 2^(-1022) */
#define NORMAL_DOUBLE_MIN DBL_MIN // = 2.2250738585072013830902327173324e-308
/* Maximum subnormal double: (1 - 2^(-53)) * 2^(-1022) */
#define SUBNORMAL_DOUBLE_MAX 2.2250738585072008890245868760859e-308
/* Minimum subnormal double: 2^(-52) * 2^(-1023) */
#define SUBNORMAL_DOUBLE_MIN 4.9406564584124654417656879286822e-324
static int test_fpclassify(double value, int class)
{
/* test fpclassify */
if (fpclassify(value) != class) {printf("%.16e class bad,", value); }
else printf("%.16e class good,", value);
if (fpclassify(-value) != class) {printf(" bad class of - value ");return 102;}
/* test signbit */
if (signbit(value)) {printf("sign neg \n"); return 103;} // return a non-zero value if and only if the sign of its argument value is negative.
else {printf("sign pos \n"); return 104;}
if (!signbit(-value)) return 105;
return 0;
}
static void test_fpclassify_values(void)
{
double d;
printf(" test some corner cases for fpclassify and signbit \n\n");
test_fpclassify(NAN, FP_NAN);
test_fpclassify(INFINITY, FP_INFINITE);
test_fpclassify(NORMAL_DOUBLE_MAX, FP_NORMAL);
test_fpclassify(1, FP_NORMAL);
test_fpclassify(NORMAL_DOUBLE_MIN, FP_NORMAL);
test_fpclassify(SUBNORMAL_DOUBLE_MAX, FP_SUBNORMAL);
test_fpclassify(SUBNORMAL_DOUBLE_MIN, FP_SUBNORMAL);
test_fpclassify(0, FP_ZERO);
printf("\n test other small numbers for fpclassify and signbit \n");
d = 1;
while (d >= NORMAL_DOUBLE_MIN)
{
test_fpclassify(d, FP_NORMAL);
d /= 10;
}
while (d >= SUBNORMAL_DOUBLE_MIN)
{
test_fpclassify(d, FP_SUBNORMAL);
d /= 10;
}
test_fpclassify(d, FP_ZERO);
/* test other large numbers for fpclassify and signbit */
d = 1;
while (d <= NORMAL_DOUBLE_MAX / 10)
{
test_fpclassify(d, FP_NORMAL);
d *= 10;
}
}
int main()
{
/* test various floating point support functions */
test_fpclassify_values();
return 0;
}
Wynik :
test some corner cases for fpclassify and signbit nan class good,sign pos inf class good,sign pos 1.7976931348623157e+308 class good,sign pos 1.0000000000000000e+00 class good,sign pos 2.2250738585072014e-308 class good,sign pos 2.2250738585072009e-308 class good,sign pos 4.9406564584124654e-324 class good,sign pos 0.0000000000000000e+00 class good,sign pos test other small numbers for fpclassify and signbit 1.0000000000000000e+00 class good,sign pos 1.0000000000000001e-01 class good,sign pos 1.0000000000000000e-02 class good,sign pos 1.0000000000000000e-03 class good,sign pos 1.0000000000000000e-04 class good,sign pos 1.0000000000000001e-05 class good,sign pos 1.0000000000000002e-06 class good,sign pos ... 9.9998886718268301e-321 class good,sign pos 9.9801260459931802e-322 class good,sign pos 9.8813129168249309e-323 class good,sign pos 9.8813129168249309e-324 class good,sign pos 0.0000000000000000e+00 class good,sign pos 1.0000000000000000e+00 class good,sign pos 1.0000000000000000e+01 class good,sign pos 1.0000000000000000e+02 class good,sign pos 1.0000000000000000e+03 class good,sign pos 1.0000000000000000e+04 class good,sign pos 1.0000000000000000e+05 class good,sign pos 1.0000000000000000e+06 class good,sign pos 1.0000000000000000e+07 class good,sign pos 1.0000000000000000e+08 class good,sign pos 1.0000000000000000e+09 class good,sign pos 1.0000000000000000e+10 class good,sign pos 1.0000000000000000e+11 class good,sign pos ... 1.0000000000000002e+301 class good,sign pos 1.0000000000000001e+302 class good,sign pos 1.0000000000000000e+303 class good,sign pos 9.9999999999999994e+303 class good,sign pos 9.9999999999999994e+304 class good,sign pos 9.9999999999999986e+305 class good,sign pos 9.9999999999999986e+306 class good,sign pos
Uwagi
edytujFunkcja została dodana do języka w standardzie C99.
W przypadku użycia funkcji matematycznych może zaistnieć konieczność podania odpowiedniego argumentu linkerowi, aby ten połączył program z biblioteką matematyczną. Np. na systemach GNU/Linux jest to -lm.
Wartości stałych są liczbami całkowitymi ( niekoniecznie zgodnymi z naszymi oczekiwaniami) :
#include <stdio.h>
#include <math.h> // fpclassify
int main(void)
{
printf(" p = %d \n",FP_ZERO);
printf(" p = %f \n",(double)FP_ZERO);
return 0;
}
przykładowy wynik :
p = 2
p = 2.000000
Zobacz też
edytuj- matherr
Odnośniki
edytuj- ↑ | Rudimentary test program for floating-point classification
- ↑ delftstack :infinity-in-c by Abdul Mateen Oct-26, 2022