From: Bruno Haible Date: Sat, 24 Feb 2007 19:15:21 +0000 (+0000) Subject: New module 'isnanl-nolibm'. X-Git-Tag: cvs-readonly~986 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=ba40cb572a7580ec1aafd0c2c1fbf3751caabdb6;p=gnulib.git New module 'isnanl-nolibm'. --- diff --git a/ChangeLog b/ChangeLog index e51282dfb..af4c2d93d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2007-02-24 Bruno Haible + * modules/isnanl-nolibm: New file. + * lib/isnanl.h: New file. + * lib/isnanl.c: New file. + * m4/isnanl.m4: New file. + +2007-02-24 Bruno Haible + * modules/isnan-nolibm-tests: New file. * tests/test-isnan.c: New file. diff --git a/lib/isnanl.c b/lib/isnanl.c new file mode 100644 index 000000000..0412c5540 --- /dev/null +++ b/lib/isnanl.c @@ -0,0 +1,62 @@ +/* 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 LDBL_EXP_MASK ((LDBL_MAX_EXP - LDBL_MIN_EXP) | 7) + +#define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +typedef union { long double value; unsigned int word[NWORDS]; } + memory_long_double; + +int +rpl_isnanl (long double x) +{ +#if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + /* Be careful to not do any floating-point operation on x, such as x == x, + because x may be a signalling NaN. */ + static memory_long_double nan = { 0.0L / 0.0L }; + static long double plus_inf = 1.0L / 0.0L; + static long double minus_inf = -1.0L / 0.0L; + memory_long_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[LDBL_EXPBIT0_WORD] >> LDBL_EXPBIT0_BIT) + ^ (nan.word[LDBL_EXPBIT0_WORD] >> LDBL_EXPBIT0_BIT)) + & LDBL_EXP_MASK) + == 0) + return (memcmp (&m.value, &plus_inf, sizeof (long double)) != 0 + && memcmp (&m.value, &minus_inf, sizeof (long 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/isnanl.h b/lib/isnanl.h new file mode 100644 index 000000000..95f45410e --- /dev/null +++ b/lib/isnanl.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_ISNANL_IN_LIBC +/* Get declaration of isnanl. */ +# include +#else +/* Test whether X is a NaN. */ +# undef isnanl +# define isnanl rpl_isnanl +extern int isnanl (long double x); +#endif diff --git a/m4/isnanl.m4 b/m4/isnanl.m4 new file mode 100644 index 000000000..54395793b --- /dev/null +++ b/m4/isnanl.m4 @@ -0,0 +1,114 @@ +# isnanl.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_FUNC_ISNANL_NO_LIBM], +[ + AC_REQUIRE([gt_TYPE_LONGDOUBLE]) + if test $gt_cv_c_long_double = yes; then + AC_CHECK_FUNC([isnanl], + [gl_cv_func_isnanl_no_libm=yes], + [gl_cv_func_isnanl_no_libm=no]) + if test $gl_cv_func_isnanl_no_libm = yes; then + AC_DEFINE([HAVE_ISNANL_IN_LIBC], 1, + [Define if the isnanl() function is available in libc.]) + else + AC_LIBOBJ([isnanl]) + gl_LONG_DOUBLE_EXPONENT_LOCATION + fi + fi +]) + +AC_DEFUN([gl_LONG_DOUBLE_EXPONENT_LOCATION], +[ + AC_CACHE_CHECK([where to find the exponent in a 'long double'], + [gl_cv_cc_long_double_expbit0], + [ + AC_TRY_RUN([ +#include +#include +#include +#include +#define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +typedef union { long double value; unsigned int word[NWORDS]; } + memory_long_double; +static unsigned int ored_words[NWORDS]; +static unsigned int anded_words[NWORDS]; +static void add_to_ored_words (long double x) +{ + memory_long_double m; + size_t i; + /* Clear it first, in case + sizeof (long double) < sizeof (memory_long_double). */ + memset (&m, 0, sizeof (memory_long_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.25L); + add_to_ored_words (0.5L); + add_to_ored_words (1.0L); + add_to_ored_words (2.0L); + add_to_ored_words (4.0L); + /* 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_long_double_expbit0=`cat conftest.out`], + [gl_cv_cc_long_double_expbit0="unknown"], + [ + dnl When cross-compiling, we don't know. It depends on the + dnl ABI and compiler version. There are too many cases. + gl_cv_cc_long_double_expbit0="unknown" + ]) + rm -f conftest.out + ]) + case "$gl_cv_cc_long_double_expbit0" in + word*bit*) + word=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` + bit=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word.*bit //'` + AC_DEFINE_UNQUOTED([LDBL_EXPBIT0_WORD], [$word], + [Define as the word index where to find the exponent of 'long double'.]) + AC_DEFINE_UNQUOTED([LDBL_EXPBIT0_BIT], [$bit], + [Define as the bit index in the word where to find bit 0 of the exponent of 'long double'.]) + ;; + esac +]) diff --git a/modules/isnanl-nolibm b/modules/isnanl-nolibm new file mode 100644 index 000000000..2833ddc27 --- /dev/null +++ b/modules/isnanl-nolibm @@ -0,0 +1,27 @@ +Description: +isnanl() function: test for NaN, without requiring libm. + +Files: +lib/isnanl.h +lib/isnanl.c +m4/isnanl.m4 +m4/longdouble.m4 + +Depends-on: + +configure.ac: +gl_FUNC_ISNANL_NO_LIBM + +Makefile.am: + +Include: +#if HAVE_LONG_DOUBLE +# include "isnan.h" +#endif + +License: +LGPL + +Maintainer: +Bruno Haible +