changeset 15301:deb35cf77594

float: Work around <float.h> bugs on FreeBSD/x86, AIX with GCC, IRIX. * lib/float.in.h: Add workarounds for FreeBSD/x86, AIX with GCC, IRIX. * lib/float.c: New file. * m4/float_h.m4 (gl_FLOAT_H): Also handle FreeBSD, AIX, IRIX. Set REPLACE_FLOAT_LDBL. * modules/float (Files): Add lib/float.c. (configure.ac): Invoke AC_LIBOBJ. * doc/posix-headers/float.texi: Mention problems on FreeBSD, AIX, IRIX.
author Bruno Haible <bruno@clisp.org>
date Mon, 20 Jun 2011 12:38:05 +0200
parents 64ce149fbae3
children 8f229ae087b4
files ChangeLog doc/posix-headers/float.texi lib/float.c lib/float.in.h m4/float_h.m4 modules/float
diffstat 6 files changed, 195 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-06-20  Bruno Haible  <bruno@clisp.org>
+
+	float: Work around <float.h> bugs on FreeBSD/x86, AIX with GCC, IRIX.
+	* lib/float.in.h: Add workarounds for FreeBSD/x86, AIX with GCC, IRIX.
+	* lib/float.c: New file.
+	* m4/float_h.m4 (gl_FLOAT_H): Also handle FreeBSD, AIX, IRIX. Set
+	REPLACE_FLOAT_LDBL.
+	* modules/float (Files): Add lib/float.c.
+	(configure.ac): Invoke AC_LIBOBJ.
+	* doc/posix-headers/float.texi: Mention problems on FreeBSD, AIX, IRIX.
+
 2011-06-20  Bruno Haible  <bruno@clisp.org>
 
 	Tests for module 'float'.
--- a/doc/posix-headers/float.texi
+++ b/doc/posix-headers/float.texi
@@ -12,6 +12,10 @@
 On OpenBSD 4.0, MirBSD 10, and BeOS, they are the same as the values of the
 @code{DBL_*} macros, although @samp{long double} is a larger type than
 @samp{double}.
+On FreeBSD/x86 6.4, they represent the incorrect 53-bit precision assumptions
+in the compiler, not the real 64-bit precision at runtime.
+On AIX 7.1 with GCC 4.2 and on IRIX 6.5, they don't reflect the
+``double double'' representation of @code{long double} correctly.
 @end itemize
 
 Portability problems not fixed by Gnulib:
new file mode 100644
--- /dev/null
+++ b/lib/float.c
@@ -0,0 +1,33 @@
+/* Auxiliary definitions for <float.h>.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2011.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <float.h>
+
+#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__
+const union gl_long_double_union gl_LDBL_MAX =
+  { { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL } };
+#elif defined __i386__
+const union gl_long_double_union gl_LDBL_MAX =
+  { { 0xFFFFFFFF, 0xFFFFFFFF, 32766 } };
+#else
+/* This declaration is solely to ensure that after preprocessing
+   this file is never empty.  */
+typedef int dummy;
+#endif
--- a/lib/float.in.h
+++ b/lib/float.in.h
@@ -29,6 +29,7 @@
 #define _@GUARD_PREFIX@_FLOAT_H
 
 /* 'long double' properties.  */
+
 #if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__)
 /* Number of mantissa units, in base FLT_RADIX.  */
 # undef LDBL_MANT_DIG
@@ -59,5 +60,115 @@
 # define LDBL_MAX_10_EXP 4932
 #endif
 
+/* On FreeBSD/x86 6.4, the 'long double' type really has only 53 bits of
+   precision in the compiler but 64 bits of precision at runtime.  See
+   <http://lists.gnu.org/archive/html/bug-gnulib/2008-07/msg00063.html>.  */
+#if defined __i386__ && defined __FreeBSD__
+/* Number of mantissa units, in base FLT_RADIX.  */
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG   64
+/* Number of decimal digits that is sufficient for representing a number.  */
+# undef LDBL_DIG
+# define LDBL_DIG        18
+/* x-1 where x is the smallest representable number > 1.  */
+# undef LDBL_EPSILON
+# define LDBL_EPSILON 1.084202172485504434007452800869941711426e-19L /* 2^-63 */
+/* Minimum e such that FLT_RADIX^(e-1) is a normalized number.  */
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP    (-16381)
+/* Maximum e such that FLT_RADIX^(e-1) is a representable finite number.  */
+# undef LDBL_MAX_EXP
+# define LDBL_MAX_EXP    16384
+/* Minimum positive normalized number.  */
+# undef LDBL_MIN
+# define LDBL_MIN        3.3621031431120935E-4932L /* = 0x1p-16382L */
+/* Maximum representable finite number.  */
+# undef LDBL_MAX
+/* LDBL_MAX is represented as { 0xFFFFFFFF, 0xFFFFFFFF, 32766 }.
+   But the largest literal that GCC allows us to write is
+   0x0.fffffffffffff8p16384L = { 0xFFFFF800, 0xFFFFFFFF, 32766 }.
+   So, define it like this through a reference to an external variable
+
+     const unsigned int LDBL_MAX[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 32766 };
+     extern const long double LDBL_MAX;
+
+   Unfortunately, this is not a constant expression.  */
+union gl_long_double_union
+  {
+    struct { unsigned int lo; unsigned int hi; unsigned int exponent; } xd;
+    long double ld;
+  };
+extern const union gl_long_double_union gl_LDBL_MAX;
+# define LDBL_MAX (gl_LDBL_MAX.ld)
+/* Minimum e such that 10^e is in the range of normalized numbers.  */
+# undef LDBL_MIN_10_EXP
+# define LDBL_MIN_10_EXP (-4931)
+/* Maximum e such that 10^e is in the range of representable finite numbers.  */
+# undef LDBL_MAX_10_EXP
+# define LDBL_MAX_10_EXP 4932
+#endif
+
+/* On AIX 7.1 with gcc 4.2, the values of LDBL_MIN_EXP, LDBL_MIN, LDBL_MAX are
+   wrong.  */
+#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP DBL_MIN_EXP
+# undef LDBL_MIN_10_EXP
+# define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+# undef LDBL_MIN
+# define LDBL_MIN 2.22507385850720138309023271733240406422e-308L /* DBL_MIN = 2^-1022 */
+# undef LDBL_MAX
+/* LDBL_MAX is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xFFFFFFFF }.
+   It is not easy to define:
+     #define LDBL_MAX 1.79769313486231580793728971405302307166e308L
+   is too small, whereas
+     #define LDBL_MAX 1.79769313486231580793728971405302307167e308L
+   is too large.  Apparently a bug in GCC decimal-to-binary conversion.
+   Also, I can't get values larger than
+     #define LDBL63 ((long double) (1ULL << 63))
+     #define LDBL882 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
+     #define LDBL945 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
+     #define LDBL1008 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
+     #define LDBL_MAX (LDBL1008 * 65535.0L + LDBL945 * (long double) 9223372036821221375ULL + LDBL882 * (long double) 4611686018427387904ULL)
+   which is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xF8000000 }.
+   So, define it like this through a reference to an external variable
+
+     const double LDBL_MAX[2] = { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL };
+     extern const long double LDBL_MAX;
+
+   or through a pointer cast
+
+     #define LDBL_MAX \
+       (*(const long double *) (double[]) { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL })
+
+   Unfortunately, this is not a constant expression, and the latter expression
+   does not work well when GCC is optimizing..  */
+union gl_long_double_union
+  {
+    struct { double hi; double lo; } dd;
+    long double ld;
+  };
+extern const union gl_long_double_union gl_LDBL_MAX;
+# define LDBL_MAX (gl_LDBL_MAX.ld)
+#endif
+
+/* On IRIX 6.5, with cc, the value of LDBL_MANT_DIG is wrong.
+   On IRIX 6.5, with gcc 4.2, the values of LDBL_MIN_EXP, LDBL_MIN, LDBL_EPSILON
+   are wrong.  */
+#if defined __sgi && (LDBL_MANT_DIG >= 106)
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG 106
+# if defined __GNUC__
+#  undef LDBL_MIN_EXP
+#  define LDBL_MIN_EXP DBL_MIN_EXP
+#  undef LDBL_MIN_10_EXP
+#  define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#  undef LDBL_MIN
+#  define LDBL_MIN 2.22507385850720138309023271733240406422e-308L /* DBL_MIN = 2^-1022 */
+#  undef LDBL_EPSILON
+#  define LDBL_EPSILON 2.46519032881566189191165176650870696773e-32L /* 2^-105 */
+# endif
+#endif
+
 #endif /* _@GUARD_PREFIX@_FLOAT_H */
 #endif /* _@GUARD_PREFIX@_FLOAT_H */
--- a/m4/float_h.m4
+++ b/m4/float_h.m4
@@ -1,4 +1,4 @@
-# float_h.m4 serial 6
+# float_h.m4 serial 7
 dnl Copyright (C) 2007, 2009-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,12 +9,41 @@
   AC_REQUIRE([AC_PROG_CC])
   AC_REQUIRE([AC_CANONICAL_HOST])
   FLOAT_H=
+  REPLACE_FLOAT_LDBL=0
   case "$host_os" in
-    beos* | openbsd* | mirbsd*)
+    aix* | beos* | openbsd* | mirbsd* | irix*)
       FLOAT_H=float.h
-      gl_NEXT_HEADERS([float.h])
+      ;;
+    freebsd*)
+      case "$host_cpu" in
+changequote(,)dnl
+        i[34567]86 )
+changequote([,])dnl
+          FLOAT_H=float.h
+          ;;
+        x86_64 )
+          # On x86_64 systems, the C compiler may still be generating
+          # 32-bit code.
+          AC_EGREP_CPP([yes],
+            [#if defined __LP64__ || defined __x86_64__ || defined __amd64__
+             yes
+             #endif],
+            [],
+            [FLOAT_H=float.h])
+          ;;
+      esac
       ;;
   esac
+  case "$host_os" in
+    aix* | freebsd*)
+      if test -n "$FLOAT_H"; then
+        REPLACE_FLOAT_LDBL=1
+      fi
+      ;;
+  esac
+  if test -n "$FLOAT_H"; then
+    gl_NEXT_HEADERS([float.h])
+  fi
   AC_SUBST([FLOAT_H])
   AM_CONDITIONAL([GL_GENERATE_FLOAT_H], [test -n "$FLOAT_H"])
 ])
--- a/modules/float
+++ b/modules/float
@@ -3,6 +3,7 @@
 
 Files:
 lib/float.in.h
+lib/float.c
 m4/float_h.m4
 
 Depends-on:
@@ -10,6 +11,9 @@
 
 configure.ac:
 gl_FLOAT_H
+if test $REPLACE_FLOAT_LDBL = 1; then
+  AC_LIBOBJ([float])
+fi
 
 Makefile.am:
 BUILT_SOURCES += $(FLOAT_H)