From: Bruno Haible Date: Wed, 31 Jul 2024 22:46:49 +0000 (+0200) Subject: float: Update to mostly guarantee ISO C 23 compliance. X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=fda40b6102f6a7452143d9c5cb66000805ace3b2;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 872cc0f6cb..bdedb82c3a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2024-07-31 Bruno Haible + + 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 attribute: Improve documentation. diff --git a/doc/posix-headers/float.texi b/doc/posix-headers/float.texi index 8e01932582..0dc41d7890 100644 --- a/doc/posix-headers/float.texi +++ b/doc/posix-headers/float.texi @@ -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 diff --git a/lib/float.c b/lib/float.c index a9ea40b063..7a563048e2 100644 --- a/lib/float.c +++ b/lib/float.c @@ -20,14 +20,101 @@ /* Specification. */ #include -#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 + . */ +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 ) */ + { 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 diff --git a/lib/float.in.h b/lib/float.in.h index 73e8d40621..5e78b4f296 100644 --- a/lib/float.in.h +++ b/lib/float.in.h @@ -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 . */ +# 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 . */ +# 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 . */ +# 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. */ diff --git a/m4/float_h.m4 b/m4/float_h.m4 index c95d417161..12c0eb6749 100644 --- a/m4/float_h.m4 +++ b/m4/float_h.m4 @@ -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 + 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], diff --git a/modules/float b/modules/float index 600de5ebee..85c0571f18 100644 --- a/modules/float +++ b/modules/float @@ -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) diff --git a/modules/float-tests b/modules/float-tests index a68e0216dd..7cb0870983 100644 --- a/modules/float-tests +++ b/modules/float-tests @@ -5,6 +5,9 @@ tests/macros.h Depends-on: fpieee fpucw +isnanf-nolibm +isnand-nolibm +isnanl-nolibm float-c++-tests configure.ac: diff --git a/tests/test-float.c b/tests/test-float.c index c8006058e4..7614e32e07 100644 --- a/tests/test-float.c +++ b/tests/test-float.c @@ -20,8 +20,12 @@ #include -/* 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. + */ + 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. + */ + 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. + */ + 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