This is the mail archive of the newlib@sourceware.org mailing list for the newlib 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: add _HAVE_LONG_DOUBLE flag, math.h update


Jeff:
     Just in case:  my parenthetical comment in the original email about
only having tested with GCC--implying some small uncertainty of all
compilers doing it--is only meant for the #2 list item that it is in,
relating to the HUGE_VAL defines.  I am certain of the 0/0 for NAN.  So
if that was the cause of your concern about NAN, read no further and
use #define NAN as it is.  Otherwise, read on.
     0 divided by 0 works for certain to make NAN:  some of the libm
routines do it that way.  (You can see "return (x-x)/(x-x)" when an NAN
needs to be generated for a return, as in, for example, s_log1p.c,
originally written in 1993.)  IEEE 754 (1985 and 2008 versions) defines
that 0/0 yields a quiet NAN.  The only possible drawback is the possible
runtime "invalid" floating-point exception, which is presently not a
problem for Newlib.
     Yes, I had seen the GLIBC method, which I indirectly dismissed
in math.h comments, saying "statics could be declared, but they suffer
from using storage in every file that includes math.h."  (I suppose that
when an optimizer is enabled, that the storage would only be allocated
if it were used.)  But even then, the integer methods are inherently
unportable and far uglier.  So even if we were to say that:

#define NAN (0.0F/0.0F)

is objectionable because of the possibility of a run-time floating-point
exception, I would say that the first step away from it would be
something like:
 
static const float __nan=0.0F/0.0F;	// use of const TBD
#define NAN (__nan)
 
rather than the GLIBC mess of (at least for the version that I have,
which is apparently earlier than yours in that it only has 2 levels
instead of 3--although your 1st level matches Newlib's first level)
 
/* IEEE Not A Number.  */

#ifdef  __GNUC__

# define NAN \
  (__extension__                                              \
   ((union { unsigned __l __attribute__((__mode__(__SI__)));  \
                                               float __d; })  \
    { __l: 0x7fc00000UL }).__d)

#else

# include <endian.h>

# if __BYTE_ORDER == __BIG_ENDIAN
#  define __nan_bytes           { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
#  define __nan_bytes           { 0, 0, 0xc0, 0x7f }
# endif

static union { unsigned char __c[4]; float __d; } __nan_union = {
__nan_bytes };
# define NAN    (__nan_union.__d)

#endif  /* GCC.  */
 
(Which, by the way, is assuming that floats are 32 bits.)
     The portability comment is more for HUGE_VALL than any of the
others,
as long double is subject to the most variation, float and double being
closer to being fixed.
     My GLIBC copy has the __mode__(__SI__) thing for nan.h, but not in
huge_val.h (I don't have an inf.h).  So the SI thing seems to be fairly
old.  I found some GCC source code:
		else if (0==strcmp(mode, "__SI__")) {
		  id = uns? ST_UNSIGNED_INT : ST_INT; }
so it seems to be asking for the size of an int.  But I didn't find it
in GCC documentation (I checked 2.95 and 4.1), so it makes me leery
of using it.
     I suggest that given 23 years in the 754 standard and the 16 years
of use in fdlibm, that the 0/0 approach will be fine across all
platforms.
It is certainly smaller (source, not executable) and more portable (in
case we ever get a platform with float != 32 bits) than the GLIBC
integer
method.  I think we should stick with it.  If you'd like to use the
static to avoid the runtime fp exception for future preparation for
supporting floating point exceptions, I'll readily do that.  (When
declared as a static, the conversion is done at translation time so that
there are no exceptions.)  But I really hesitate to go to the integer
ugliness, as it's far worse than /0.  (If you're only objecting to
divide
by zero, then it could be changed to "(HUGE_VALF/HUGE_VALF)", which
produces identical results to "(0.F/0.F)". ;)
     (By the way, it seems like even though you mentioned the GLIBC
method for the infinities, that your only complaint with the patch
is related to NAN.  Is this correct, or are you also not liking the
infinities approach?  I would have used what I did in s_infconst.c
in math.h if it weren't for avoiding the nested inclusion of float.h.)
				Craig

-----Original Message-----
From: Jeff Johnston [mailto:jjohnstn@redhat.com] 
Sent: Tuesday, May 05, 2009 3:54 PM
To: Howland Craig D (Craig)
Cc: Newlib
Subject: Re: add _HAVE_LONG_DOUBLE flag, math.h update

Craig,

Have you looked at how glibc handles the constants?  Take a look at 
bits/nan.h bits/huge_val.h, bits/inf.h which use builtin first, then a 
GNUC extension, and failing that, a static union.  For the 2nd attempt, 
my headers have __mode__(__SI__) used.  I do not know if this is 
guaranteed for all platforms.  I prefer their logic to a divide by 0.

Regarding the old externs, keep them.  Some code may need them for 
linking back-level code.  They are harmless if not being used.

-- Jeff J.

Howland Craig D (Craig) wrote:
> ...
> math.h receives two tweaks, both being related to some defines that
> either use GCC builtins (GCC >= 3.3) or "hand-done" values,
specifically
> related to the hand-done case:
> 1)  The missing INFINITY and NAN defines are added.
> 2)  The HUGE_VAL set of defines as they were violated the standard,
not
> being constant expressions, but pointing to a set of globals (defined
> in libm/common/s_infconst.c).  These are changed to legitimate
constant
> expressions.  (I only have various GCC versions to test them with.  So
> while these should also work with other compilers, it is presently
> untested.)
> ...


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