Paul mentioned copysign and signbit as possible new gnulib modules. Here is the 'signbit' module.
2007-04-06 Bruno Haible <[EMAIL PROTECTED]> * 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. =========================== modules/signbit ================================ 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: <math.h> License: LGPL Maintainer: Bruno Haible ============================ lib/signbitf.c ================================ /* 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 <config.h> /* Specification. */ #include <math.h> #include <string.h> #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 } ============================ lib/signbitd.c ================================ /* 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 <config.h> /* Specification. */ #include <math.h> #include <string.h> #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 } ============================ lib/signbitl.c ================================ /* 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 <config.h> /* Specification. */ #include <math.h> #include <string.h> #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 } ============================ m4/signbit.m4 ================================= # 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 <math.h> #include <string.h> 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 <stddef.h> #include <stdio.h> #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 ]) ============================================================================ *** lib/math_.h 6 Apr 2007 12:25:54 -0000 1.9 --- lib/math_.h 6 Apr 2007 20:46:32 -0000 *************** *** 215,220 **** --- 215,265 ---- #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 *** m4/math_h.m4 30 Mar 2007 00:13:24 -0000 1.6 --- m4/math_h.m4 6 Apr 2007 20:46:32 -0000 *************** *** 21,30 **** 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]) 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]) --- 21,31 ---- 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_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,45 **** --- 43,47 ---- 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]) ]) *** modules/math 30 Mar 2007 00:13:24 -0000 1.6 --- modules/math 6 Apr 2007 20:46:32 -0000 *************** *** 25,30 **** --- 25,31 ---- -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,46 **** --- 42,48 ---- -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; \ } > [EMAIL PROTECTED]