public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
@ 2003-12-03 18:12 Ian Lance Taylor
  2003-12-03 18:17 ` Daniel Jacobowitz
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Ian Lance Taylor @ 2003-12-03 18:12 UTC (permalink / raw)
  To: gcc-patches; +Cc: gdb-patches

Here is a patch to improve the support for infinity, NaN, and
denormalized numbers in floatformat.c.  It's not clear how to handle
these for non-IEEE formats.  But the old code did entirely the wrong
thing even when using IEEE formats, which are used by pretty much all
modern processors.  So I think we might as well do the right thing
here.

These patches cause the following compilation warnings on a Red Hat
Linux 7.3 system:

../../gcc/libiberty/floatformat.c: In function `floatformat_to_double':
../../gcc/libiberty/floatformat.c:319: warning: traditional C rejects the 'u' suffix
../../gcc/libiberty/floatformat.c:319: warning: traditional C rejects initialization of unions
../../gcc/libiberty/floatformat.c:321: warning: traditional C rejects the 'f' suffix

These are all cases in which the code is using macros which are
defined by the standard <math.h> header (namely INFINITY and NAN).  So
these warnings do not indicate actual code problems.  I don't see any
obvious way to avoid them.

After writing these patches, I decided to see what uses the
floatformat routines.  I discovered only one use: the m68k
disassembler.  gdb uses different routines which probably started as a
copy of the floatformat routines, but use the type DOUBLEST which can
be `long double' instead of `double'.  The code has diverged, and
there is some support there for denormalized numbers.  It doesn't look
right to me, but I haven't investigated much further.

It seems to me that the gdb code should move into libiberty.  We can
easily add floatformat_to_long_double and
floatformat_from_long_double, which would only be available if the
long double type is available.  gdb would then call the appropriate
function from libiberty.  There is other gdb floatformat code which
could move over as well, such as floatformat_is_negative() and
floatformat_is_nan().

Any other opinions on the best way to merge the libiberty and gdb
implementations?

Ian


2003-12-03  Ian Lance Taylor  <ian@wasabisystems.com>

	* floatformat.c: Include "config.h" and <string.h> if available.
	(INFINITY, NAN): Define if not defined by <math.h>.
	(floatformat_to_double): Handle NaN, infinity, and denormalized
	numbers.
	(floatformat_from_double): Likewise.
	(ieee_test): In debugging code, use little endian rather than big
	endian.  Correct tests to handle NaN and to check correct sign of
	zero.  Omit m68k extended test.
	(main): Add more debugging cases.


Index: floatformat.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/floatformat.c,v
retrieving revision 1.14
diff -u -p -r1.14 floatformat.c
--- floatformat.c	31 Oct 2003 05:29:37 -0000	1.14
+++ floatformat.c	3 Dec 2003 18:05:31 -0000
@@ -17,16 +17,33 @@ You should have received a copy of the G
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+/* This is needed to pick up the NAN macro on some systems.  */
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
 #include "ansidecl.h"
+#include "libiberty.h"
 #include "floatformat.h"
-#include <math.h>		/* ldexp */
-#ifdef ANSI_PROTOTYPES
-#include <stddef.h>
-extern void *memcpy (void *s1, const void *s2, size_t n);
-extern void *memset (void *s, int c, size_t n);
+
+#ifndef INFINITY
+#ifdef HUGE_VAL
+#define INFINITY HUGE_VAL
 #else
-extern char *memcpy ();
-extern char *memset ();
+#define INFINITY (1.0 / 0.0)
+#endif
+#endif
+
+#ifndef NAN
+#define NAN (0.0 / 0.0)
 #endif
 
 static unsigned long get_field PARAMS ((const unsigned char *,
@@ -271,9 +288,45 @@ floatformat_to_double (fmt, from, to)
 
   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			fmt->exp_start, fmt->exp_len);
-  /* Note that if exponent indicates a NaN, we can't really do anything useful
-     (not knowing if the host has NaN's, or how to build one).  So it will
-     end up as an infinity or something close; that is OK.  */
+
+  /* If the exponent indicates a NaN, we don't have information to
+     decide what to do.  So we handle it like IEEE, except that we
+     don't try to preserve the type of NaN.  FIXME.  */
+  if ((unsigned long) exponent == fmt->exp_nan)
+    {
+      int nan;
+
+      mant_off = fmt->man_start;
+      mant_bits_left = fmt->man_len;
+      nan = 0;
+      while (mant_bits_left > 0)
+	{
+	  mant_bits = min (mant_bits_left, 32);
+
+	  if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
+			 mant_off, mant_bits) != 0)
+	    {
+	      /* This is a NaN.  */
+	      nan = 1;
+	      break;
+	    }
+
+	  mant_off += mant_bits;
+	  mant_bits_left -= mant_bits;
+	}
+
+      if (nan)
+	dto = NAN;
+      else
+	dto = INFINITY;
+
+      if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+	dto = -dto;
+
+      *to = dto;
+
+      return;
+    }
 
   mant_bits_left = fmt->man_len;
   mant_off = fmt->man_start;
@@ -306,8 +359,18 @@ floatformat_to_double (fmt, from, to)
       mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			 mant_off, mant_bits);
 
-      dto += ldexp ((double)mant, exponent - mant_bits);
-      exponent -= mant_bits;
+      /* Handle denormalized numbers.  FIXME: What should we do for
+	 non-IEEE formats?  */
+      if (exponent == 0 && mant != 0)
+	dto += ldexp ((double)mant,
+		      (- fmt->exp_bias
+		       - mant_bits
+		       - (mant_off - fmt->man_start)
+		       + 1));
+      else
+	dto += ldexp ((double)mant, exponent - mant_bits);
+      if (exponent != 0)
+	exponent -= mant_bits;
       mant_off += mant_bits;
       mant_bits_left -= mant_bits;
     }
@@ -392,33 +455,54 @@ floatformat_from_double (fmt, from, to)
   int mant_bits_left;
   unsigned char *uto = (unsigned char *)to;
 
-  memcpy (&dfrom, from, sizeof (dfrom));
+  dfrom = *from;
   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
+
+  /* If negative, set the sign bit.  */
+  if (dfrom < 0)
+    {
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+      dfrom = -dfrom;
+    }
+
   if (dfrom == 0)
-    return;			/* Result is zero */
+    {
+      /* 0.0.  */
+      return;
+    }
+
   if (dfrom != dfrom)
     {
-      /* From is NaN */
+      /* NaN.  */
       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
 		 fmt->exp_len, fmt->exp_nan);
-      /* Be sure it's not infinity, but NaN value is irrel */
+      /* Be sure it's not infinity, but NaN value is irrelevant.  */
       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
 		 32, 1);
       return;
     }
 
-  /* If negative, set the sign bit.  */
-  if (dfrom < 0)
+  if (dfrom + dfrom == dfrom)
     {
-      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
-      dfrom = -dfrom;
+      /* This can only happen for an infinite value (or zero, which we
+	 already handled above).  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+		 fmt->exp_len, fmt->exp_nan);
+      return;
     }
 
-  /* How to tell an infinity from an ordinary number?  FIXME-someday */
-
   mant = frexp (dfrom, &exponent);
-  put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
-	     exponent + fmt->exp_bias - 1);
+  if (exponent + fmt->exp_bias - 1 > 0)
+    put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+	       fmt->exp_len, exponent + fmt->exp_bias - 1);
+  else
+    {
+      /* Handle a denormalized number.  FIXME: What should we do for
+	 non-IEEE formats?  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+		 fmt->exp_len, 0);
+      mant = ldexp (mant, exponent + fmt->exp_bias - 1);
+    }
 
   mant_bits_left = fmt->man_len;
   mant_off = fmt->man_start;
@@ -431,12 +515,11 @@ floatformat_from_double (fmt, from, to)
       mant_long = (unsigned long)mant;
       mant -= mant_long;
 
-      /* If the integer bit is implicit, then we need to discard it.
-	 If we are discarding a zero, we should be (but are not) creating
-	 a denormalized	number which means adjusting the exponent
-	 (I think).  */
+      /* If the integer bit is implicit, and we are not creating a
+	 denormalized number, then we need to discard it.  */
       if ((unsigned int) mant_bits_left == fmt->man_len
-	  && fmt->intbit == floatformat_intbit_no)
+	  && fmt->intbit == floatformat_intbit_no
+	  && exponent + fmt->exp_bias - 1 > 0)
 	{
 	  mant_long &= 0x7fffffff;
 	  mant_bits -= 1;
@@ -468,6 +551,8 @@ floatformat_is_valid (fmt, from)
 
 #ifdef IEEE_DEBUG
 
+#include <stdio.h>
+
 /* This is to be run on a host which uses IEEE floating point.  */
 
 void
@@ -475,19 +560,31 @@ ieee_test (n)
      double n;
 {
   double result;
-  char exten[16];
 
-  floatformat_to_double (&floatformat_ieee_double_big, &n, &result);
-  if (n != result)
+  floatformat_to_double (&floatformat_ieee_double_little, (char *) &n,
+			 &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
     printf ("Differ(to): %.20g -> %.20g\n", n, result);
-  floatformat_from_double (&floatformat_ieee_double_big, &n, &result);
-  if (n != result)
+
+  floatformat_from_double (&floatformat_ieee_double_little, &n,
+			   (char *) &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
     printf ("Differ(from): %.20g -> %.20g\n", n, result);
 
-  floatformat_from_double (&floatformat_m68881_ext, &n, exten);
-  floatformat_to_double (&floatformat_m68881_ext, exten, &result);
-  if (n != result)
-    printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
+#if 0
+  {
+    char exten[16];
+
+    floatformat_from_double (&floatformat_m68881_ext, &n, exten);
+    floatformat_to_double (&floatformat_m68881_ext, exten, &result);
+    if (n != result)
+      printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
+  }
+#endif
 
 #if IEEE_DEBUG > 1
   /* This is to be run on a host which uses 68881 format.  */
@@ -502,12 +599,22 @@ ieee_test (n)
 int
 main ()
 {
+  ieee_test (0.0);
   ieee_test (0.5);
   ieee_test (256.0);
   ieee_test (0.12345);
   ieee_test (234235.78907234);
   ieee_test (-512.0);
   ieee_test (-0.004321);
+  ieee_test (1.2E-70);
+  ieee_test (1.2E-316);
+  ieee_test (4.9406564584124654E-324);
+  ieee_test (- 4.9406564584124654E-324);
+  ieee_test (- 0.0);
+  ieee_test (- INFINITY);
+  ieee_test (- NAN);
+  ieee_test (INFINITY);
+  ieee_test (NAN);
   return 0;
 }
 #endif

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
@ 2003-12-03 18:17 ` Daniel Jacobowitz
  2003-12-03 19:09   ` Andrew Cagney
  2003-12-03 18:35 ` DJ Delorie
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2003-12-03 18:17 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gdb-patches

On Wed, Dec 03, 2003 at 01:12:45PM -0500, Ian Lance Taylor wrote:
> Here is a patch to improve the support for infinity, NaN, and
> denormalized numbers in floatformat.c.  It's not clear how to handle
> these for non-IEEE formats.  But the old code did entirely the wrong
> thing even when using IEEE formats, which are used by pretty much all
> modern processors.  So I think we might as well do the right thing
> here.
> 
> These patches cause the following compilation warnings on a Red Hat
> Linux 7.3 system:
> 
> ../../gcc/libiberty/floatformat.c: In function `floatformat_to_double':
> ../../gcc/libiberty/floatformat.c:319: warning: traditional C rejects the 'u' suffix
> ../../gcc/libiberty/floatformat.c:319: warning: traditional C rejects initialization of unions
> ../../gcc/libiberty/floatformat.c:321: warning: traditional C rejects the 'f' suffix
> 
> These are all cases in which the code is using macros which are
> defined by the standard <math.h> header (namely INFINITY and NAN).  So
> these warnings do not indicate actual code problems.  I don't see any
> obvious way to avoid them.
> 
> After writing these patches, I decided to see what uses the
> floatformat routines.  I discovered only one use: the m68k
> disassembler.  gdb uses different routines which probably started as a
> copy of the floatformat routines, but use the type DOUBLEST which can
> be `long double' instead of `double'.  The code has diverged, and
> there is some support there for denormalized numbers.  It doesn't look
> right to me, but I haven't investigated much further.

For the record, that's not 100% correct - GDB doesn't use
floatformat_to_double or floatformat_from_double, but we do use the
rest of the file (is_valid, and all the actual floatformats).  This is
fairly obvious after re-reading what you said but it gave me a turn the
first time :)

> It seems to me that the gdb code should move into libiberty.  We can
> easily add floatformat_to_long_double and
> floatformat_from_long_double, which would only be available if the
> long double type is available.  gdb would then call the appropriate
> function from libiberty.  There is other gdb floatformat code which
> could move over as well, such as floatformat_is_negative() and
> floatformat_is_nan().
> 
> Any other opinions on the best way to merge the libiberty and gdb
> implementations?

That sounds reasonable to me.  floatformat_to_doublest could contain a
check on HAVE_LONG_DOUBLE and call one or the other.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
  2003-12-03 18:17 ` Daniel Jacobowitz
  2003-12-03 18:35 ` DJ Delorie
@ 2003-12-03 18:35 ` Carlo Wood
  2003-12-03 18:44   ` Ian Lance Taylor
  2003-12-03 18:47 ` Paul Koning
  2012-08-16 16:20 ` Andreas Schwab
  4 siblings, 1 reply; 10+ messages in thread
From: Carlo Wood @ 2003-12-03 18:35 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gdb-patches

On Wed, Dec 03, 2003 at 01:12:45PM -0500, Ian Lance Taylor wrote:
> Here is a patch to improve the support for infinity, NaN, and
> denormalized numbers in floatformat.c.  It's not clear how to handle
> these for non-IEEE formats.  But the old code did entirely the wrong
> thing even when using IEEE formats, which are used by pretty much all
> modern processors.  So I think we might as well do the right thing
> here.

Sorry if this is not related - but what are you going to do
with the demangling of floating point values?  I sensed a strong
opposition against the IEEE decoding - so I removed my IEEE print
routine again :/.

But if your demangler will demangle everything as IEEE regardless
then I suppose I might as well do the same.

Thanks,

-- 
Carlo Wood <carlo@alinoe.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
  2003-12-03 18:17 ` Daniel Jacobowitz
@ 2003-12-03 18:35 ` DJ Delorie
  2003-12-03 18:35 ` Carlo Wood
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: DJ Delorie @ 2003-12-03 18:35 UTC (permalink / raw)
  To: ian; +Cc: gcc-patches, gdb-patches


> 2003-12-03  Ian Lance Taylor  <ian@wasabisystems.com>
> 
> 	* floatformat.c: Include "config.h" and <string.h> if available.
> 	(INFINITY, NAN): Define if not defined by <math.h>.
> 	(floatformat_to_double): Handle NaN, infinity, and denormalized
> 	numbers.
> 	(floatformat_from_double): Likewise.
> 	(ieee_test): In debugging code, use little endian rather than big
> 	endian.  Correct tests to handle NaN and to check correct sign of
> 	zero.  Omit m68k extended test.
> 	(main): Add more debugging cases.

Ok.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:35 ` Carlo Wood
@ 2003-12-03 18:44   ` Ian Lance Taylor
  2003-12-03 18:56     ` Carlo Wood
  0 siblings, 1 reply; 10+ messages in thread
From: Ian Lance Taylor @ 2003-12-03 18:44 UTC (permalink / raw)
  To: Carlo Wood; +Cc: gcc-patches, gdb-patches

Carlo Wood <carlo@alinoe.com> writes:

> On Wed, Dec 03, 2003 at 01:12:45PM -0500, Ian Lance Taylor wrote:
> > Here is a patch to improve the support for infinity, NaN, and
> > denormalized numbers in floatformat.c.  It's not clear how to handle
> > these for non-IEEE formats.  But the old code did entirely the wrong
> > thing even when using IEEE formats, which are used by pretty much all
> > modern processors.  So I think we might as well do the right thing
> > here.
> 
> Sorry if this is not related - but what are you going to do
> with the demangling of floating point values?  I sensed a strong
> opposition against the IEEE decoding - so I removed my IEEE print
> routine again :/.
> 
> But if your demangler will demangle everything as IEEE regardless
> then I suppose I might as well do the same.

What I'm working toward right now is permitting the caller of the
demangling routines to pass in an optional array mapping floating
point types to floatformat structures.  Then if I see a floating point
literal, I can use the floatformat structures to pull it apart.  I
then plan to output the literal as a C99 hex floating point constant.
(A couple of people suggested this approach, and I can't think of a
good reason to not do it.)

If the demangler is called with no floatformat structures, then I plan
to just dump out the string without any attempt to display it as a
floating point number, just as I do today.

This approach probably doesn't help you, since you probably don't want
to deal with the floatformat routines.

Anyhow, I was setting up the floatformat array when I realized that
the floatformat routines were moderately bogus in that they completely
failed to handle denormalized numbers.  So I fixed them.

I do think this is all kind of ridiculous, since I'm sure that nobody
uses floating point constants in template expressions in real life.
And I think that changing the mangling of floating point constants
would be a much better solution for all concerned.  But I don't know
how to make that happen.

Ian

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
                   ` (2 preceding siblings ...)
  2003-12-03 18:35 ` Carlo Wood
@ 2003-12-03 18:47 ` Paul Koning
  2012-08-16 16:20 ` Andreas Schwab
  4 siblings, 0 replies; 10+ messages in thread
From: Paul Koning @ 2003-12-03 18:47 UTC (permalink / raw)
  To: ian; +Cc: gcc-patches, gdb-patches

>>>>> "Ian" == Ian Lance Taylor <ian@wasabisystems.com> writes:

 Ian> Here is a patch to improve the support for infinity, NaN, and
 Ian> denormalized numbers in floatformat.c.  It's not clear how to
 Ian> handle these for non-IEEE formats.

Depends on the specific format.  For example, DEC float has NaN, but
it doesn't have infinites, and it doesn't have denormals.

And since for that format NaN is never produced as the result of
arithmetic (its only use is as a memory initialization pattern) it
would probably be reasonable enough not to define it.  (If you'd want
to define it, you may have to use the hex format.)

   paul

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:44   ` Ian Lance Taylor
@ 2003-12-03 18:56     ` Carlo Wood
  0 siblings, 0 replies; 10+ messages in thread
From: Carlo Wood @ 2003-12-03 18:56 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gdb-patches

On Wed, Dec 03, 2003 at 01:44:28PM -0500, Ian Lance Taylor wrote:
> literal, I can use the floatformat structures to pull it apart.  I
> then plan to output the literal as a C99 hex floating point constant.
> (A couple of people suggested this approach, and I can't think of a
> good reason to not do it.)

I think they meant to use C99 hex as the base for a new mangling,
and then print that more or less literally when demangling.  That would
avoid rounding on both ends (I understood that C99 corresponds exactly
with the internal representation of floats by gcc anyway) and removes all
target dependency.  I disagree with this, but well - its not that important.

[...]
> This approach probably doesn't help you, since you probably don't want
> to deal with the floatformat routines.
They allocate memory - therefore prefer to simply output the mangled bit.
After all,...

[...]
> I do think this is all kind of ridiculous, since I'm sure that nobody
> uses floating point constants in template expressions in real life.

Exactly what I've said several times :/.  I think my last patch is my
last word in the subject of demangling floats.  I'll have another look
iff a third party files a real-life complaint through GNATS, and not
sooner.

Thanks for your reply,
Carlo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:17 ` Daniel Jacobowitz
@ 2003-12-03 19:09   ` Andrew Cagney
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Cagney @ 2003-12-03 19:09 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Ian Lance Taylor, gcc-patches, gdb-patches


> That sounds reasonable to me.  floatformat_to_doublest could contain a
> check on HAVE_LONG_DOUBLE and call one or the other.

something like

floatformat_from_doublest()
{
#if HAVE_LONG_DOUBLE
   return floatformat_from_long_double (...)
#else
   return floatformat_from_double (...)
}

Yes, that would keep GDB insulated from liberty's configuration internals.

(Any long term signs of a portable target floating point library (so 
that the code can completly avoid host fpu assumptions?).  glibc's 
floating-point code has been suggested in the past.)

Andrew


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
                   ` (3 preceding siblings ...)
  2003-12-03 18:47 ` Paul Koning
@ 2012-08-16 16:20 ` Andreas Schwab
  2012-08-17 21:16   ` Ian Lance Taylor
  4 siblings, 1 reply; 10+ messages in thread
From: Andreas Schwab @ 2012-08-16 16:20 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gdb-patches

Ian Lance Taylor <ian@wasabisystems.com> writes:

> @@ -306,8 +359,18 @@ floatformat_to_double (fmt, from, to)
>        mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
>  			 mant_off, mant_bits);
>  
> -      dto += ldexp ((double)mant, exponent - mant_bits);
> -      exponent -= mant_bits;
> +      /* Handle denormalized numbers.  FIXME: What should we do for
> +	 non-IEEE formats?  */
> +      if (exponent == 0 && mant != 0)
> +	dto += ldexp ((double)mant,
> +		      (- fmt->exp_bias
> +		       - mant_bits
> +		       - (mant_off - fmt->man_start)
> +		       + 1));
> +      else
> +	dto += ldexp ((double)mant, exponent - mant_bits);
> +      if (exponent != 0)
> +	exponent -= mant_bits;

That mishandles numbers between 1 and 2 (ie. where the unbiased exponent
is zero) with floating-point formats with more than 32 mantissa bits.
Also, the handling of denormal numbers can be simplified by just setting
exponent appropriately.

Andreas.

	* floatformat.c (floatformat_to_double): Correctly handle numbers
	between 1 and 2.  Simplify handling of denormal number.
	(main): Test with 1.1.
---
 libiberty/floatformat.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/libiberty/floatformat.c b/libiberty/floatformat.c
index 1116c63..c58ab01 100644
--- a/libiberty/floatformat.c
+++ b/libiberty/floatformat.c
@@ -1,5 +1,5 @@
 /* IEEE floating point support routines, for GDB, the GNU Debugger.
-   Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006, 2010
+   Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006, 2010, 2012
    Free Software Foundation, Inc.
 
 This file is part of GDB.
@@ -463,7 +463,6 @@ floatformat_to_double (const struct floatformat *fmt,
   unsigned long mant;
   unsigned int mant_bits, mant_off;
   int mant_bits_left;
-  int special_exponent;		/* It's a NaN, denorm or zero */
 
   /* Split values are not handled specially, since the top half has
      the correctly rounded double value (in the only supported case of
@@ -503,20 +502,20 @@ floatformat_to_double (const struct floatformat *fmt,
   mant_off = fmt->man_start;
   dto = 0.0;
 
-  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
-
-  /* Don't bias zero's, denorms or NaNs.  */
-  if (!special_exponent)
-    exponent -= fmt->exp_bias;
-
   /* Build the result algebraically.  Might go infinite, underflow, etc;
      who cares. */
 
-  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
-     increment the exponent by one to account for the integer bit.  */
-
-  if (!special_exponent)
+  /* For denorms use minimum exponent.  */
+  if (exponent == 0)
+    exponent = 1 - fmt->exp_bias;
+  else
     {
+      exponent -= fmt->exp_bias;
+
+      /* If this format uses a hidden bit, explicitly add it in now.
+	 Otherwise, increment the exponent by one to account for the
+	 integer bit.  */
+
       if (fmt->intbit == floatformat_intbit_no)
 	dto = ldexp (1.0, exponent);
       else
@@ -530,18 +529,8 @@ floatformat_to_double (const struct floatformat *fmt,
       mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			 mant_off, mant_bits);
 
-      /* Handle denormalized numbers.  FIXME: What should we do for
-	 non-IEEE formats?  */
-      if (special_exponent && exponent == 0 && mant != 0)
-	dto += ldexp ((double)mant,
-		      (- fmt->exp_bias
-		       - mant_bits
-		       - (mant_off - fmt->man_start)
-		       + 1));
-      else
-	dto += ldexp ((double)mant, exponent - mant_bits);
-      if (exponent != 0)
-	exponent -= mant_bits;
+      dto += ldexp ((double) mant, exponent - mant_bits);
+      exponent -= mant_bits;
       mant_off += mant_bits;
       mant_bits_left -= mant_bits;
     }
@@ -756,6 +745,7 @@ main (void)
 {
   ieee_test (0.0);
   ieee_test (0.5);
+  ieee_test (1.1);
   ieee_test (256.0);
   ieee_test (0.12345);
   ieee_test (234235.78907234);
-- 
1.7.11.5


-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: RFA: Support infinity, NaN, and denormalized numbers in floatformat.c
  2012-08-16 16:20 ` Andreas Schwab
@ 2012-08-17 21:16   ` Ian Lance Taylor
  0 siblings, 0 replies; 10+ messages in thread
From: Ian Lance Taylor @ 2012-08-17 21:16 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: gcc-patches, gdb-patches

On Thu, Aug 16, 2012 at 9:20 AM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>
>         * floatformat.c (floatformat_to_double): Correctly handle numbers
>         between 1 and 2.  Simplify handling of denormal number.
>         (main): Test with 1.1.

This is OK.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-08-17 21:16 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-03 18:12 RFA: Support infinity, NaN, and denormalized numbers in floatformat.c Ian Lance Taylor
2003-12-03 18:17 ` Daniel Jacobowitz
2003-12-03 19:09   ` Andrew Cagney
2003-12-03 18:35 ` DJ Delorie
2003-12-03 18:35 ` Carlo Wood
2003-12-03 18:44   ` Ian Lance Taylor
2003-12-03 18:56     ` Carlo Wood
2003-12-03 18:47 ` Paul Koning
2012-08-16 16:20 ` Andreas Schwab
2012-08-17 21:16   ` Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).