Przejdź do zawartości

C/fpclassify

Z Wikibooks, biblioteki wolnych podręczników.
< C

Deklaracja

[edytuj]
int 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

[edytuj]

math.h

Argumenty

[edytuj]
x
wartość do sprawdzenia

Opis

[edytuj]

Funkcje (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

[edytuj]

isnan

[edytuj]

Sprawdzanie zakresu :

double x, r; 

if (isnan(x) || islessequal(x, 0)) 

  { /* Deal with NaN / pole error / domain error */ }

r = log(x);


Klasyfikacja liczb

[edytuj]

Program 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

[edytuj]

Funkcja 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]
  1. | Rudimentary test program for floating-point classification
  2. delftstack :infinity-in-c by Abdul Mateen Oct-26, 2022