From 2cc4af230b9c35894b9e6e3515681c0a313ad3cc Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 23 Jul 2008 21:48:35 -0700 Subject: [PATCH] Add isinf module. --- ChangeLog | 16 +++ MODULES.html.sh | 1 + doc/posix-functions/isinf.texi | 8 +- lib/isinf.c | 37 ++++++ lib/math.in.h | 16 +++ m4/isinf.m4 | 49 ++++++++ m4/math_h.m4 | 2 + modules/isinf | 27 +++++ modules/isinf-tests | 21 ++++ modules/math | 2 + tests/test-isinf.c | 249 +++++++++++++++++++++++++++++++++++++++++ 11 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 lib/isinf.c create mode 100644 m4/isinf.m4 create mode 100644 modules/isinf create mode 100644 modules/isinf-tests create mode 100644 tests/test-isinf.c diff --git a/ChangeLog b/ChangeLog index e7770eff9..80815bd20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2008-07-14 Ben Pfaff + Add isinf module. + * lib/isinf.c: New file. + * lib/math.in.h: Define isinf macro if we have decided to replace + it. + * m4/isinf.m4: New file. + * m4/math_h.m4: Initialize and substitute variables for isinf + module. + * modules/isinf: New file. + * modules/isinf-tests: New file. + * modules/math: Add substitutions for new module. + * tests/test-isinf.c: New file. + * doc/posix-functions/isinf.texi: Mention new module. + * MODULES.html.sh: Mention new module. + +2008-07-14 Ben Pfaff + Factor out some macros for use by additional modules. * m4/isnanf.m4 (gl_FLOAT_EXPONENT_LOCATION): Move into new file exponentf.m4. diff --git a/MODULES.html.sh b/MODULES.html.sh index 7b771ef13..bf0f5e9f5 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2000,6 +2000,7 @@ func_all_modules () func_module frexpl func_module frexpl-nolibm func_module isfinite + func_module isinf func_module isnan func_module isnanf func_module isnanf-nolibm diff --git a/doc/posix-functions/isinf.texi b/doc/posix-functions/isinf.texi index 8377f4fea..19e793bf1 100644 --- a/doc/posix-functions/isinf.texi +++ b/doc/posix-functions/isinf.texi @@ -4,15 +4,15 @@ POSIX specification: @url{http://www.opengroup.org/susv3xsh/isinf.html} -Gnulib module: --- +Gnulib module: isinf Portability problems fixed by Gnulib: @itemize +@item +This macro is missing on some platforms: +AIX 4.3.2, IRIX 6.5, OSF/1 5.1, Solaris 10. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -AIX 4.3.2, IRIX 6.5, OSF/1 5.1, Solaris 10. @end itemize diff --git a/lib/isinf.c b/lib/isinf.c new file mode 100644 index 000000000..56ca9ae1d --- /dev/null +++ b/lib/isinf.c @@ -0,0 +1,37 @@ +/* Test for positive or negative infinity. + Copyright (C) 2007-2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Ben Pfaff , 2008. */ + +#include + +#include + +int gl_isinff (float x) +{ + return x < -FLT_MAX || x > FLT_MAX; +} + +int gl_isinfd (double x) +{ + return x < -DBL_MAX || x > DBL_MAX; +} + +int gl_isinfl (long double x) +{ + return x < -LDBL_MAX || x > LDBL_MAX; +} diff --git a/lib/math.in.h b/lib/math.in.h index 85f37855c..4ff8fc964 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -381,6 +381,22 @@ extern int gl_isfinitel (long double x); #endif +#if @GNULIB_ISINF@ +# if @REPLACE_ISINF@ +extern int gl_isinff (float x); +extern int gl_isinfd (double x); +extern int gl_isinfl (long double x); +# undef isinf +# define isinf(x) \ + (sizeof (x) == sizeof (long double) ? gl_isinfl (x) : \ + sizeof (x) == sizeof (double) ? gl_isinfd (x) : \ + gl_isinff (x)) +# endif +#elif defined GNULIB_POSIXCHECK + /* How to override a macro? */ +#endif + + #if @GNULIB_ISNAN@ # if @REPLACE_ISNAN@ /* We can't just use the isnanf macro (e.g.) as exposed by diff --git a/m4/isinf.m4 b/m4/isinf.m4 new file mode 100644 index 000000000..1b9e45a54 --- /dev/null +++ b/m4/isinf.m4 @@ -0,0 +1,49 @@ +# isinf.m4 serial 1 +dnl Copyright (C) 2007-2008 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_ISINF], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + dnl Persuade glibc to declare isinf. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_CHECK_DECLS([isinf], , , [#include ]) + if test "$ac_cv_have_decl_isinf" = yes; then + gl_CHECK_MATH_LIB([ISINF_LIBM], [x = isinf (x);]) + if test "$ISINF_LIBM" != missing; then + dnl Test whether isinf() on 'long double' works. + gl_ISINFL_WORKS + case "$gl_cv_func_isinfl_works" in + *yes) ;; + *) ISINF_LIBM=missing;; + esac + fi + fi + if test "$ac_cv_have_decl_isinf" != yes || + test "$ISINF_LIBM" = missing; then + REPLACE_ISINF=1 + AC_LIBOBJ([isinf]) + ISINF_LIBM= + fi + AC_SUBST([REPLACE_ISINF]) + AC_SUBST([ISINF_LIBM]) +]) + +dnl Test whether isinf() correctly returns false for LDBL_MAX. +AC_DEFUN([gl_ISINFL_WORKS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_C_BIGENDIAN]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether isinf(long double) works], [gl_cv_func_isinfl_works], + [ + AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[return !!isinf(LDBL_MAX);]])], + [gl_cv_func_isinfl_works=yes], + [gl_cv_func_isinfl_works=no], + [gl_cv_func_isinfl_works="guessing no"]) + ]) +]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 0348f24be..b7a273860 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -51,6 +51,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_FREXP=0; AC_SUBST([GNULIB_FREXP]) GNULIB_FREXPL=0; AC_SUBST([GNULIB_FREXPL]) GNULIB_ISFINITE=0; AC_SUBST([GNULIB_ISFINITE]) + GNULIB_ISINF=0; AC_SUBST([GNULIB_ISINF]) GNULIB_ISNAN=0; AC_SUBST([GNULIB_ISNAN]) GNULIB_LDEXPL=0; AC_SUBST([GNULIB_LDEXPL]) GNULIB_MATHL=0; AC_SUBST([GNULIB_MATHL]) @@ -83,6 +84,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_HUGE_VAL=0; AC_SUBST([REPLACE_HUGE_VAL]) REPLACE_ISFINITE=0; AC_SUBST([REPLACE_ISFINITE]) + REPLACE_ISINF=0; AC_SUBST([REPLACE_ISINF]) REPLACE_ISNAN=0; AC_SUBST([REPLACE_ISNAN]) REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL]) REPLACE_NAN=0; AC_SUBST([REPLACE_NAN]) diff --git a/modules/isinf b/modules/isinf new file mode 100644 index 000000000..c5e4dbd0b --- /dev/null +++ b/modules/isinf @@ -0,0 +1,27 @@ +Description: +isinf macro: test for positive or negative infinity + +Files: +lib/isinf.c +m4/isinf.m4 +m4/check-math-lib.m4 + +Depends-on: +float +math +extensions + +configure.ac: +gl_ISINF +gl_MATH_MODULE_INDICATOR([isinf]) + +Makefile.am: + +Include: + + +License: +GPL + +Maintainer: +Ben Pfaff diff --git a/modules/isinf-tests b/modules/isinf-tests new file mode 100644 index 000000000..8e15f659e --- /dev/null +++ b/modules/isinf-tests @@ -0,0 +1,21 @@ +Files: +m4/exponentf.m4 +m4/exponentd.m4 +m4/exponentl.m4 +tests/test-isinf.c + +Depends-on: +float + +configure.ac: +gl_FLOAT_EXPONENT_LOCATION +gl_DOUBLE_EXPONENT_LOCATION +gl_LONG_DOUBLE_EXPONENT_LOCATION + +Makefile.am: +TESTS += test-isinf +check_PROGRAMS += test-isinf +test_isinf_LDADD = $(LDADD) @ISINF_LIBM@ + +License: +GPL diff --git a/modules/math b/modules/math index 4be850150..20ec1d670 100644 --- a/modules/math +++ b/modules/math @@ -29,6 +29,7 @@ math.h: math.in.h -e 's|@''GNULIB_FREXP''@|$(GNULIB_FREXP)|g' \ -e 's|@''GNULIB_FREXPL''@|$(GNULIB_FREXPL)|g' \ -e 's|@''GNULIB_ISFINITE''@|$(GNULIB_ISFINITE)|g' \ + -e 's|@''GNULIB_ISINF''@|$(GNULIB_ISINF)|g' \ -e 's|@''GNULIB_ISNAN''@|$(GNULIB_ISNAN)|g' \ -e 's|@''GNULIB_LDEXPL''@|$(GNULIB_LDEXPL)|g' \ -e 's|@''GNULIB_MATHL''@|$(GNULIB_MATHL)|g' \ @@ -60,6 +61,7 @@ math.h: math.in.h -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_HUGE_VAL''@|$(REPLACE_HUGE_VAL)|g' \ -e 's|@''REPLACE_ISFINITE''@|$(REPLACE_ISFINITE)|g' \ + -e 's|@''REPLACE_ISINF''@|$(REPLACE_ISINF)|g' \ -e 's|@''REPLACE_ISNAN''@|$(REPLACE_ISNAN)|g' \ -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \ -e 's|@''REPLACE_NAN''@|$(REPLACE_NAN)|g' \ diff --git a/tests/test-isinf.c b/tests/test-isinf.c new file mode 100644 index 000000000..43c77ada1 --- /dev/null +++ b/tests/test-isinf.c @@ -0,0 +1,249 @@ +/* Test of isinf() substitute. + Copyright (C) 2007-2008 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Ben Pfaff, 2008, using Bruno Haible's code as a + template. */ + +#include + +#include +#include +#include + +#include +#include + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +float zerof = 0.0f; +double zerod = 0.0; +long double zerol = 0.0L; + +static void +test_isinff () +{ + /* Zero. */ + ASSERT (!isinf (0.0f)); + /* Subnormal values. */ + ASSERT (!isinf (FLT_MIN / 2)); + ASSERT (!isinf (-FLT_MIN / 2)); + /* Finite values. */ + ASSERT (!isinf (3.141f)); + ASSERT (!isinf (3.141e30f)); + ASSERT (!isinf (3.141e-30f)); + ASSERT (!isinf (-2.718f)); + ASSERT (!isinf (-2.718e30f)); + ASSERT (!isinf (-2.718e-30f)); + ASSERT (!isinf (FLT_MAX)); + ASSERT (!isinf (-FLT_MAX)); + /* Infinite values. */ + ASSERT (isinf (1.0f / 0.0f)); + ASSERT (isinf (-1.0f / 0.0f)); + /* Quiet NaN. */ + ASSERT (!isinf (zerof / zerof)); +#if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { float value; unsigned int word[NWORDS]; } memory_float; + memory_float m; + m.value = zerof / zerof; +# if FLT_EXPBIT0_BIT > 0 + m.word[FLT_EXPBIT0_WORD] ^= (unsigned int) 1 << (FLT_EXPBIT0_BIT - 1); +# else + m.word[FLT_EXPBIT0_WORD + (FLT_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + if (FLT_EXPBIT0_WORD < NWORDS / 2) + m.word[FLT_EXPBIT0_WORD + 1] |= (unsigned int) 1 << FLT_EXPBIT0_BIT; + else + m.word[0] |= (unsigned int) 1; + ASSERT (!isinf (m.value)); + #undef NWORDS + } +#endif +} + +static void +test_isinfd () +{ + /* Zero. */ + ASSERT (!isinf (0.0)); + /* Subnormal values. */ + ASSERT (!isinf (DBL_MIN / 2)); + ASSERT (!isinf (-DBL_MIN / 2)); + /* Finite values. */ + ASSERT (!isinf (3.141)); + ASSERT (!isinf (3.141e30)); + ASSERT (!isinf (3.141e-30)); + ASSERT (!isinf (-2.718)); + ASSERT (!isinf (-2.718e30)); + ASSERT (!isinf (-2.718e-30)); + ASSERT (!isinf (DBL_MAX)); + ASSERT (!isinf (-DBL_MAX)); + /* Infinite values. */ + ASSERT (isinf (1.0 / 0.0)); + ASSERT (isinf (-1.0 / 0.0)); + /* Quiet NaN. */ + ASSERT (!isinf (zerod / zerod)); +#if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { double value; unsigned int word[NWORDS]; } memory_double; + memory_double m; + m.value = zerod / zerod; +# if DBL_EXPBIT0_BIT > 0 + m.word[DBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (DBL_EXPBIT0_BIT - 1); +# else + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << DBL_EXPBIT0_BIT; + ASSERT (!isinf (m.value)); + #undef NWORDS + } +#endif +} + +static void +test_isinfl () +{ + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { unsigned int word[NWORDS]; long double value; } + memory_long_double; + + /* Zero. */ + ASSERT (!isinf (0.0L)); + /* Subnormal values. */ + ASSERT (!isinf (LDBL_MIN / 2)); + ASSERT (!isinf (-LDBL_MIN / 2)); + /* Finite values. */ + ASSERT (!isinf (3.141L)); + ASSERT (!isinf (3.141e30L)); + ASSERT (!isinf (3.141e-30L)); + ASSERT (!isinf (-2.718L)); + ASSERT (!isinf (-2.718e30L)); + ASSERT (!isinf (-2.718e-30L)); + ASSERT (!isinf (LDBL_MAX)); + ASSERT (!isinf (-LDBL_MAX)); + /* Infinite values. */ + ASSERT (isinf (1.0L / 0.0L)); + ASSERT (isinf (-1.0L / 0.0L)); + /* Quiet NaN. */ + ASSERT (!isinf (zerol / zerol)); + +#if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + /* A bit pattern that is different from a Quiet NaN. With a bit of luck, + it's a Signalling NaN. */ + { + memory_long_double m; + m.value = zerol / zerol; +# if LDBL_EXPBIT0_BIT > 0 + m.word[LDBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (LDBL_EXPBIT0_BIT - 1); +# else + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << LDBL_EXPBIT0_BIT; + ASSERT (!isinf (m.value)); + } +#endif + +#if ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_)) +/* Representation of an 80-bit 'long double' as an initializer for a sequence + of 'unsigned int' words. */ +# ifdef WORDS_BIGENDIAN +# define LDBL80_WORDS(exponent,manthi,mantlo) \ + { ((unsigned int) (exponent) << 16) | ((unsigned int) (manthi) >> 16), \ + ((unsigned int) (manthi) << 16) | (unsigned int) (mantlo) >> 16), \ + (unsigned int) (mantlo) << 16 \ + } +# else +# define LDBL80_WORDS(exponent,manthi,mantlo) \ + { mantlo, manthi, exponent } +# endif + { /* Quiet NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0xC3333333, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + { + /* Signalling NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x83333333, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + /* The isnanl function should recognize Pseudo-NaNs, Pseudo-Infinities, + Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals, as defined in + Intel IA-64 Architecture Software Developer's Manual, Volume 1: + Application Architecture. + Table 5-2 "Floating-Point Register Encodings" + Figure 5-6 "Memory to Floating-Point Register Data Translation" + */ + { /* Pseudo-NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x40000001, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + { /* Pseudo-Infinity. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x00000000, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + { /* Pseudo-Zero. */ + static memory_long_double x = + { LDBL80_WORDS (0x4004, 0x00000000, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + { /* Unnormalized number. */ + static memory_long_double x = + { LDBL80_WORDS (0x4000, 0x63333333, 0x00000000) }; + ASSERT (!isinf (x.value)); + } + { /* Pseudo-Denormal. */ + static memory_long_double x = + { LDBL80_WORDS (0x0000, 0x83333333, 0x00000000) }; + ASSERT (!isinf (x.value)); + } +#endif + + #undef NWORDS +} + +int +main () +{ + test_isinff (); + test_isinfd (); + test_isinfl (); + return 0; +} -- 2.11.0