From f8cce822d6a82cadf0ea2907eb94a1017910322f Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 6 Apr 2007 20:55:44 +0000 Subject: [PATCH] New module 'signbit'. --- ChangeLog | 16 +++++- lib/math_.h | 45 ++++++++++++++++ lib/signbitd.c | 55 +++++++++++++++++++ lib/signbitf.c | 55 +++++++++++++++++++ lib/signbitl.c | 55 +++++++++++++++++++ m4/math_h.m4 | 10 ++-- m4/signbit.m4 | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/math | 2 + modules/signbit | 32 +++++++++++ 9 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 lib/signbitd.c create mode 100644 lib/signbitf.c create mode 100644 lib/signbitl.c create mode 100644 m4/signbit.m4 create mode 100644 modules/signbit diff --git a/ChangeLog b/ChangeLog index 7a3f49732..9fe37697c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2007-04-06 Bruno Haible + * modules/signbit: New file. + * lib/signbitf.c: New file. + * lib/signbitd.c: New file. + * lib/signbitl.c: New file. + * m4/signbit.m4: New file. + * lib/math_.h (gl_signbitf, gl_signbitd, gl_signbitl): New declarations. + (signbit): New macro. + * m4/math_h.m4 (gl_MATH_H_DEFAULTS): Initialize GNULIB_SIGNBIT and + REPLACE_SIGNBIT. + * modules/math (Makefile.am) Substibute also GNULIB_SIGNBIT and + REPLACE_FREXPL into math.h. + +2007-04-06 Bruno Haible + * modules/isnanf-nolibm-tests: New file. * tests/test-isnanf.c: New file. @@ -29502,4 +29516,4 @@ * m4/isc-posix.m4: New file. -1998-05-10 Jim Meyering \ No newline at end of file +1998-05-10 Jim Meyering diff --git a/lib/math_.h b/lib/math_.h index 66aa0538e..9e84d06aa 100644 --- a/lib/math_.h +++ b/lib/math_.h @@ -215,6 +215,51 @@ extern long double tanl (long double x); #endif +#if @GNULIB_SIGNBIT@ +# if @REPLACE_SIGNBIT@ +# undef signbit +extern int gl_signbitf (float arg); +extern int gl_signbitd (double arg); +extern int gl_signbitl (long double arg); +# if __GNUC__ >= 2 && !__STRICT_ANSI__ +# if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT +# define gl_signbitf(arg) \ + ({ union { float _value; \ + unsigned int _word[(sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)]; \ + } _m; \ + _m._value = (arg); \ + (_m._word[FLT_SIGNBIT_WORD] >> FLT_SIGNBIT_BIT) & 1; \ + }) +# endif +# if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT +# define gl_signbitd(arg) \ + ({ union { double _value; \ + unsigned int _word[(sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)]; \ + } _m; \ + _m._value = (arg); \ + (_m._word[DBL_SIGNBIT_WORD] >> DBL_SIGNBIT_BIT) & 1; \ + }) +# endif +# if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT +# define gl_signbitl(arg) \ + ({ union { long double _value; \ + unsigned int _word[(sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)]; \ + } _m; \ + _m._value = (arg); \ + (_m._word[LDBL_SIGNBIT_WORD] >> LDBL_SIGNBIT_BIT) & 1; \ + }) +# endif +# endif +# define signbit(x) \ + (sizeof (x) == sizeof (long double) ? gl_signbitl (x) : \ + sizeof (x) == sizeof (double) ? gl_signbitd (x) : \ + gl_signbitf (x)) +# endif +#elif defined GNULIB_POSIXCHECK + /* How to override a macro? */ +#endif + + #ifdef __cplusplus } #endif diff --git a/lib/signbitd.c b/lib/signbitd.c new file mode 100644 index 000000000..f8a9613db --- /dev/null +++ b/lib/signbitd.c @@ -0,0 +1,55 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + 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. */ + +#include + +/* Specification. */ +#include + +#include +#include "isnan.h" +#include "float+.h" + +#undef gl_signbitd + +int +gl_signbitd (double arg) +{ +#if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT +# define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { double value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[DBL_SIGNBIT_WORD] >> DBL_SIGNBIT_BIT) & 1; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnan (arg)) + return 0; + if (arg < 0.0) + return 1; + else if (arg == 0.0) + { + /* Distinguish 0.0 and -0.0. */ + static double plus_zero = 0.0; + double arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_DBL) != 0); + } + else + return 0; +#endif +} diff --git a/lib/signbitf.c b/lib/signbitf.c new file mode 100644 index 000000000..c172b5fbe --- /dev/null +++ b/lib/signbitf.c @@ -0,0 +1,55 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + 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. */ + +#include + +/* Specification. */ +#include + +#include +#include "isnanf.h" +#include "float+.h" + +#undef gl_signbitf + +int +gl_signbitf (float arg) +{ +#if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT +# define NWORDS \ + ((sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { float value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[FLT_SIGNBIT_WORD] >> FLT_SIGNBIT_BIT) & 1; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnanf (arg)) + return 0; + if (arg < 0.0f) + return 1; + else if (arg == 0.0f) + { + /* Distinguish 0.0f and -0.0f. */ + static float plus_zero = 0.0f; + float arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_FLT) != 0); + } + else + return 0; +#endif +} diff --git a/lib/signbitl.c b/lib/signbitl.c new file mode 100644 index 000000000..04814dcda --- /dev/null +++ b/lib/signbitl.c @@ -0,0 +1,55 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + 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. */ + +#include + +/* Specification. */ +#include + +#include +#include "isnanl-nolibm.h" +#include "float+.h" + +#undef gl_signbitl + +int +gl_signbitl (long double arg) +{ +#if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT +# define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { long double value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[LDBL_SIGNBIT_WORD] >> LDBL_SIGNBIT_BIT) & 1; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnanl (arg)) + return 0; + if (arg < 0.0L) + return 1; + else if (arg == 0.0L) + { + /* Distinguish 0.0L and -0.0L. */ + static long double plus_zero = 0.0L; + long double arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_LDBL) != 0); + } + else + return 0; +#endif +} diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 1202dc878..cc8570248 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -21,10 +21,11 @@ AC_DEFUN([gl_MATH_MODULE_INDICATOR], AC_DEFUN([gl_MATH_H_DEFAULTS], [ - GNULIB_FREXP=0; AC_SUBST([GNULIB_FREXP]) - GNULIB_FREXPL=0; AC_SUBST([GNULIB_FREXPL]) - GNULIB_LDEXPL=0; AC_SUBST([GNULIB_LDEXPL]) - GNULIB_MATHL=0; AC_SUBST([GNULIB_MATHL]) + GNULIB_FREXP=0; AC_SUBST([GNULIB_FREXP]) + GNULIB_FREXPL=0; AC_SUBST([GNULIB_FREXPL]) + GNULIB_LDEXPL=0; AC_SUBST([GNULIB_LDEXPL]) + GNULIB_MATHL=0; AC_SUBST([GNULIB_MATHL]) + GNULIB_SIGNBIT=0; AC_SUBST([GNULIB_SIGNBIT]) 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]) @@ -42,4 +43,5 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL]) + REPLACE_SIGNBIT=0; AC_SUBST([REPLACE_SIGNBIT]) ]) diff --git a/m4/signbit.m4 b/m4/signbit.m4 new file mode 100644 index 000000000..267ef6718 --- /dev/null +++ b/m4/signbit.m4 @@ -0,0 +1,164 @@ +# signbit.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_SIGNBIT], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_CACHE_CHECK([for signbit macro], [gl_cv_func_signbit], + [ + AC_TRY_RUN([ +#include +#include +float p0f = 0.0f; +float m0f = -0.0f; +double p0d = 0.0; +double m0d = -0.0; +long double p0l = 0.0L; +long double m0l = -0.0L; +int main () +{ + { + float plus_inf = 1.0f / p0f; + float minus_inf = -1.0f / p0f; + if (!(!signbit (255.0f) + && signbit (-255.0f) + && !signbit (p0f) + && (memcmp (&m0f, &p0f, sizeof (float)) == 0 || signbit (m0f)) + && !signbit (plus_inf) + && signbit (minus_inf))) + return 1; + } + { + double plus_inf = 1.0 / p0d; + double minus_inf = -1.0 / p0d; + if (!(!signbit (255.0) + && signbit (-255.0) + && !signbit (p0d) + && (memcmp (&m0d, &p0d, sizeof (double)) == 0 || signbit (m0d)) + && !signbit (plus_inf) + && signbit (minus_inf))) + return 1; + } + { + long double plus_inf = 1.0L / p0l; + long double minus_inf = -1.0L / p0l; + if (!(!signbit (255.0L) + && signbit (-255.0L) + && !signbit (p0l) + && (memcmp (&m0l, &p0l, sizeof (long double)) == 0 || signbit (m0l)) + && !signbit (plus_inf) + && signbit (minus_inf))) + return 1; + } + return 0; +}], [gl_cv_func_signbit=yes], [gl_cv_func_signbit=no], + [gl_cv_func_signbit="guessing no"]) + ]) + if test "$gl_cv_func_signbit" != yes; then + REPLACE_SIGNBIT=1 + AC_LIBOBJ([signbitf]) + AC_LIBOBJ([signbitd]) + AC_LIBOBJ([signbitl]) + gl_FLOAT_SIGN_LOCATION + gl_DOUBLE_SIGN_LOCATION + gl_LONG_DOUBLE_SIGN_LOCATION + fi +]) + +AC_DEFUN([gl_FLOAT_SIGN_LOCATION], +[ + gl_FLOATTYPE_SIGN_LOCATION([float], [gl_cv_cc_float_signbit], [f], [FLT]) +]) + +AC_DEFUN([gl_DOUBLE_SIGN_LOCATION], +[ + gl_FLOATTYPE_SIGN_LOCATION([double], [gl_cv_cc_double_signbit], [], [DBL]) +]) + +AC_DEFUN([gl_LONG_DOUBLE_SIGN_LOCATION], +[ + gl_FLOATTYPE_SIGN_LOCATION([long double], [gl_cv_cc_long_double_signbit], [L], [LDBL]) +]) + +AC_DEFUN([gl_FLOATTYPE_SIGN_LOCATION], +[ + AC_CACHE_CHECK([where to find the sign bit in a '$1'], + [$2], + [ + AC_TRY_RUN([ +#include +#include +#define NWORDS \ + ((sizeof ($1) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +typedef union { $1 value; unsigned int word[NWORDS]; } + memory_float; +static memory_float plus = { 1.0$3 }; +static memory_float minus = { -1.0$3 }; +int main () +{ + size_t j, k, i; + unsigned int m; + FILE *fp = fopen ("conftest.out", "w"); + if (fp == NULL) + return 1; + /* Find the different bit. */ + k = 0; m = 0; + for (j = 0; j < NWORDS; j++) + { + unsigned int x = plus.word[j] ^ minus.word[j]; + if ((x & (x - 1)) || (x && m)) + { + /* More than one bit difference. */ + fprintf (fp, "unknown"); + return 1; + } + if (x) + { + k = j; + m = x; + } + } + if (m == 0) + { + /* No difference. */ + fprintf (fp, "unknown"); + return 1; + } + /* Now m = plus.word[k] ^ ~minus.word[k]. */ + if (plus.word[k] & ~minus.word[k]) + { + /* Oh? The sign bit is set in the positive and cleared in the negative + numbers? */ + fprintf (fp, "unknown"); + return 1; + } + for (i = 0; ; i++) + if ((m >> i) & 1) + break; + fprintf (fp, "word %d bit %d", (int) k, (int) i); + return (fclose (fp) != 0); +} + ], + [$2=`cat conftest.out`], + [$2="unknown"], + [ + dnl When cross-compiling, we don't know. It depends on the + dnl ABI and compiler version. There are too many cases. + $2="unknown" + ]) + rm -f conftest.out + ]) + case "$]$2[" in + word*bit*) + word=`echo "$]$2[" | sed -e 's/word //' -e 's/ bit.*//'` + bit=`echo "$]$2[" | sed -e 's/word.*bit //'` + AC_DEFINE_UNQUOTED([$4][_SIGNBIT_WORD], [$word], + [Define as the word index where to find the sign of '$1'.]) + AC_DEFINE_UNQUOTED([$4][_SIGNBIT_BIT], [$bit], + [Define as the bit index in the word where to find the sign of '$1'.]) + ;; + esac +]) diff --git a/modules/math b/modules/math index eb72003be..ea497f170 100644 --- a/modules/math +++ b/modules/math @@ -25,6 +25,7 @@ math.h: math_.h -e 's|@''GNULIB_FREXPL''@|$(GNULIB_FREXPL)|g' \ -e 's|@''GNULIB_LDEXPL''@|$(GNULIB_LDEXPL)|g' \ -e 's|@''GNULIB_MATHL''@|$(GNULIB_MATHL)|g' \ + -e 's|@''GNULIB_SIGNBIT''@|$(GNULIB_SIGNBIT)|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' \ @@ -41,6 +42,7 @@ math.h: math_.h -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \ + -e 's|@''REPLACE_SIGNBIT''@|$(REPLACE_SIGNBIT)|g' \ -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \ < $(srcdir)/math_.h; \ } > $@-t diff --git a/modules/signbit b/modules/signbit new file mode 100644 index 000000000..10c1840b0 --- /dev/null +++ b/modules/signbit @@ -0,0 +1,32 @@ +Description: +signbit() macro: Determine the sign bit of a floating-point number. + +Files: +lib/signbitf.c +lib/signbitd.c +lib/signbitl.c +lib/float+.h +m4/signbit.m4 + +Depends-on: +math +isnanf-nolibm +isnan-nolibm +isnanl-nolibm +fpieee + +configure.ac: +gl_SIGNBIT +gl_MATH_MODULE_INDICATOR([signbit]) + +Makefile.am: + +Include: + + +License: +LGPL + +Maintainer: +Bruno Haible + -- 2.11.0