changeset 8652:9aabfa2b3200

New module 'signbit'.
author Bruno Haible <bruno@clisp.org>
date Fri, 06 Apr 2007 20:55:44 +0000
parents acd997e2cee5
children 02c040ba84bf
files ChangeLog lib/math_.h lib/signbitd.c lib/signbitf.c lib/signbitl.c m4/math_h.m4 m4/signbit.m4 modules/math modules/signbit
diffstat 9 files changed, 429 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2007-04-06  Bruno Haible  <bruno@clisp.org>
+
+	* 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  <bruno@clisp.org>
 
 	* modules/isnanf-nolibm-tests: New file.
@@ -29502,4 +29516,4 @@
 
 	* m4/isc-posix.m4: New file.
 
-1998-05-10  Jim Meyering  <meyering@ascend.com>
\ No newline at end of file
+1998-05-10  Jim Meyering  <meyering@ascend.com>
--- a/lib/math_.h
+++ b/lib/math_.h
@@ -215,6 +215,51 @@
 #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
new file mode 100644
--- /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 <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
+}
new file mode 100644
--- /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 <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
+}
new file mode 100644
--- /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 <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
+}
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -21,10 +21,11 @@
 
 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 @@
   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])
 ])
new file mode 100644
--- /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 <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
+])
--- a/modules/math
+++ b/modules/math
@@ -25,6 +25,7 @@
 	      -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 @@
 	      -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
new file mode 100644
--- /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:
+<math.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
+