+2023-10-14 Bruno Haible <bruno@clisp.org>
+
+ totalorder*: Fix test failures on PA-RISC and MIPS CPUs.
+ * lib/totalorderf.c (totalorderf): On hppa and mips, invert bit 22
+ before comparing two NaNs.
+ * lib/totalorder.c (totalorder): On hppa and mips, invert bit 51 before
+ comparing two NaNs.
+ * lib/totalorderl.c: Include <float.h>.
+ (totalorderl): On hppa and mips, invert bit 51 or 47 of the xhi, yhi
+ parts before comparing two NaNs.
+ * modules/totalorderl (Depends-on): Add 'float'.
+
2023-10-14 Bruno Haible <bruno@clisp.org>
totalorder* tests: Test also the signalling NaNs.
#include <config.h>
+/* Specification. */
#include <math.h>
int
totalorder (double const *x, double const *y)
{
- /* Although the following is not strictly portable, and won't work
- on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
- to IEEE 754-2008), it should be good enough nowadays. */
+ /* If the sign bits of *X and *Y differ, the one with non-zero sign bit
+ is "smaller" than the one with sign bit == 0. */
int xs = signbit (*x);
int ys = signbit (*y);
if (!xs != !ys)
return xs;
+
+ /* If one of *X, *Y is a NaN and the other isn't, the answer is easy
+ as well: the negative NaN is "smaller", the positive NaN is "greater"
+ than the other argument. */
int xn = isnand (*x);
int yn = isnand (*y);
if (!xn != !yn)
return !xn == !xs;
+ /* If none of *X, *Y is a NaN, the '<=' operator does the job, including
+ for -Infinity and +Infinity. */
if (!xn)
return *x <= *y;
+ /* At this point, *X and *Y are NaNs with the same sign bit. */
+
unsigned long long extended_sign = -!!xs;
+#if defined __hppa || defined __mips__
+ /* Invert the most significant bit of the mantissa field. Cf. snan.h. */
+ extended_sign ^= (1ULL << 51);
+#endif
union { unsigned long long i; double f; } volatile xu = {0}, yu = {0};
xu.f = *x;
yu.f = *y;
#include <config.h>
+/* Specification. */
#include <math.h>
int
totalorderf (float const *x, float const *y)
{
- /* Although the following is not strictly portable, and won't work
- on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
- to IEEE 754-2008), it should be good enough nowadays. */
+ /* If the sign bits of *X and *Y differ, the one with non-zero sign bit
+ is "smaller" than the one with sign bit == 0. */
int xs = signbit (*x);
int ys = signbit (*y);
if (!xs != !ys)
return xs;
+
+ /* If one of *X, *Y is a NaN and the other isn't, the answer is easy
+ as well: the negative NaN is "smaller", the positive NaN is "greater"
+ than the other argument. */
int xn = isnanf (*x);
int yn = isnanf (*y);
if (!xn != !yn)
return !xn == !xs;
+ /* If none of *X, *Y is a NaN, the '<=' operator does the job, including
+ for -Infinity and +Infinity. */
if (!xn)
return *x <= *y;
- unsigned long extended_sign = -!!xs;
- union { unsigned long i; float f; } volatile xu = {0}, yu = {0};
+ /* At this point, *X and *Y are NaNs with the same sign bit. */
+
+ unsigned int extended_sign = -!!xs;
+#if defined __hppa || defined __mips__
+ /* Invert the most significant bit of the mantissa field. Cf. snan.h. */
+ extended_sign ^= (1U << 22);
+#endif
+ union { unsigned int i; float f; } volatile xu = {0}, yu = {0};
xu.f = *x;
yu.f = *y;
return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign);
#include <config.h>
+/* Specification. */
#include <math.h>
+#include <float.h>
+
#ifndef LDBL_SIGNBIT_WORD
# define LDBL_SIGNBIT_WORD (-1)
#endif
int
totalorderl (long double const *x, long double const *y)
{
- /* Although the following is not strictly portable, and won't work
- on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
- to IEEE 754-2008), it should be good enough nowadays. */
-
/* If the sign bits of *X and *Y differ, the one with non-zero sign bit
is "smaller" than the one with sign bit == 0. */
int xs = signbit (*x);
if (sizeof (long double) <= sizeof (unsigned long long))
{
+#if defined __hppa || defined __mips__
+ /* Invert the most significant bit of the mantissa field. Cf. snan.h. */
+ extended_sign ^= (1ULL << 51);
+#endif
union { unsigned long long i; long double f; } volatile
xu = {0}, yu = {0};
xu.f = *x;
return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign);
}
+ unsigned long long extended_sign_hi = extended_sign;
+#if defined __hppa || defined __mips__
+ /* Invert the most significant bit of the mantissa field. Cf. snan.h. */
+ extended_sign_hi ^=
+ (1ULL << (LDBL_MANT_DIG == 106
+ ? 51 /* double-double representation */
+ : (LDBL_MANT_DIG - 2) - 64)); /* quad precision representation */
+#endif
union u { unsigned long long i[2]; long double f; } volatile xu, yu;
/* Although it is tempting to initialize with {0}, Solaris cc (Sun C 5.8)
on x86_64 miscompiles {0}: it initializes only the lower 80 bits,
bigendian = LDBL_SIGNBIT_WORD < sizeof xu.i[0] / sizeof (unsigned);
unsigned long long
- xhi = xu.i[!bigendian] ^ extended_sign,
- yhi = yu.i[!bigendian] ^ extended_sign,
+ xhi = xu.i[!bigendian] ^ extended_sign_hi,
+ yhi = yu.i[!bigendian] ^ extended_sign_hi,
xlo = xu.i[ bigendian] ^ extended_sign,
ylo = yu.i[ bigendian] ^ extended_sign;
return (xhi < yhi) | ((xhi == yhi) & (xlo <= ylo));
Depends-on:
math
extensions
+float [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
stdbool [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
isnanl [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
signbit [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]