add _HAVE_LONG_DOUBLE flag, math.h update

Jeff Johnston jjohnstn@redhat.com
Thu May 7 00:06:00 GMT 2009


Howland Craig D (Craig) wrote:
> 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,

I don't have the 754 standard so thanks for the details.

I wasn't really interested in the SI stuff, but I mentioned it nonetheless.

I'm not comfortable with the infinities logic due to the possibility of 
warnings.  I am not sure how you know that the infinities and hugevals 
won't generate warnings in any other embedded compilers using the logic 
per your comment.

Again, I would prefer to use the statics as I know they will work and 
avoid the runtime fp exception.  Special casing should be handled for a 
platform in machine/ieeefp.h (e.g. float not 32-bits). 

As an aside, I don't understand why the glibc non-GNUC logic doesn't 
simply reuse HUGE_VALF for HUGE_VAL and HUGE_VALL so one only cares 
about the float bytes and endianness, but I must be missing something.

-- Jeff J.



More information about the Newlib mailing list