From: Ben Pfaff Date: Sun, 28 Oct 2007 05:12:07 +0000 (-0700) Subject: Implement 'isfinite' module. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e74e1f1540f02fc57e442a6281c62f9594af15e5;p=pspp Implement 'isfinite' module. --- diff --git a/ChangeLog b/ChangeLog index 04b696f296..847b76a567 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2007-10-27 Ben Pfaff + + * lib/math.in.h: Define isfinite macro and prototypes for + gl_isfinitef, gl_isfinited, gl_isfinitel if we are providing + implementations. + * m4/math_h.m4: New substitutions for isfinite module. + * lib/isfinite.c: New file. + * m4/isfinite.m4: New file. + * modules/math: Replace isfinite-related @VARS@ in math.in.h. + * modules/isfinite: New file. + * modules/isfinite-tests: New file. + * tests/tests-isfinite.c: New file. + * doc/functions/isfinite.texi: Mention isfinite module. + * MODULES.html.sh: Mention new module. + 2007-10-27 Ben Pfaff Ralf Wildenhues reported that Tru64 4.0D declares the round diff --git a/MODULES.html.sh b/MODULES.html.sh index 11c4e3e3ae..3f353a7793 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1970,6 +1970,7 @@ func_all_modules () func_module frexp func_module frexpl func_module frexpl-nolibm + func_module isfinite func_module isnan-nolibm func_module isnanf-nolibm func_module isnanl diff --git a/doc/functions/isfinite.texi b/doc/functions/isfinite.texi index 2b777a653f..50d0a7c319 100644 --- a/doc/functions/isfinite.texi +++ b/doc/functions/isfinite.texi @@ -4,15 +4,18 @@ POSIX specification: @url{http://www.opengroup.org/susv3xsh/isfinite.html} -Gnulib module: --- +Gnulib module: isfinite Portability problems fixed by Gnulib: @itemize +@item +This macro is missing on some platforms: +MacOS X 10.3, OpenBSD 3.8, AIX 5.1, IRIX 6.5, OSF/1 5.1, Solaris 10, Interix 3.5. @end itemize Portability problems not fixed by Gnulib: @itemize @item -This function is missing on some platforms: -MacOS X 10.3, OpenBSD 3.8, AIX 5.1, IRIX 6.5, OSF/1 5.1, Solaris 10, Interix 3.5. +It is implementation-dependent whether @code{isfinite} raises an +exception given a signaling NaN operand. @end itemize diff --git a/lib/isfinite.c b/lib/isfinite.c new file mode 100644 index 0000000000..84dcd175aa --- /dev/null +++ b/lib/isfinite.c @@ -0,0 +1,39 @@ +/* Test for finite value (zero, subnormal, or normal, and not infinite or NaN). + Copyright (C) 2007 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 , 2007. */ + +#include + +#include "isnan.h" +#include "isnanf.h" +#include "isnanl-nolibm.h" + +int gl_isfinitef (float x) +{ + return !isnanf (x) && x - x == 0.f; +} + +int gl_isfinited (double x) +{ + return !isnan (x) && x - x == 0.; +} + +int gl_isfinitel (long double x) +{ + return !isnanl (x) && x - x == 0.L; +} diff --git a/lib/math.in.h b/lib/math.in.h index c0f77705b8..9e48ce14d1 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -337,6 +337,20 @@ extern long double truncl (long double x); truncl (x)) #endif +#if @GNULIB_ISFINITE@ +# if !@HAVE_DECL_ISFINITE@ +extern int gl_isfinitef (float x); +extern int gl_isfinited (double x); +extern int gl_isfinitel (long double x); +# undef isfinite +# define isfinite(x) \ + (sizeof (x) == sizeof (long double) ? gl_isfinitel (x) : \ + sizeof (x) == sizeof (double) ? gl_isfinited (x) : \ + gl_isfinitef (x)) +# endif +#elif defined GNULIB_POSIXCHECK + /* How to override a macro? */ +#endif #if @GNULIB_SIGNBIT@ # if @REPLACE_SIGNBIT@ diff --git a/m4/isfinite.m4 b/m4/isfinite.m4 new file mode 100644 index 0000000000..e87fb8e288 --- /dev/null +++ b/m4/isfinite.m4 @@ -0,0 +1,24 @@ +# isfinite.m4 serial 1 +dnl Copyright (C) 2007 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_ISFINITE], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + dnl Persuade glibc to declare isfinite. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_CHECK_DECLS([isfinite], , , [#include ]) + if test "$ac_cv_have_decl_isfinite" = yes; then + gl_CHECK_MATH_LIB([ISFINITE_LIBM], [x = isfinite (x);]) + fi + if test "$ac_cv_have_decl_isfinite" != yes || + test "$ISFINITE_LIBM" = missing; then + ISFINITE_LIBM= + HAVE_DECL_ISFINITE=0 + AC_LIBOBJ([isfinite]) + fi + AC_SUBST([HAVE_DECL_ISFINITE]) + AC_SUBST([ISFINITE_LIBM]) +]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 4806e08e4f..890888cab8 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -34,6 +34,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_TRUNC=0; AC_SUBST([GNULIB_TRUNC]) GNULIB_TRUNCF=0; AC_SUBST([GNULIB_TRUNCF]) GNULIB_TRUNCL=0; AC_SUBST([GNULIB_TRUNCL]) + GNULIB_ISFINITE=0; AC_SUBST([GNULIB_ISFINITE]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_DECL_ACOSL=1; AC_SUBST([HAVE_DECL_ACOSL]) HAVE_DECL_ASINL=1; AC_SUBST([HAVE_DECL_ASINL]) @@ -56,6 +57,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], HAVE_DECL_TRUNC=1; AC_SUBST([HAVE_DECL_TRUNC]) HAVE_DECL_TRUNCF=1; AC_SUBST([HAVE_DECL_TRUNCF]) HAVE_DECL_TRUNCL=1; AC_SUBST([HAVE_DECL_TRUNCL]) + HAVE_DECL_ISFINITE=1; AC_SUBST([HAVE_DECL_ISFINITE]) REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL]) diff --git a/modules/isfinite b/modules/isfinite new file mode 100644 index 0000000000..6c77a0aa6b --- /dev/null +++ b/modules/isfinite @@ -0,0 +1,29 @@ +Description: +isfinite macro: test for finite value (zero, subnormal, or normal, and not infinite or NaN). + +Files: +lib/isfinite.c +m4/isfinite.m4 +m4/check-math-lib.m4 + +Depends-on: +isnan-nolibm +isnanf-nolibm +isnanl-nolibm +math +extensions + +configure.ac: +gl_ISFINITE +gl_MATH_MODULE_INDICATOR([isfinite]) + +Makefile.am: + +Include: + + +License: +GPL + +Maintainer: +Ben Pfaff diff --git a/modules/isfinite-tests b/modules/isfinite-tests new file mode 100644 index 0000000000..673aa1cdfc --- /dev/null +++ b/modules/isfinite-tests @@ -0,0 +1,18 @@ +Files: +tests/test-isfinite.c + +Depends-on: +float + +configure.ac: +gl_FLOAT_EXPONENT_LOCATION +gl_DOUBLE_EXPONENT_LOCATION +gl_LONG_DOUBLE_EXPONENT_LOCATION + +Makefile.am: +TESTS += test-isfinite +check_PROGRAMS += test-isfinite +test_isfinite_LDADD = $(LDADD) @ISFINITE_LIBM@ + +License: +GPL diff --git a/modules/math b/modules/math index 540f2fa65a..935bebb79f 100644 --- a/modules/math +++ b/modules/math @@ -37,6 +37,7 @@ math.h: math.in.h -e 's|@''GNULIB_TRUNC''@|$(GNULIB_TRUNC)|g' \ -e 's|@''GNULIB_TRUNCF''@|$(GNULIB_TRUNCF)|g' \ -e 's|@''GNULIB_TRUNCL''@|$(GNULIB_TRUNCL)|g' \ + -e 's|@''GNULIB_ISFINITE''@|$(GNULIB_ISFINITE)|g' \ -e 's|@''HAVE_DECL_ACOSL''@|$(HAVE_DECL_ACOSL)|g' \ -e 's|@''HAVE_DECL_ASINL''@|$(HAVE_DECL_ASINL)|g' \ -e 's|@''HAVE_DECL_ATANL''@|$(HAVE_DECL_ATANL)|g' \ @@ -58,6 +59,7 @@ math.h: math.in.h -e 's|@''HAVE_DECL_TRUNC''@|$(HAVE_DECL_TRUNC)|g' \ -e 's|@''HAVE_DECL_TRUNCF''@|$(HAVE_DECL_TRUNCF)|g' \ -e 's|@''HAVE_DECL_TRUNCL''@|$(HAVE_DECL_TRUNCL)|g' \ + -e 's|@''HAVE_DECL_ISFINITE''@|$(HAVE_DECL_ISFINITE)|g' \ -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \ diff --git a/tests/test-isfinite.c b/tests/test-isfinite.c new file mode 100644 index 0000000000..acdb4564a6 --- /dev/null +++ b/tests/test-isfinite.c @@ -0,0 +1,181 @@ +/* Test of isfinite() substitute. + Copyright (C) 2007 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, 2007, 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__); \ + abort (); \ + } \ + } \ + while (0) + +float zerof = 0.0f; +double zerod = 0.0; +long double zerol = 0.0L; + +static void +test_isfinitef () +{ + /* Zero. */ + ASSERT (isfinite (0.0f)); + /* Subnormal values. */ + ASSERT (isfinite (FLT_MIN / 2)); + ASSERT (isfinite (-FLT_MIN / 2)); + /* Finite values. */ + ASSERT (isfinite (3.141f)); + ASSERT (isfinite (3.141e30f)); + ASSERT (isfinite (3.141e-30f)); + ASSERT (isfinite (-2.718f)); + ASSERT (isfinite (-2.718e30f)); + ASSERT (isfinite (-2.718e-30f)); + /* Infinite values. */ + ASSERT (!isfinite (1.0f / 0.0f)); + ASSERT (!isfinite (-1.0f / 0.0f)); + /* Quiet NaN. */ + ASSERT (!isfinite (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 (!isfinite (m.value)); + #undef NWORDS + } +#endif +} + +static void +test_isfinited () +{ + /* Zero. */ + ASSERT (isfinite (0.0)); + /* Subnormal values. */ + ASSERT (isfinite (DBL_MIN / 2)); + ASSERT (isfinite (-DBL_MIN / 2)); + /* Finite values. */ + ASSERT (isfinite (3.141)); + ASSERT (isfinite (3.141e30)); + ASSERT (isfinite (3.141e-30)); + ASSERT (isfinite (-2.718)); + ASSERT (isfinite (-2.718e30)); + ASSERT (isfinite (-2.718e-30)); + /* Infinite values. */ + ASSERT (!isfinite (1.0 / 0.0)); + ASSERT (!isfinite (-1.0 / 0.0)); + /* Quiet NaN. */ + ASSERT (!isfinite (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 (!isfinite (m.value)); + #undef NWORDS + } +#endif +} + +static void +test_isfinitel () +{ + /* Zero. */ + ASSERT (isfinite (0.0L)); + /* Subnormal values. */ + ASSERT (isfinite (LDBL_MIN / 2)); + ASSERT (isfinite (-LDBL_MIN / 2)); + /* Finite values. */ + ASSERT (isfinite (3.141L)); + ASSERT (isfinite (3.141e30L)); + ASSERT (isfinite (3.141e-30L)); + ASSERT (isfinite (-2.718L)); + ASSERT (isfinite (-2.718e30L)); + ASSERT (isfinite (-2.718e-30L)); + /* Infinite values. */ + ASSERT (!isfinite (1.0L / 0.0L)); + ASSERT (!isfinite (-1.0L / 0.0L)); + /* Quiet NaN. */ + ASSERT (!isfinite (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. */ + { + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { unsigned int word[NWORDS]; long double value; } + memory_long_double; + 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 (!isfinite (m.value)); + #undef NWORDS + } +#endif +} + +int +main () +{ + test_isfinitef (); + test_isfinited (); + test_isfinitel (); + return 0; +}