eggert@twinsun.com (Paul Eggert) (02/09/90)
GDB 3.5 has problems displaying IEEE floating point values, particularly NaNs.
* The test for whether a number is a NaN is flawed: the expression highhalf &
0xfffff == 0 in is_nan() should be (highhalf & 0xfffff) == 0.
* The signs of NaNs are not displayed. The fractions of NaNs (which give
machine-dependent information about what generated the NaN) are not displayed.
* Several m-*.h files should #define IEEE_FLOAT but don't, e.g. m-news.h,
m-sun3.h.
* Only 16 digits of a double are printed; the IEEE standard requires 17 digits
for maximum precision.
Patches for these problems are enclosed below. The patches avoid the
IEEE_FLOAT problem by using a simple dynamic test to see whether a number X is
a NaN; if (X!=X), it's a NaN, otherwise it isn't. This trick is documented in
the IEEE floating point standard, so it works for IEEE floating point. If some
non-IEEE floating point format has a value X where X!=X, the ``else if (doub !=
doub) { ... }'' code below needs to be surrounded by ``#ifdef IEEE_FLOAT ...
#endif''; but I suspect that this is not the case, and that IEEE_FLOAT can be
removed from the m-*.h files.
*** old/printcmd.c Fri Jan 19 19:32:54 1990
--- new/printcmd.c Thu Feb 8 22:56:08 1990
***************
*** 63,68 ****
--- 63,69 ----
void do_displays ();
void print_address ();
+ void print_floating ();
void print_scalar_formatted ();
***************
*** 355,377 ****
type = builtin_type_float;
else if (len == sizeof (double))
type = builtin_type_double;
! #ifdef IEEE_FLOAT
! if (is_nan (type, valaddr))
! {
! fprintf_filtered (stream, "Nan");
! break;
! }
! #endif
! {
! double doub;
! int inv;
!
! doub = unpack_double (type, valaddr, &inv);
! if (inv)
! fprintf_filtered (stream, "Invalid float value");
! else
! fprintf_filtered (stream, len > 4 ? "%.16g" : "%.6g", doub);
! }
break;
case 0:
--- 356,362 ----
type = builtin_type_float;
else if (len == sizeof (double))
type = builtin_type_double;
! print_floating(valaddr, type, stream);
break;
case 0:
***************
*** 380,385 ****
--- 365,423 ----
default:
error ("Undefined output format \"%c\".", format);
}
+ }
+
+ /* Print a floating point value of type TYPE, pointed to in GDB by VALADDR,
+ on STREAM. */
+
+ void
+ print_floating(valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ FILE *stream;
+ {
+ double doub;
+ int inv;
+ int len = TYPE_LENGTH (type);
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf_filtered (stream, "Invalid float value");
+ else if (doub != doub)
+ {
+ /* Surely it is an IEEE floating point NaN. */
+
+ long low, high, *arg = (long *)valaddr; /* ASSUMED 32 BITS */
+ int nonneg;
+
+ if (len <= sizeof(float))
+ {
+ /* It's single precision. */
+ low = *arg;
+ nonneg = low >= 0;
+ low &= 0x7fffff;
+ high = 0;
+ }
+ else
+ {
+ /* It's double precision.
+ Get the high and low words of the fraction.
+ Distinguish big and little-endian machines. */
+ #ifdef WORDS_BIG_ENDIAN
+ low = arg[1], high = arg[0];
+ #else
+ low = arg[0], high = arg[1];
+ #endif
+ nonneg = high >= 0;
+ high &= 0xfffff;
+ }
+ if (high)
+ fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonneg, high, low);
+ else
+ fprintf_filtered (stream, "-NaN(0x%lx)" + nonneg, low);
+ }
+ else
+ fprintf_filtered (stream, len <= sizeof(float) ? "%.6g" : "%.17g", doub);
}
/* Specify default address for `x' command.
*** old/valprint.c Thu Feb 1 14:48:29 1990
--- new/valprint.c Thu Feb 8 22:56:12 1990
***************
*** 714,741 ****
case TYPE_CODE_FLT:
if (format)
! {
! print_scalar_formatted (valaddr, type, format, 0, stream);
! break;
! }
! #ifdef IEEE_FLOAT
! if (is_nan ((char *) valaddr, TYPE_LENGTH (type)))
! {
! fprintf_filtered (stream, "NaN");
! break;
! }
! #endif
! {
! double doub;
! int inv;
!
! doub = unpack_double (type, valaddr, &inv);
! if (inv)
! fprintf_filtered (stream, "Invalid float value");
! else
! fprintf_filtered (stream,
! TYPE_LENGTH (type) <= 4? "%.6g": "%.16g", doub);
! }
break;
case TYPE_CODE_VOID:
--- 714,722 ----
case TYPE_CODE_FLT:
if (format)
! print_scalar_formatted (valaddr, type, format, 0, stream);
! else
! print_floating (valaddr, type, stream);
break;
case TYPE_CODE_VOID:
***************
*** 748,796 ****
fflush (stream);
return 0;
}
-
- #ifdef IEEE_FLOAT
-
- /* Nonzero if ARG (a double) is a NAN. */
-
- int
- is_nan (fp, len)
- char *fp;
- int len;
- {
- int lowhalf, highhalf;
- union ieee
- {
- long i[2]; /* ASSUMED 32 BITS */
- float f; /* ASSUMED 32 BITS */
- double d; /* ASSUMED 64 BITS */
- } *arg;
-
- arg = (union ieee *)fp;
-
- /*
- * Single precision float.
- */
- if (len == sizeof(long))
- {
- highhalf = arg->i[0];
- return ((((highhalf >> 23) & 0xFF) == 0xFF)
- && 0 != (highhalf & 0x7FFFFF));
- }
-
- /* Separate the high and low words of the double.
- Distinguish big and little-endian machines. */
- #ifdef WORDS_BIG_ENDIAN
- lowhalf = arg->i[1], highhalf = arg->i[0];
- #else
- lowhalf = arg->i[0], highhalf = arg->i[1];
- #endif
-
- /* Nan: exponent is the maximum possible, and fraction is nonzero. */
- return (((highhalf>>20) & 0x7ff) == 0x7ff
- && ! ((highhalf & 0xfffff == 0) && (lowhalf == 0)));
- }
- #endif
/* Print a description of a type TYPE
in the form of a declaration of a variable named VARSTRING.
--- 729,734 ----