This is the mail archive of the cygwin-apps mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Dodgy functions (finitel, strold)


Achim Gratz writes:
> Achim Gratz writes:
>> Long story short, they seem to report a finite value on at least some
>> NaN constructs and then the %a format for the Perl sprintf outputs those
>> bits as a hex FP number rather than just printing "NaN".  On 64bit the
>> culprit is actually finitel, of course, since Perl gets compiled with
>> long doubles.
>
> And looking into newlib this seems to be a compile bug, because the
> function just uses an intrinsic.

But the compiler is innocent, because newlib uses the wrong intrinsic or
an incomplete implementation.  If it must be using that intrinsic for
compatibility reasons, it would need to implement

--8<---------------cut here---------------start------------->8---
return (x == x) ? (__builtin_isinf_sign (x) == 0) : 0;
--8<---------------cut here---------------end--------------->8---

so it doesn't report NaN as finite.  NaN compares unequal even with
itself, so the first part implements !isnan(x).  But it should really
just use

--8<---------------cut here---------------start------------->8---
return __builtin_isfinite;
--8<---------------cut here---------------end--------------->8---

provided that is available from all targeted compilers.

So it's a newlib bug.  But for whatever reason I couldn't make it appear
in a simple test case, most likely because gcc somehow recognized
something about it and replaced it with the correct version when
compiling with the standard options, so it never links in the wrong
newlib implementation.  However, compiling with -std=c89 (like Perl)
finally teases it out.

I've extended the test program from Corinna so it compiles with both
options and doesn't crash with no input.  This also uncovered a separate
bug with strtold (which is only available in C99 mode).

--8<---------------cut here---------------start------------->8---
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
int
test_infsgn (double x)
{
  return __builtin_isinf_sign (x) == 0;
}
 
int
test_infsgnl (long double x)
{
  return __builtin_isinf_sign (x) == 0;
}
 
int
test_finite (double x)
{
  return __builtin_isfinite (x);
}
 
int
test_finitel (long double x)
{
  return __builtin_isfinite (x);
}
 
int
main (int argc, char **argv)
{
  printf ("===== got %d argument(s)\n", argc);
  int i=0;
  while (++i < argc) {
    double a = strtod (argv[i], NULL);
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
    long double b = strtold (argv[i], NULL);
#endif
    long double c = a;
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
    printf ("===== arg[%d] = (double) %a = (long double) %La = (long double)(double) %La\n", i, a, b, c);
#else
    printf ("===== arg[%d] = (double) %a = (long double)(double) %La\n", i, a, c);
#endif
    printf ("infsgn:              (double) %d\n", test_infsgn (a));
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
    printf ("infsgn:         (long double) %d\n", test_infsgnl (b));
#endif
    printf ("infsgn: (long double)(double) %d\n", test_infsgnl (c));
    printf ("finite:              (double) %d\n", test_finite (a));
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
    printf ("finite:         (long double) %d\n", test_finitel (b));
#endif
    printf ("finite: (long double)(double) %d\n", test_finitel (c));
    printf ("newlib:              (double) %d\n", finite (a));
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
    printf ("newlib:         (long double) %d\n", finitel (b));
#endif
    printf ("newlib: (long double)(double) %d\n", finitel (c));
  }
  printf ("===== ran out of args\n");
  return 0;
}
--8<---------------cut here---------------end--------------->8---

Compilation with C89 showing the newlib bug:

--8<---------------cut here---------------start------------->8---
$ gcc -std=c89 infnan.c -o infnan && ./infnan 1 nan -inf +inf
===== got 5 argument(s)
===== arg[1] = (double) 0x1p+0 = (long double)(double) 0x1p+0
infsgn:              (double) 1
infsgn: (long double)(double) 1
finite:              (double) 1
finite: (long double)(double) 1
newlib:              (double) 1
newlib: (long double)(double) 1
===== arg[2] = (double) nan = (long double)(double) nan
infsgn:              (double) 1
infsgn: (long double)(double) 1
finite:              (double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib: (long double)(double) 1
===== arg[3] = (double) -inf = (long double)(double) -inf
infsgn:              (double) 0
infsgn: (long double)(double) 0
finite:              (double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib: (long double)(double) 0
===== arg[4] = (double) inf = (long double)(double) inf
infsgn:              (double) 0
infsgn: (long double)(double) 0
finite:              (double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib: (long double)(double) 0
===== ran out of args
--8<---------------cut here---------------end--------------->8---

Compilation with C99 showing that strtold still doesn't work correctly
(it folds Inf->NaN):

--8<---------------cut here---------------start------------->8---
 gcc -std=c99 infnan.c -o infnan && ./infnan 1 nan -inf +inf
===== got 5 argument(s)
===== arg[1] = (double) 0x1p+0 = (long double) 0x1p+0 = (long double)(double) 0x1p+0
infsgn:              (double) 1
infsgn:         (long double) 1
infsgn: (long double)(double) 1
finite:              (double) 1
finite:         (long double) 1
finite: (long double)(double) 1
newlib:              (double) 1
newlib:         (long double) 1
newlib: (long double)(double) 1
===== arg[2] = (double) nan = (long double) nan = (long double)(double) nan
infsgn:              (double) 1
infsgn:         (long double) 1
infsgn: (long double)(double) 1
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 1
newlib: (long double)(double) 1
===== arg[3] = (double) -inf = (long double) nan = (long double)(double) -inf
infsgn:              (double) 0
infsgn:         (long double) 1
infsgn: (long double)(double) 0
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 1
newlib: (long double)(double) 0
===== arg[4] = (double) inf = (long double) nan = (long double)(double) inf
infsgn:              (double) 0
infsgn:         (long double) 1
infsgn: (long double)(double) 0
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 1
newlib: (long double)(double) 0
===== ran out of args
--8<---------------cut here---------------end--------------->8---

Finally, here's gcc making a run-around the bug in newlib (it was no fun
finding _that_, since it cost me two days of sleuthing to recognize that
I'd been lied to by the test program):

--8<---------------cut here---------------start------------->8---
$ gcc infnan.c -o infnan && ./infnan 1 nan -inf +inf
===== got 5 argument(s)
===== arg[1] = (double) 0x1p+0 = (long double) 0x1p+0 = (long double)(double) 0x1p+0
infsgn:              (double) 1
infsgn:         (long double) 1
infsgn: (long double)(double) 1
finite:              (double) 1
finite:         (long double) 1
finite: (long double)(double) 1
newlib:              (double) 1
newlib:         (long double) 1
newlib: (long double)(double) 1
===== arg[2] = (double) nan = (long double) nan = (long double)(double) nan
infsgn:              (double) 1
infsgn:         (long double) 1
infsgn: (long double)(double) 1
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 0
newlib: (long double)(double) 0
===== arg[3] = (double) -inf = (long double) nan = (long double)(double) -inf
infsgn:              (double) 0
infsgn:         (long double) 1
infsgn: (long double)(double) 0
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 0
newlib: (long double)(double) 0
===== arg[4] = (double) inf = (long double) nan = (long double)(double) inf
infsgn:              (double) 0
infsgn:         (long double) 1
infsgn: (long double)(double) 0
finite:              (double) 0
finite:         (long double) 0
finite: (long double)(double) 0
newlib:              (double) 0
newlib:         (long double) 0
newlib: (long double)(double) 0
===== ran out of args
--8<---------------cut here---------------end--------------->8---


Regards,
Achim.
-- 
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+

Factory and User Sound Singles for Waldorf Blofeld:
http://Synth.Stromeko.net/Downloads.html#WaldorfSounds


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]