]> Savannah Git Hosting - gnulib.git/commitdiff
float: Update to mostly guarantee ISO C 23 compliance.
authorBruno Haible <bruno@clisp.org>
Wed, 31 Jul 2024 22:46:49 +0000 (00:46 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 31 Jul 2024 22:47:42 +0000 (00:47 +0200)
* doc/posix-headers/float.texi: Mention the various portability
problems.
* lib/float.in.h (FLT_HAS_SUBNORM, FLT_DECIMAL_DIG, FLT_TRUE_MIN,
DBL_HAS_SUBNORM, DBL_DECIMAL_DIG, DBL_TRUE_MIN, LDBL_HAS_SUBNORM,
LDBL_DECIMAL_DIG, LDBL_TRUE_MIN): New macros.
(gl_LDBL_TRUE_MIN): New declaration.
(FLT_IS_IEC_60559, FLT_NORM_MAX, FLT_SNAN, GNULIB_defined_FLT_SNAN,
DBL_IS_IEC_60559, DBL_NORM_MAX, DBL_SNAN, GNULIB_defined_DBL_SNAN,
LDBL_IS_IEC_60559, LDBL_NORM_MAX, LDBL_SNAN, GNULIB_defined_LDBL_SNAN):
New macros.
(gl_FLT_SNAN_t, gl_DBL_SNAN_t, gl_LDBL_SNAN_t): New types.
(gl_FLT_SNAN, gl_DBL_SNAN, gl_LDBL_SNAN): New declarations.
* lib/float.c (gl_LDBL_TRUE_MIN): New variable.
(gl_FLT_SNAN, gl_DBL_SNAN, gl_LDBL_SNAN): New variables.
* m4/float_h.m4 (gl_FLOAT_H): Add check whether float.h conforms to
ISO C23. Set REPLACE_FLOAT_SNAN.
* modules/float (configure.ac): Test also REPLACE_FLOAT_SNAN. Require
gl_BIGENDIAN.
* tests/test-float.c: Also check FLT_EVAL_METHOD, FLT_HAS_SUBNORM,
FLT_DECIMAL_DIG, FLT_IS_IEC_60559, FLT_TRUE_MIN, FLT_NORM_MAX,
DBL_HAS_SUBNORM, DBL_DECIMAL_DIG, DBL_IS_IEC_60559, DBL_TRUE_MIN,
DBL_NORM_MAX, LDBL_HAS_SUBNORM, LDBL_DECIMAL_DIG, LDBL_IS_IEC_60559.
Conditionally check LDBL_TRUE_MIN, LDBL_NORM_MAX.
Include isnanf-nolibm.h, isnand-nolibm.h, isnanl-nolibm.h.
(test_float): Check the values of FLT_HAS_SUBNORM, FLT_DECIMAL_DIG,
FLT_TRUE_MIN, FLT_IS_IEC_60559, FLT_NORM_MAX, FLT_SNAN.
(test_double): Check the values of DBL_HAS_SUBNORM, DBL_DECIMAL_DIG,
DBL_TRUE_MIN, DBL_IS_IEC_60559, DBL_NORM_MAX, DBL_SNAN.
(test_long_double): Check the values of LDBL_HAS_SUBNORM,
LDBL_DECIMAL_DIG, LDBL_TRUE_MIN, LDBL_IS_IEC_60559, LDBL_NORM_MAX,
LDBL_SNAN.
* modules/float-tests (Depends-on): Add isnanf-nolibm, isnand-nolibm,
isnanl-nolibm.

ChangeLog
doc/posix-headers/float.texi
lib/float.c
lib/float.in.h
m4/float_h.m4
modules/float
modules/float-tests
tests/test-float.c

index 872cc0f6cb2790dc8faf50406a8c6eef7513b3c2..bdedb82c3a2d93c2544dadf34d75db86870b3367 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2024-07-31  Bruno Haible  <bruno@clisp.org>
+
+       float: Update to mostly guarantee ISO C 23 compliance.
+       * doc/posix-headers/float.texi: Mention the various portability
+       problems.
+       * lib/float.in.h (FLT_HAS_SUBNORM, FLT_DECIMAL_DIG, FLT_TRUE_MIN,
+       DBL_HAS_SUBNORM, DBL_DECIMAL_DIG, DBL_TRUE_MIN, LDBL_HAS_SUBNORM,
+       LDBL_DECIMAL_DIG, LDBL_TRUE_MIN): New macros.
+       (gl_LDBL_TRUE_MIN): New declaration.
+       (FLT_IS_IEC_60559, FLT_NORM_MAX, FLT_SNAN, GNULIB_defined_FLT_SNAN,
+       DBL_IS_IEC_60559, DBL_NORM_MAX, DBL_SNAN, GNULIB_defined_DBL_SNAN,
+       LDBL_IS_IEC_60559, LDBL_NORM_MAX, LDBL_SNAN, GNULIB_defined_LDBL_SNAN):
+       New macros.
+       (gl_FLT_SNAN_t, gl_DBL_SNAN_t, gl_LDBL_SNAN_t): New types.
+       (gl_FLT_SNAN, gl_DBL_SNAN, gl_LDBL_SNAN): New declarations.
+       * lib/float.c (gl_LDBL_TRUE_MIN): New variable.
+       (gl_FLT_SNAN, gl_DBL_SNAN, gl_LDBL_SNAN): New variables.
+       * m4/float_h.m4 (gl_FLOAT_H): Add check whether float.h conforms to
+       ISO C23. Set REPLACE_FLOAT_SNAN.
+       * modules/float (configure.ac): Test also REPLACE_FLOAT_SNAN. Require
+       gl_BIGENDIAN.
+       * tests/test-float.c: Also check FLT_EVAL_METHOD, FLT_HAS_SUBNORM,
+       FLT_DECIMAL_DIG, FLT_IS_IEC_60559, FLT_TRUE_MIN, FLT_NORM_MAX,
+       DBL_HAS_SUBNORM, DBL_DECIMAL_DIG, DBL_IS_IEC_60559, DBL_TRUE_MIN,
+       DBL_NORM_MAX, LDBL_HAS_SUBNORM, LDBL_DECIMAL_DIG, LDBL_IS_IEC_60559.
+       Conditionally check LDBL_TRUE_MIN, LDBL_NORM_MAX.
+       Include isnanf-nolibm.h, isnand-nolibm.h, isnanl-nolibm.h.
+       (test_float): Check the values of FLT_HAS_SUBNORM, FLT_DECIMAL_DIG,
+       FLT_TRUE_MIN, FLT_IS_IEC_60559, FLT_NORM_MAX, FLT_SNAN.
+       (test_double): Check the values of DBL_HAS_SUBNORM, DBL_DECIMAL_DIG,
+       DBL_TRUE_MIN, DBL_IS_IEC_60559, DBL_NORM_MAX, DBL_SNAN.
+       (test_long_double): Check the values of LDBL_HAS_SUBNORM,
+       LDBL_DECIMAL_DIG, LDBL_TRUE_MIN, LDBL_IS_IEC_60559, LDBL_NORM_MAX,
+       LDBL_SNAN.
+       * modules/float-tests (Depends-on): Add isnanf-nolibm, isnand-nolibm,
+       isnanl-nolibm.
+
 2024-07-30  Bruno Haible  <bruno@clisp.org>
 
        attribute: Improve documentation.
index 8e01932582daa800f9ed7ce226f21bce129e4d0f..0dc41d789002adf2faba44811d0fe0bd6d16ced0 100644 (file)
@@ -21,6 +21,26 @@ in the compiler, not the real 64-bit precision at runtime.
 On Linux/PowerPC with GCC 4.4, and on AIX 7.1 with GCC 4.2,
 they don't reflect the ``double double'' representation of @code{long double}
 correctly.
+@item
+The macros
+@code{FLT_HAS_SUBNORM}, @code{FLT_DECIMAL_DIG}, @code{FLT_TRUE_MIN},
+@code{DBL_HAS_SUBNORM}, @code{DBL_DECIMAL_DIG}, @code{DBL_TRUE_MIN},
+@code{LDBL_HAS_SUBNORM}, @code{LDBL_DECIMAL_DIG}, @code{LDBL_TRUE_MIN},
+that were added in ISO C 11, are missing on some platforms:
+gcc 4.5.4, clang 7, Solaris 11.3 with Sun C.
+@item
+The macro @code{LDBL_DECIMAL_DIG} is missing on some platforms:
+MSVC 14.
+@item
+The value of macro @code{FLT_TRUE_MIN} is not a @code{float} on some platforms:
+AIX 7.1 with xlc.
+@item
+The macros
+@code{FLT_IS_IEC_60559}, @code{FLT_NORM_MAX}, @code{FLT_SNAN},
+@code{DBL_IS_IEC_60559}, @code{DBL_NORM_MAX}, @code{DBL_SNAN},
+@code{LDBL_IS_IEC_60559}, @code{LDBL_NORM_MAX}, @code{LDBL_SNAN},
+that were added in ISO C 23, are missing on some platforms:
+gcc 14 without @code{-std=c23} or @code{-std=gnu23}, clang 18, musl libc 1.2.5, AIX 7.3 with xlclang, Solaris 11.3 with Sun C, MSVC 14.
 @end itemize
 
 Portability problems not fixed by Gnulib:
@@ -29,4 +49,11 @@ Portability problems not fixed by Gnulib:
 The macro @code{FLT_ROUNDS} is a constant expression and does not represent
 the current rounding mode on some platforms:
 glibc 2.11, HP-UX 11, mingw.
+@item
+The value of @code{FLT_TRUE_MIN} is not a constant on some platforms:
+FreeBSD/x86.
+@item
+The values of @code{FLT_SNAN}, @code{DBL_SNAN}, @code{LDBL_SNAN} are not
+constants on some platforms:
+AIX 7.3 with xlclang, and all platforms which use the gnulib replacements.
 @end itemize
index a9ea40b063bdf04b1f9d72927324c2850b8f5159..7a563048e2ed1494dadf11cd91e9e06a382673c0 100644 (file)
 /* Specification.  */
 #include <float.h>
 
-#if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__
+#if GNULIB_defined_long_double_union
+# if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (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__
+# elif defined __i386__
 const union gl_long_double_union gl_LDBL_MAX =
   { { 0xFFFFFFFF, 0xFFFFFFFF, 32766 } };
-#else
+# endif
+# if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__)
+/* We can't even simply evaluate the formula (LDBL_MIN / 9223372036854775808.0L)
+   at run time, because it would require BEGIN_LONG_DOUBLE_ROUNDING /
+   END_LONG_DOUBLE_ROUNDING invocations.  It simpler to just write down the
+   representation of LDBL_TRUE_MIN, based on
+   <https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format>.  */
+const union gl_long_double_union gl_LDBL_TRUE_MIN =
+  { { 0x00000001, 0x00000000, 0 } };
+# endif
+#endif
+
+#if GNULIB_defined_FLT_SNAN
+/* Define like memory_positive_SNaNf(), see signed-snan.h and snan.h,
+   or like setpayloadsigf() with an arbitrary payload.  */
+gl_FLT_SNAN_t gl_FLT_SNAN =
+# if FLT_MANT_DIG == 24
+#  if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
+  /* sign bit: 0, 8 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
+  { { 0x7FE00000U } }
+#  else
+  /* sign bit: 0, 8 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
+  { { 0x7FA00000U } }
+#  endif
+# endif
+  ;
+#endif
+
+#if GNULIB_defined_DBL_SNAN
+/* Define like memory_positive_SNaNd(), see signed-snan.h and snan.h,
+   or like setpayloadsig() with an arbitrary payload.  */
+gl_DBL_SNAN_t gl_DBL_SNAN =
+# if DBL_MANT_DIG == 53
+#  if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
+  /* sign bit: 0, 11 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
+  { { 0x7FFC000000000000ULL } }
+#  else
+  /* sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
+  { { 0x7FF4000000000000ULL } }
+#  endif
+# endif
+  ;
+#endif
+
+#if GNULIB_defined_LDBL_SNAN
+# ifdef WORDS_BIGENDIAN
+#  define TWO(hi,lo) { hi, lo }
+# else
+#  define TWO(hi,lo) { lo, hi }
+# endif
+/* Define like memory_positive_SNaNl(), see signed-snan.h and snan.h,
+   or like setpayloadsigl() with an arbitrary payload.  */
+gl_LDBL_SNAN_t gl_LDBL_SNAN =
+# if LDBL_MANT_DIG == 53 /* on arm, hppa, mips, sh, but also MSVC */
+#  if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
+  /* sign bit: 0, 11 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
+  { { 0x7FFC000000000000ULL } }
+#  else
+  /* sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
+  { { 0x7FF4000000000000ULL } }
+#  endif
+# elif LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */
+#  if defined __m68k__
+  /* sign bit: 0, 15 exponent bits: all 1, 16 gap bits: all 0,
+     always=1 bit: 1, next bit: 0, payload: 0b10...0 */
+  { { 0x7FFF0000ULL, 0xA0000000ULL, 0x00000000ULL } }
+#  else
+  /* sign bit: 0, 15 exponent bits: all 1, always=1 bit: 1, next bit: 0, payload: 0b10...0
+     (see <https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format>) */
+  { TWO (0x00007FFFULL, 0xA000000000000000ULL) }
+#  endif
+# elif LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */
+  /* most-significant double:
+     sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0,
+     least-significant double: 0.0 */
+  { { 0x7FF4000000000000ULL, 0ULL } }
+# elif LDBL_MANT_DIG == 113 /* on alpha, arm64, loongarch64, mips64, riscv64, s390x, sparc64 */
+#  if (defined __mips__ && !MIPS_NAN2008_FLOAT)
+  /* sign bit: 0, 15 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
+  { TWO (0x7FFFC00000000000ULL, 0ULL) }
+#  else
+  /* sign bit: 0, 15 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
+  { TWO (0x7FFF400000000000ULL, 0ULL) }
+#  endif
+# endif
+  ;
+#endif
+
 /* This declaration is solely to ensure that after preprocessing
    this file is never empty.  */
 typedef int dummy;
-#endif
index 73e8d40621ffa521cddbab3e63168fbdd55dc8f3..5e78b4f296628f58aabc17ce04a7a0478f74592c 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef _@GUARD_PREFIX@_FLOAT_H
 #define _@GUARD_PREFIX@_FLOAT_H
 
+/* ============================ ISO C99 support ============================ */
+
 /* 'long double' properties.  */
 
 #if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__)
@@ -179,6 +181,156 @@ extern const union gl_long_double_union gl_LDBL_MAX;
 # endif
 #endif
 
+/* ============================ ISO C11 support ============================ */
+
+/* 'float' properties */
+
+#ifndef FLT_HAS_SUBNORM
+# define FLT_HAS_SUBNORM 1
+#endif
+#ifndef FLT_DECIMAL_DIG
+/* FLT_MANT_DIG = 24 => FLT_DECIMAL_DIG = 9 */
+# define FLT_DECIMAL_DIG ((int)(FLT_MANT_DIG * 0.3010299956639812 + 2))
+#endif
+#if defined _AIX && !defined __GNUC__
+/* On AIX, the value of FLT_TRUE_MIN in /usr/include/float.h is a 'double',
+   not a 'float'.  */
+# undef FLT_TRUE_MIN
+#endif
+#ifndef FLT_TRUE_MIN
+/* FLT_MIN / 2^(FLT_MANT_DIG-1) */
+# define FLT_TRUE_MIN (FLT_MIN / 8388608.0f)
+#endif
+
+/* 'double' properties */
+
+#ifndef DBL_HAS_SUBNORM
+# define DBL_HAS_SUBNORM 1
+#endif
+#ifndef DBL_DECIMAL_DIG
+/* DBL_MANT_DIG = 53 => DBL_DECIMAL_DIG = 17 */
+# define DBL_DECIMAL_DIG ((int)(DBL_MANT_DIG * 0.3010299956639812 + 2))
+#endif
+#ifndef DBL_TRUE_MIN
+/* DBL_MIN / 2^(DBL_MANT_DIG-1) */
+# define DBL_TRUE_MIN (DBL_MIN / 4503599627370496.0)
+#endif
+
+/* 'long double' properties */
+
+#ifndef LDBL_HAS_SUBNORM
+# define LDBL_HAS_SUBNORM 1
+#endif
+#ifndef LDBL_DECIMAL_DIG
+/* LDBL_MANT_DIG = 53 => LDBL_DECIMAL_DIG = 17 */
+/* LDBL_MANT_DIG = 64 => LDBL_DECIMAL_DIG = 21 */
+/* LDBL_MANT_DIG = 106 => LDBL_DECIMAL_DIG = 33 */
+/* LDBL_MANT_DIG = 113 => LDBL_DECIMAL_DIG = 36 */
+# define LDBL_DECIMAL_DIG ((int)(LDBL_MANT_DIG * 0.3010299956639812 + 2))
+#endif
+#ifndef LDBL_TRUE_MIN
+/* LDBL_MIN / 2^(LDBL_MANT_DIG-1) */
+# if LDBL_MANT_DIG == 53
+#  define LDBL_TRUE_MIN (LDBL_MIN / 4503599627370496.0L)
+# elif LDBL_MANT_DIG == 64
+#  if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__)
+/* Work around FreeBSD/x86 problem mentioned above.  */
+extern const union gl_long_double_union gl_LDBL_TRUE_MIN;
+#   define LDBL_TRUE_MIN (gl_LDBL_TRUE_MIN.ld)
+#  else
+#   define LDBL_TRUE_MIN (LDBL_MIN / 9223372036854775808.0L)
+#  endif
+# elif LDBL_MANT_DIG == 106
+#  define LDBL_TRUE_MIN (LDBL_MIN / 40564819207303340847894502572032.0L)
+# elif LDBL_MANT_DIG == 113
+#  define LDBL_TRUE_MIN (LDBL_MIN / 5192296858534827628530496329220096.0L)
+# endif
+#endif
+
+/* ============================ ISO C23 support ============================ */
+
+/* 'float' properties */
+
+#ifndef FLT_IS_IEC_60559
+# if defined __m68k__
+#  define FLT_IS_IEC_60559 0
+# else
+#  define FLT_IS_IEC_60559 1
+# endif
+#endif
+#ifndef FLT_NORM_MAX
+# define FLT_NORM_MAX FLT_MAX
+#endif
+#ifndef FLT_SNAN
+/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>.  */
+# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
+#  define FLT_SNAN __builtin_nansf ("")
+# else
+typedef union { unsigned int word[1]; float value; } gl_FLT_SNAN_t;
+extern gl_FLT_SNAN_t gl_FLT_SNAN;
+#  define FLT_SNAN (gl_FLT_SNAN.value)
+#  define GNULIB_defined_FLT_SNAN 1
+# endif
+#endif
+
+/* 'double' properties */
+
+#ifndef DBL_IS_IEC_60559
+# if defined __m68k__
+#  define DBL_IS_IEC_60559 0
+# else
+#  define DBL_IS_IEC_60559 1
+# endif
+#endif
+#ifndef DBL_NORM_MAX
+# define DBL_NORM_MAX DBL_MAX
+#endif
+#ifndef DBL_SNAN
+/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>.  */
+# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
+#  define DBL_SNAN __builtin_nans ("")
+# else
+typedef union { unsigned long long word[1]; double value; } gl_DBL_SNAN_t;
+extern gl_DBL_SNAN_t gl_DBL_SNAN;
+#  define DBL_SNAN (gl_DBL_SNAN.value)
+#  define GNULIB_defined_DBL_SNAN 1
+# endif
+#endif
+
+/* 'long double' properties */
+
+#ifndef LDBL_IS_IEC_60559
+# if defined __m68k__
+#  define LDBL_IS_IEC_60559 0
+# elif LDBL_MANT_DIG == 53 || LDBL_MANT_DIG == 113
+#  define LDBL_IS_IEC_60559 1
+# else
+#  define LDBL_IS_IEC_60559 0
+# endif
+#endif
+#ifndef LDBL_NORM_MAX
+# define LDBL_NORM_MAX LDBL_MAX
+#endif
+#ifndef LDBL_SNAN
+/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>.  */
+# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
+#  define LDBL_SNAN __builtin_nansl ("")
+# else
+#  if LDBL_MANT_DIG == 53
+typedef union { unsigned long long word[1]; long double value; } gl_LDBL_SNAN_t;
+#  elif defined __m68k__
+typedef union { unsigned int word[3]; long double value; } gl_LDBL_SNAN_t;
+#  else
+typedef union { unsigned long long word[2]; long double value; } gl_LDBL_SNAN_t;
+#  endif
+extern gl_LDBL_SNAN_t gl_LDBL_SNAN;
+#  define LDBL_SNAN (gl_LDBL_SNAN.value)
+#  define GNULIB_defined_LDBL_SNAN 1
+# endif
+#endif
+
+/* ================================= Other ================================= */
+
 #if @REPLACE_ITOLD@
 /* Pull in a function that fixes the 'int' to 'long double' conversion
    of glibc 2.7.  */
index c95d417161910bbe7eaf8453797b80ce37abd93c..12c0eb6749ccbabc4d31519862ea9e37d00e9f36 100644 (file)
@@ -1,5 +1,5 @@
 # float_h.m4
-# serial 14
+# serial 15
 dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -54,6 +54,31 @@ changequote([,])dnl
       ;;
   esac
 
+  dnl Test for completeness w.r.t. ISO C 23.
+  REPLACE_FLOAT_SNAN=0
+  AC_CACHE_CHECK([whether float.h conforms to ISO C23],
+    [gl_cv_header_float_h_isoc23],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <float.h>
+            int x[] = { FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG };
+            float maxf = FLT_NORM_MAX;
+            double maxd = DBL_NORM_MAX;
+            long double maxl = LDBL_NORM_MAX;
+          ]],
+          [[float sf = FLT_SNAN;
+            double sd = DBL_SNAN;
+            long double sl = LDBL_SNAN;
+            return (sf != 0) + (sd != 0) + (sl != 0);
+          ]])],
+       [gl_cv_header_float_h_isoc23=yes],
+       [gl_cv_header_float_h_isoc23=no])
+    ])
+  if test $gl_cv_header_float_h_isoc23 != yes; then
+    GL_GENERATE_FLOAT_H=true
+    REPLACE_FLOAT_SNAN=1
+  fi
+
   dnl Test against glibc-2.7 Linux/SPARC64 bug.
   REPLACE_ITOLD=0
   AC_CACHE_CHECK([whether conversion from 'int' to 'long double' works],
index 600de5ebee873ca918f5ea0fd33b4bd3b7427737..85c0571f18c4eb83b0844a37d0577b8dde8c6ebe 100644 (file)
@@ -15,8 +15,11 @@ configure.ac:
 gl_FLOAT_H
 gl_CONDITIONAL_HEADER([float.h])
 AC_PROG_MKDIR_P
-gl_CONDITIONAL([GL_COND_OBJ_FLOAT], [test $REPLACE_FLOAT_LDBL = 1])
+gl_CONDITIONAL([GL_COND_OBJ_FLOAT],
+               [test $REPLACE_FLOAT_LDBL = 1 || test $REPLACE_FLOAT_SNAN = 1])
 gl_CONDITIONAL([GL_COND_OBJ_ITOLD], [test $REPLACE_ITOLD = 1])
+dnl Prerequisites of lib/float.c.
+AC_REQUIRE([gl_BIGENDIAN])
 
 Makefile.am:
 BUILT_SOURCES += $(FLOAT_H)
index a68e0216dd5ea5e65e5624ee84d9c968ac741db2..7cb0870983822c0d6c323ffe231c474bda9f668a 100644 (file)
@@ -5,6 +5,9 @@ tests/macros.h
 Depends-on:
 fpieee
 fpucw
+isnanf-nolibm
+isnand-nolibm
+isnanl-nolibm
 float-c++-tests
 
 configure.ac:
index c8006058e45721ad9b537896646ac2a8805665c8..7614e32e072fe068cda100ad0c34bdd89548072c 100644 (file)
 
 #include <float.h>
 
-/* Check that FLT_RADIX is a constant expression.  */
-int a[] = { FLT_RADIX };
+/* Check that some macros are constant expressions.  */
+int a[] =
+  {
+    FLT_RADIX,
+    FLT_EVAL_METHOD /* added in ISO C 99 */
+  };
 
 /* ----------------------- Check macros for 'float' ----------------------- */
 
@@ -29,9 +33,20 @@ int a[] = { FLT_RADIX };
 int fb[] =
   {
     FLT_MANT_DIG, FLT_MIN_EXP, FLT_MAX_EXP,
-    FLT_DIG, FLT_MIN_10_EXP, FLT_MAX_10_EXP
+    FLT_DIG, FLT_MIN_10_EXP, FLT_MAX_10_EXP,
+    FLT_HAS_SUBNORM, /* added in ISO C 11 */
+    FLT_DECIMAL_DIG, /* added in ISO C 11 */
+    FLT_IS_IEC_60559 /* added in ISO C 23 */
   };
-float fc[] = { FLT_EPSILON, FLT_MIN, FLT_MAX };
+float fc[] =
+  {
+    FLT_EPSILON, FLT_MIN, FLT_MAX,
+    FLT_TRUE_MIN, /* added in ISO C 11 */
+    FLT_NORM_MAX /* added in ISO C 23 */
+  };
+#if 0 /* FLT_SNAN is not a constant expression on some platforms.  */
+float fs = FLT_SNAN; /* added in ISO C 23 */
+#endif
 
 /* ----------------------- Check macros for 'double' ----------------------- */
 
@@ -39,9 +54,20 @@ float fc[] = { FLT_EPSILON, FLT_MIN, FLT_MAX };
 int db[] =
   {
     DBL_MANT_DIG, DBL_MIN_EXP, DBL_MAX_EXP,
-    DBL_DIG, DBL_MIN_10_EXP, DBL_MAX_10_EXP
+    DBL_DIG, DBL_MIN_10_EXP, DBL_MAX_10_EXP,
+    DBL_HAS_SUBNORM, /* added in ISO C 11 */
+    DBL_DECIMAL_DIG, /* added in ISO C 11 */
+    DBL_IS_IEC_60559 /* added in ISO C 23 */
   };
-double dc[] = { DBL_EPSILON, DBL_MIN, DBL_MAX };
+double dc[] =
+  {
+    DBL_EPSILON, DBL_MIN, DBL_MAX,
+    DBL_TRUE_MIN, /* added in ISO C 11 */
+    DBL_NORM_MAX /* added in ISO C 23 */
+  };
+#if 0 /* DBL_SNAN is not a constant expression on some platforms.  */
+double ds = DBL_SNAN; /* added in ISO C 23 */
+#endif
 
 /* -------------------- Check macros for 'long double' -------------------- */
 
@@ -49,17 +75,36 @@ double dc[] = { DBL_EPSILON, DBL_MIN, DBL_MAX };
 int lb[] =
   {
     LDBL_MANT_DIG, LDBL_MIN_EXP, LDBL_MAX_EXP,
-    LDBL_DIG, LDBL_MIN_10_EXP, LDBL_MAX_10_EXP
+    LDBL_DIG, LDBL_MIN_10_EXP, LDBL_MAX_10_EXP,
+    LDBL_HAS_SUBNORM, /* added in ISO C 11 */
+    LDBL_DECIMAL_DIG, /* added in ISO C 11 */
+    LDBL_IS_IEC_60559 /* added in ISO C 23 */
   };
 long double lc1 = LDBL_EPSILON;
 long double lc2 = LDBL_MIN;
-#if 0 /* LDBL_MAX is not a constant expression on some platforms.  */
+#if !GNULIB_defined_long_double_union
+/* LDBL_MAX is not a constant expression on some platforms.  */
 long double lc3 = LDBL_MAX;
 #endif
+#if !GNULIB_defined_long_double_union
+/* LDBL_TRUE_MIN is not a constant expression on FreeBSD/i386.  */
+long double lc4 = LDBL_TRUE_MIN; /* added in ISO C 11 */
+#endif
+#if !GNULIB_defined_long_double_union
+/* LDBL_MAX is not a constant expression on some platforms.  */
+long double lc5 = LDBL_NORM_MAX; /* added in ISO C 23 */
+#endif
+#if 0
+/* LDBL_SNAN is not a constant expression on some platforms.  */
+long double ls = LDBL_SNAN; /* added in ISO C 23 */
+#endif
 
 /* ------------------------------------------------------------------------- */
 
 #include "fpucw.h"
+#include "isnanf-nolibm.h"
+#include "isnand-nolibm.h"
+#include "isnanl-nolibm.h"
 #include "macros.h"
 
 #if FLT_RADIX == 2
@@ -220,6 +265,34 @@ test_float (void)
           ASSERT (x <= 1.0f);
       }
   }
+
+  /* Check the value of FLT_HAS_SUBNORM.  */
+  ASSERT (FLT_HAS_SUBNORM == 1);
+
+  /* Check the value of FLT_DECIMAL_DIG.  */
+  ASSERT (FLT_DECIMAL_DIG == (int)(FLT_MANT_DIG * 0.3010299956639812 + 2));
+
+  /* Check the value of FLT_TRUE_MIN.  */
+  ASSERT (FLT_TRUE_MIN > 0.0f);
+  {
+    volatile float x = FLT_TRUE_MIN * 0.5f;
+    ASSERT (x == 0.0f);
+  }
+
+  /* Check the value of FLT_IS_IEC_60559.  */
+#if !defined __m68k__
+  ASSERT (FLT_IS_IEC_60559);
+#elif 0
+  /* It is not clear what this macro actually means.  Cf.
+     <http://mailman.oakapple.net/pipermail/cfp-interest/2023-April/002760.html> */
+  ASSERT (!FLT_IS_IEC_60559);
+#endif
+
+  /* Check the value of FLT_NORM_MAX.  */
+  ASSERT (FLT_NORM_MAX == FLT_MAX);
+
+  /* Check the value of FLT_SNAN.  */
+  ASSERT (isnanf (FLT_SNAN));
 }
 
 /* ----------------------- Check macros for 'double' ----------------------- */
@@ -291,6 +364,34 @@ test_double (void)
           ASSERT (x <= 1.0);
       }
   }
+
+  /* Check the value of DBL_HAS_SUBNORM.  */
+  ASSERT (DBL_HAS_SUBNORM == 1);
+
+  /* Check the value of DBL_DECIMAL_DIG.  */
+  ASSERT (DBL_DECIMAL_DIG == (int)(DBL_MANT_DIG * 0.3010299956639812 + 2));
+
+  /* Check the value of DBL_TRUE_MIN.  */
+  ASSERT (DBL_TRUE_MIN > 0.0);
+  {
+    volatile double x = DBL_TRUE_MIN * 0.5;
+    ASSERT (x == 0.0);
+  }
+
+  /* Check the value of DBL_IS_IEC_60559.  */
+#if !defined __m68k__
+  ASSERT (DBL_IS_IEC_60559);
+#elif 0
+  /* It is not clear what this macro actually means.  Cf.
+     <http://mailman.oakapple.net/pipermail/cfp-interest/2023-April/002760.html> */
+  ASSERT (!DBL_IS_IEC_60559);
+#endif
+
+  /* Check the value of DBL_NORM_MAX.  */
+  ASSERT (DBL_NORM_MAX == DBL_MAX);
+
+  /* Check the value of DBL_SNAN.  */
+  ASSERT (isnand (DBL_SNAN));
 }
 
 /* -------------------- Check macros for 'long double' -------------------- */
@@ -359,6 +460,34 @@ test_long_double (void)
           ASSERT (x <= 1.0L);
       }
   }
+
+  /* Check the value of LDBL_HAS_SUBNORM.  */
+  ASSERT (LDBL_HAS_SUBNORM == 1);
+
+  /* Check the value of LDBL_DECIMAL_DIG.  */
+  ASSERT (LDBL_DECIMAL_DIG == (int)(LDBL_MANT_DIG * 0.3010299956639812 + 2));
+
+  /* Check the value of LDBL_TRUE_MIN.  */
+  ASSERT (LDBL_TRUE_MIN > 0.0L);
+  {
+    volatile long double x = LDBL_TRUE_MIN * 0.5L;
+    ASSERT (x == 0.0L);
+  }
+
+  /* Check the value of LDBL_IS_IEC_60559.  */
+#if (LDBL_MANT_DIG == 53 || LDBL_MANT_DIG == 113) && !defined __m68k__
+  ASSERT (LDBL_IS_IEC_60559);
+#elif 0
+  /* It is not clear what this macro actually means.  Cf.
+     <http://mailman.oakapple.net/pipermail/cfp-interest/2023-April/002760.html> */
+  ASSERT (!LDBL_IS_IEC_60559);
+#endif
+
+  /* Check the value of LDBL_NORM_MAX.  */
+  ASSERT (LDBL_NORM_MAX == LDBL_MAX);
+
+  /* Check the value of LDBL_SNAN.  */
+  ASSERT (isnanl (LDBL_SNAN));
 }
 
 int