Re: std::isinf(-inf) strange results

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 13 February 2017 at 16:08, Andrew - <hidefromkgb@xxxxxxxxx> wrote:
> Is this the expected behaviour when std::isinf(-inf) yields 0 or -1
> instead of 1?
> Consider the source:
>
> #include <iostream>
> #include <limits>
> #include <cmath>
> int main() {
>     std::cout << "   ::isinf, long d = " <<
> ::isinf(-std::numeric_limits<long double>::infinity()) << std::endl
>               << "   ::isinf, double = " <<
> ::isinf(-std::numeric_limits<     double>::infinity()) << std::endl
>               << "   ::isinf, float  = " <<
> ::isinf(-std::numeric_limits<     float >::infinity()) << std::endl
>               << "std::isinf, long d = " <<
> std::isinf(-std::numeric_limits<long double>::infinity()) << std::endl
>               << "std::isinf, double = " <<
> std::isinf(-std::numeric_limits<     double>::infinity()) << std::endl
>               << "std::isinf, float  = " <<
> std::isinf(-std::numeric_limits<     float >::infinity()) <<
> std::endl;
>     return 0;
> }

This program is not conforming, to declare ::isinf you need to #include <math.h>

> $ # this is expected, everything`s all right
> $ g++ test.cpp
> $ ./a.out
>    ::isinf, long d = 1
>    ::isinf, double = 1
>    ::isinf, float  = 1
> std::isinf, long d = 1
> std::isinf, double = 1
> std::isinf, float  = 1
>
> $ # now let`s force -lm ... things begin to get weird
> $ g++ -fno-builtin-isinf -lm test.cpp
> $ ./a.out
>    ::isinf, long d = -1
>    ::isinf, double = -1
>    ::isinf, float  = -1
> std::isinf, long d = 1
> std::isinf, double = -1
> std::isinf, float  = 1

This is because your C library (which I'm guessing is GNU libc)
defines a non-conforming isinf(double). All three calls to ::isinf
call that one (converting the float and long double arguments to
double as needed).  The C++ library is limited in what it can do in
the face of the non-conforming C library function (which is defined
because it was part of Unix98). It adds std::isinf(float) and
std::isinf(long double) with the correct behaviour, but simply re-uses
the non-standard isinf(double) for std::isinf(double).

> $ # and now to insanity and beyond:
> $ g++ -Ofast test.cpp
> $ ./a.out
>    ::isinf, long d = -1
>    ::isinf, double = -1
>    ::isinf, float  = -1
> std::isinf, long d = 0
> std::isinf, double = -1
> std::isinf, float  = 0
>
> Granted, -Ofast is allowed to disregard some standards in favor of
> performance... but is it allowed to produce code that is plain wrong?

-Ofast is clearly documented to enable -ffast-math which turns on
-ffinite-math-only which means "Allow optimizations for floating-point
arithmetic that assume that arguments and results are not NaNs or
+-Infs."

If your program has floating-point values containing NaNs or
infinities then you should not be using those options.



> Furthermore, std::isinf sometimes takes the output of isinf from the
> math library without casting it to bool, which, as far as I know,
> doesn`t comply to the standard.

The standard says std::isinf is exactly the same function as isinf, so
if the C library defines isinf to return int, then we can't do
anything about that. The GNU C library no longer defines the
non-standard isinf and isnan functions, so std::isinf will be
confirming if the C library makes it possible. That was
https://gcc.gnu.org/PR48891 and if you use a recent glibc and a recent
GCC everything should be conforming.



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux