Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Aug 2012 23:01:46 -0000
From:      Bruce Evans <brde@optusnet.com.au>
To:        Peter Jeremy <peter@rulingia.com>
Cc:        Diane Bruce <db@db.net>, Steve Kargl <sgk@troutmask.apl.washington.edu>, John Baldwin <jhb@freebsd.org>, David Chisnall <theraven@freebsd.org>, Stephen Montgomery-Smith <stephen@missouri.edu>, Bruce Evans <bde@freebsd.org>, Bruce Evans <brde@optusnet.com.au>, David Schultz <das@freebsd.org>, Warner Losh <imp@bsdimp.com>
Subject:   Re: Use of C99 extra long double math functions after r236148
Message-ID:  <20120723143145.T1353@besplex.bde.org>
Resent-Message-ID: <20120812230138.GW20453@server.rulingia.com>
In-Reply-To: <20120722233134.GB8033@server.rulingia.com>
References:  <20120717042125.GF66913@server.rulingia.com> <20120717043848.GB87001@troutmask.apl.washington.edu> <20120717225328.GA86902@server.rulingia.com> <20120717232740.GA95026@troutmask.apl.washington.edu> <20120718001337.GA87817@server.rulingia.com> <20120718123627.D1575@besplex.bde.org> <20120722121219.GC73662@server.rulingia.com> <20120722220031.GA7791@server.rulingia.com> <20120722221614.GB53450@zim.MIT.EDU> <20120722231056.GA84338@troutmask.apl.washington.edu> <20120722233134.GB8033@server.rulingia.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 23 Jul 2012, Peter Jeremy wrote:

> On 2012-Jul-22 16:10:56 -0700, Steve Kargl <sgk@troutmask.apl.washington.edu> wrote:
>> The above isn't necessarily true.  The Fortran standards from
>> 2003 and 2008, very care about NaN.  Under certain conditions,
>> if one has something like
>>
>>   x = sin(NaN)
>>
>> in Fortran, then the returned NaN must be the one in the function
>> call.
>
> Even if it was a SNaN?  My understanding is that SNaN should be
> quietened if they are used in any further floating point operations.

This may depend on the language specification, but it can be hard to even
pass signaling NaNs without causing an exception.
   (The following interesting behaviour occurs on x86:
   - On i387, loading a float or double involves a conversion to long double.
     This conversion is considered to be an operation and it generates an
     exception and quietens signalling NaNs.
   - On i386, the ABI requires FP args to be passed on the stack.  Compilers
     may or may not load float and double args as part of putting them on
     the stack.  If they do, then by the previous point, functions never
     see float or double signaling NaN args, but functions always see
     long double signaling NaN args.  Then is a buggy function returns x
     when it should return x+x, the bug is not noticed for the float and
     double cases but it is noticed (if tested for) in the long double
     case.
   - On at least Athlon-xp and Athlon64 before Phenom, compilers should
     always load at least double args as part of putting them on the
     stack (or other memory), since copying them through integer registers
     is very slow (it causes store-to-load mismatches).  Compilers don't
     understand this well, but newer gcc is better and goes through the
     FPU more (going through SSE is good too).  Thus the previous points
     are affected by CFLAGS and compiler opt/pessimizations.
   - On SSE, no loads involve an implicit conversion and loads of signaling
     NaNs never trigger exception handling.
   - On amd64, SSE is the default for floats and doubles, so passing
     signaling NaNs never triggers the signal, although the ABI now
     the first few float and double args to be loaded into SSE registes
     for passing.
   - On i386, clang uses SSE too much, and thus triggers signaling NaNs
     less than gcc.
   )

>>  Having libm, do
>>
>>   if (x == NaN)
>>      return (x + x);
>>
>> does/may not return the correct NaN.

It usually does return the correct NaN.  There is no other reasonably
portable way to quieten signaling NaNs.

(x + x) works well for NaNs and Infs, but if the value might also be
finite, I haven't found anything better than adding 0.0L to trigger
the signaling NaNs without corrupting finite values.  I changed places
like e_hypot.c by adding 0 in the same precision as x (this should
be written as plain 0, but I used 0.0 for e_hypot.c and 0.0F or
(float)0.0 in e_hypotf.c) to give more consistent NaN mixing (convert
before mixing).  This still gave inconsistences for long doubles, on
x86 due to the above messes and maybe on sparc64 too.  Adding 0.0L
causes x to be promoted to long double, giving the consistent i387
behaviour for its registers.  This is free (makes no difference)
on i386, but on amd64 it gives consistently by forcing (das would
say) gratuitous use of the i387, and on other arches it gives whatever
behaviour long doubles give.

> I presume you mean
>    if (isnan(x))
>        return (x + x);

Nah, in fdlibm, NaNs are classified using magic bit tests on bits that
are kept handy in integer registers for other reasons :-).  Using
mainly bits is a significant optimization, but it can be better to mix
bit operations with FP operations even for test operations, to keep more
ALUs streaming.

> Do you have a test case that shows that?  As far as I can tell, all
> the FPUs I have access to will return a quietened variant of the
> input NaN in this case (ie, only the signalling bit is altered).

I test amd64, i386, ia64 and sparc64 and haven't noticed this failing,
though I've noticed a few hundred billion other failures for NaNs.

Bruce



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