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 ----