Subject: bug#7228: coreutils-8.6 sort-float failure on ppc

From: Jim Meyering <[email-masked]>
Date: Sat, 16 Oct 2010 21:14:48 +0200

Gilles Espinasse wrote:
> Just tested 8.6 on linux glibc-2.11.1/gcc-4.4.5 LFS build on x86, sparc and
> ppc
>
> First a good news is that on sparc (32-bits), 8.6 test suite is now passing
> I didn't report yet a failure on misc/stty which was
> Failure was
> + stty -icanon
> stty: standard input: unable to perform all requested operations

Is that consistently reproducible?
If so, you might want to investigate, but it's probably not a big deal.

> The bad news is that it fail now on ppc in FAIL: misc/sort-float
>
> + LC_ALL=C
> + sort -sg
> + compare out exp
> + diff -u out exp
> --- out 2010-10-16 13:40:44.000000000 +0000
> +++ exp 2010-10-16 13:40:44.000000000 +0000
> @@ -2,11 +2,11 @@
>  -1.797693e+308
>  -3.402823e+38
>  -1.175494e-38
> --2.004168e-292
>  -2.225074e-308
> +-2.004168e-292
>  0
> -2.225074e-308
>  2.004168e-292
> +2.225074e-308
>  1.175494e-38
>  3.402823e+38
>  1.797693e+308
> + fail=1
> ...
> + LC_ALL=fr_FR
> + sort -sg
> + compare out exp
> + diff -u out exp
> --- out 2010-10-16 13:40:44.000000000 +0000
> +++ exp 2010-10-16 13:40:44.000000000 +0000
> @@ -2,11 +2,11 @@
>  -1,797693e+308
>  -3,402823e+38
>  -1,175494e-38
> --2,004168e-292
>  -2,225074e-308
> +-2,004168e-292
>  0
> -2,225074e-308
>  2,004168e-292
> +2,225074e-308
>  1,175494e-38
>  3,402823e+38
>  1,797693e+308
> + fail=1
> + Exit 1

Thank you for the report.
The expected output ("exp") above was generated via this:

      printf -- "\
    -$LDBL_MAX
    -$DBL_MAX
    -$FLT_MAX
    -$FLT_MIN
    -$DBL_MIN
    -$LDBL_MIN
    0
    $LDBL_MIN
    $DBL_MIN
    $FLT_MIN
    $FLT_MAX
    $DBL_MAX
    $LDBL_MAX
    " ...

Along with the diff output above, you can see that
your system's LDBL_MIN is *larger* than its DBL_MIN.
The test did not account for that possibility, since
LDBL_MIN is usually smaller than DBL_MIN.

We'll adjust the test to allow for that.

One way would be to compare $LDBL_MIN and $DBL_MIN manually,
extracting and comparing the exponents, the whole part of each mantissa
and finally the fractional part of each mantissa, stopping whenever
you find a difference.
While using awk would be cleaner, it may be more likely to fail
for values at the extremes.

Apply the following patch and the test should pass:

>From 3cce70f0a4fd06954430faf86efd4a53a606a88a Mon Sep 17 00:00:00 2001
From: Jim Meyering <[email-masked]>
Date: Sat, 16 Oct 2010 20:18:19 +0200
Subject: [PATCH] tests: sort-float: avoid spurious test failure on ppc64

* tests/misc/sort-float: On systems with DBL_MIN < LDBL_MIN,
this test would fail because the expected output was not sorted.
Detect that case, and if needed, reverse those two values.
---
 tests/misc/sort-float |   41 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/tests/misc/sort-float b/tests/misc/sort-float
index 639cd7e..f9e0e69 100755
--- a/tests/misc/sort-float
+++ b/tests/misc/sort-float
@@ -23,6 +23,39 @@ fi

 . $srcdir/test-lib.sh

+# Return 0 if LDBL_MIN is smaller than DBL_MIN, else 1.
+# Dissect numbers like these, comparing first exponent, then
+# whole part of mantissa, then fraction, until finding enough
+# of a difference to determine the relative order of the numbers.
+# These are "reversed":
+#   $ ./getlimits |grep DBL_MIN
+#   DBL_MIN=2.225074e-308
+#   LDBL_MIN=2.004168e-292
+#
+# These are in the expected order:
+#   $ ./getlimits|grep DBL_MIN
+#   DBL_MIN=2.225074e-308
+#   LDBL_MIN=3.362103e-4932
+
+dbl_minima_order()
+{
+  LC_ALL=C getlimits_
+  set -- $(echo $LDBL_MIN | tr .e- '   ')
+  local ldbl_whole=$1 ldbl_frac=$2 ldbl_exp=$3
+
+  set -- $(echo $DBL_MIN |tr .e- '   ')
+  local dbl_whole=$1 dbl_frac=$2 dbl_exp=$3
+
+  test "$dbl_exp" -lt "$ldbl_exp" && return 0
+  test "$ldbl_exp" -lt "$dbl_exp" && return 1
+  test "$dbl_whole" -lt "$ldbl_whole" && return 0
+  test "$ldbl_whole" -lt "$dbl_whole" && return 1
+  test "$dbl_frac" -le "$ldbl_frac" && return 0
+  return 1
+}
+
+dbl_minima_order; reversed=$?
+
 for LOC in C $LOCALE_FR; do

   LC_ALL=$LOC getlimits_
@@ -31,6 +64,14 @@ for LOC in C $LOCALE_FR; do
   grep '^#define HAVE_C99_STRTOLD 1' $CONFIG_HEADER > /dev/null ||
     { LDBL_MAX="$DBL_MAX"; LDBL_MIN="$DBL_MIN"; }

+  # If DBL_MIN happens to be smaller than LDBL_MIN, swap them,
+  # so that out expected output is sorted.
+  if test $reversed = 1; then
+    t=$LDBL_MIN
+    LDBL_MIN=$DBL_MIN
+    DBL_MIN=$t
+  fi
+
   printf -- "\
 -$LDBL_MAX
 -$DBL_MAX
--
1.7.3.1.526.g2ee4