Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Jun 2013 05:05:19 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Steve Kargl <sgk@troutmask.apl.washington.edu>
Cc:        David Schultz <das@CSAIL.MIT.EDU>, numerics@FreeBSD.org
Subject:   Re: isinf() on NaN args
Message-ID:  <20130606031050.Q17887@besplex.bde.org>
In-Reply-To: <20130605163712.GA74110@troutmask.apl.washington.edu>
References:  <20130605183354.V1244@besplex.bde.org> <20130605160558.GA44189@zim.MIT.EDU> <20130605163712.GA74110@troutmask.apl.washington.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 5 Jun 2013, Steve Kargl wrote:

> On Wed, Jun 05, 2013 at 09:05:58AM -0700, David Schultz wrote:
>> On Wed, Jun 05, 2013, Bruce Evans wrote:
>>> Is isinf(x) (or even fpclassify(x)) permitted to raise FE_INVALID if
>>> x is a (quiet) NaN?  It shouldn't, but I can't find where C99 requires
>>> this.  I can only find where C99 requires FE_INVALID to not be raised
>>> for comparison macros.
>>>
>>> It should raise if x is a signaling NaN, but C99 doesn't specify
>>> signaling NaNs and the hardware behaviour is more varied and the
>>> software bugs are larger for signaling NaNs, so getting this wrong in
>>> many cases doesn't matter much.
>>
>> The equivalent operation in IEEE-754R never raises an exception,
>> even for signaling NaNs.  If we ignore signaling NaNs for a
>> moment, I think the general idea is to raise an invalid exception
>> in two situations:

Is this new in 754R?  754 doesn't require it according to Steve's quote.
I now remember this part of 754.

> IIRC, C99 defers to IEC 60559 (aka IEEE 754) when a behavior is not
> specified within C99.  The copy of IEEE 754 that I have states
>
>   Some functions, such as the copy operation y := x without change
>   of format, may at the implementor's option be treated as nonarithmetic
>   operations which do not signal the invalid operation exception for
>   signaling NaNs; the functions in question are (1), (2), (6), and (7).
>   ...
>   (7) Isnan(x), or equivalently x != x, returns the value TRUE if x is
>       a NaN, and returns FALSE otherwise.
>
> This means that isnan is not required to raised the invalid operation.

Except for signaling NaNs.  These are required to raise invalid for
every operation in section 5.  These include comparisons but don't
include conversions without change of format.  If isnan(x) really is
required to be equivalent to x != x, IEEE754 isnan() is required to
raise invalid for signaling NaNs.

For quiet NaNs, isnan() raising invalid is implementation-defineded.  Since
C99 is older than 754R, it can't require much more than 754, so this must
be implementation-defined in C99 too.  isnan() on signaling NaNs is even
more implementation-defined, since C99 doesn't specify signaling NaNs.

All this seems to be implemented correctly by hardware and compilers
on x86.  Compilers alway use the unordered comparison operations fucom
(i387) and ucom (SSE).  These always raise invalid for signaling NaNs
but never for quiet NaNs (I only checked this for fucom).

Most of this is implemented less correctly for all macros at the level
of isnan() except the comparison ones.  Builtins are used for the latter,
so they work.  The other macros have various bugs, starting with their
slowness.  For signaling NaNs, their only (?) bug is that they only
raise invalid accidentally (when there is a conversion in the parameter
passing.  This is very machine-dependent).  This conforms to C99 but
not to IEEE754.

One thing I learned from investigating this recently is that it is not
a bug for isnan() and friends to sometimes raise invalid for signaling
NaNs.  They accidentally conform to IEEE754 when they do this.

x86 is easy to fix by using the builtins more.  On other arches, it
should be safe to use x != x for isnan() and fabs*(x) == INFINITY for
isinf(), since even if these raise invalid incorrectly, they just get
different cases wrong than now.  These expressions can be used on x86
too, so no ifdefs are needed.  Perhaps similarly for isfinite()
(fabs*(x) < INFINITY?) and isnormal().  fpclassify() and signbit() are
not so easy.

I investigated this more when emaste@ told me that __isinfl() never worked
on arches without real long doubles, except on alpha, since it uses a
hard-coded MAX_EXP that is only ifdefed for alpha.  Others like __isnanl()
never worked on alpha either.

Oops.  I just remembered that __isinfl() and its long double friends are
supposed to be unreacble on arches where they don't apply.  The isinf(x)
macro translates to isinf(x) for long double x on these arches.  It would
take either a compiler transalation of isinf(x) to __isinfl(x), or source
code hacks that do the same thing, or a direct call to __isinfl() to
reach it.  There is no weak symbol that translates isinfl() to __isinfl()
which would allow smaller code hacks to reach it.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130606031050.Q17887>