# HG changeset patch # User Bruno Haible # Date 1172344136 0 # Node ID fc7bcbeadfee01143c31b041da45b58d9d1344be # Parent e27c94a6558aa3fa31b1d35a95ca76537f90e61a New module 'isnan-nolibm'. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2007-02-24 Bruno Haible + + * modules/isnan-nolibm: New file. + * lib/isnan.h: New file. + * lib/isnan.c: New file. + * m4/isnan.m4: New file. + 2007-02-24 Bruno Haible * lib/frexpl.c (frexpl): Correct return values for x = 1.0L. Don't diff --git a/lib/isnan.c b/lib/isnan.c new file mode 100644 --- /dev/null +++ b/lib/isnan.c @@ -0,0 +1,61 @@ +/* Test for NaN that does not need libm. + 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 Bruno Haible , 2007. */ + +#include + +#include +#include + +#define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7) + +#define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +typedef union { double value; unsigned int word[NWORDS]; } memory_double; + +int +rpl_isnan (double x) +{ +#if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT + /* Be careful to not do any floating-point operation on x, such as x == x, + because x may be a signaling NaN. */ + static memory_double nan = { 0.0 / 0.0 }; + static double plus_inf = 1.0 / 0.0; + static double minus_inf = -1.0 / 0.0; + memory_double m; + + /* A NaN can be recognized through its exponent. But exclude +Infinity and + -Infinity, which have the same exponent. */ + m.value = x; + if ((((m.word[DBL_EXPBIT0_WORD] >> DBL_EXPBIT0_BIT) + ^ (nan.word[DBL_EXPBIT0_WORD] >> DBL_EXPBIT0_BIT)) + & DBL_EXP_MASK) + == 0) + return (memcmp (&m.value, &plus_inf, sizeof (double)) != 0 + && memcmp (&m.value, &minus_inf, sizeof (double)) != 0); + else + return 0; +#else + /* The configuration did not find sufficient information. Give up about + the signaling NaNs, handle only the quiet NaNs. */ + if (x == x) + return 0; + else + return 1; +#endif +} diff --git a/lib/isnan.h b/lib/isnan.h new file mode 100644 --- /dev/null +++ b/lib/isnan.h @@ -0,0 +1,26 @@ +/* Test for NaN that does not need libm. + 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. */ + +#if HAVE_ISNAN_IN_LIBC +/* Get declaration of isnan. */ +# include +#else +/* Test whether X is a NaN. */ +# undef isnan +# define isnan rpl_isnan +extern int isnan (double x); +#endif diff --git a/m4/isnan.m4 b/m4/isnan.m4 new file mode 100644 --- /dev/null +++ b/m4/isnan.m4 @@ -0,0 +1,122 @@ +# isnan.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. + +dnl Check how to get or define isnan() without linking with libm. + +AC_DEFUN([gl_FUNC_ISNAN_NO_LIBM], +[ + AC_CHECK_FUNC([isnan], + [gl_cv_func_isnan_no_libm=yes], + [gl_cv_func_isnan_no_libm=no]) + if test $gl_cv_func_isnan_no_libm = yes; then + AC_DEFINE([HAVE_ISNAN_IN_LIBC], 1, + [Define if the isnan() function is available in libc.]) + else + AC_LIBOBJ([isnan]) + gl_DOUBLE_EXPONENT_LOCATION + fi +]) + +AC_DEFUN([gl_DOUBLE_EXPONENT_LOCATION], +[ + AC_CACHE_CHECK([where to find the exponent in a 'double'], + [gl_cv_cc_double_expbit0], + [ + AC_TRY_RUN([ +#include +#include +#include +#include +#define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +typedef union { double value; unsigned int word[NWORDS]; } memory_double; +static unsigned int ored_words[NWORDS]; +static unsigned int anded_words[NWORDS]; +static void add_to_ored_words (double x) +{ + memory_double m; + size_t i; + /* Clear it first, in case sizeof (double) < sizeof (memory_double). */ + memset (&m, 0, sizeof (memory_double)); + m.value = x; + for (i = 0; i < NWORDS; i++) + { + ored_words[i] |= m.word[i]; + anded_words[i] &= m.word[i]; + } +} +int main () +{ + size_t j; + FILE *fp = fopen ("conftest.out", "w"); + if (fp == NULL) + return 1; + for (j = 0; j < NWORDS; j++) + anded_words[j] = ~ (unsigned int) 0; + add_to_ored_words (0.25); + add_to_ored_words (0.5); + add_to_ored_words (1.0); + add_to_ored_words (2.0); + add_to_ored_words (4.0); + /* Remove bits that are common (e.g. if representation of the first mantissa + bit is explicit). */ + for (j = 0; j < NWORDS; j++) + ored_words[j] &= ~anded_words[j]; + /* Now find the nonzero word. */ + for (j = 0; j < NWORDS; j++) + if (ored_words[j] != 0) + break; + if (j < NWORDS) + { + size_t i; + for (i = j + 1; i < NWORDS; i++) + if (ored_words[i] != 0) + { + fprintf (fp, "unknown"); + return (fclose (fp) != 0); + } + for (i = 0; ; i++) + if ((ored_words[j] >> i) & 1) + { + fprintf (fp, "word %d bit %d", (int) j, (int) i); + return (fclose (fp) != 0); + } + } + fprintf (fp, "unknown"); + return (fclose (fp) != 0); +} + ], + [gl_cv_cc_double_expbit0=`cat conftest.out`], + [gl_cv_cc_double_expbit0="unknown"], + [ + dnl On ARM, integer types are stored in little-endian byte order, + dnl but floats are stored in big-endian word order. + AC_EGREP_CPP([mixed_endianness], [ +#if defined arm || defined __arm || defined __arm__ + mixed_endianness +#endif + ], + [gl_cv_cc_double_expbit0="word 0 bit 20"], + [ + AC_C_BIGENDIAN( + [gl_cv_cc_double_expbit0="word 0 bit 20"], + [gl_cv_cc_double_expbit0="word 1 bit 20"], + [gl_cv_cc_double_expbit0="unknown"]) + ]) + ]) + rm -f conftest.out + ]) + case "$gl_cv_cc_double_expbit0" in + word*bit*) + word=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` + bit=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word.*bit //'` + AC_DEFINE_UNQUOTED([DBL_EXPBIT0_WORD], [$word], + [Define as the word index where to find the exponent of 'double'.]) + AC_DEFINE_UNQUOTED([DBL_EXPBIT0_BIT], [$bit], + [Define as the bit index in the word where to find bit 0 of the exponent of 'double'.]) + ;; + esac +]) diff --git a/modules/isnan-nolibm b/modules/isnan-nolibm new file mode 100644 --- /dev/null +++ b/modules/isnan-nolibm @@ -0,0 +1,24 @@ +Description: +isnan() function: test for NaN, without requiring libm. + +Files: +lib/isnan.h +lib/isnan.c +m4/isnan.m4 + +Depends-on: + +configure.ac: +gl_FUNC_ISNAN_NO_LIBM + +Makefile.am: + +Include: +#include "isnan.h" + +License: +LGPL + +Maintainer: +Bruno Haible +