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


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.


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