X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com X-Authenticated: #27081556 X-Provags-ID: V01U2FsdGVkX1/i0u5HgAvi/kIyvIJ8Q4cVW89h0vqsOknjR9VG+F bdqH/Xij1Q6usS From: Juan Manuel Guerrero To: djgpp-workers AT delorie DOT com Subject: Re: Implementation of certain conversion specifiers in _doprnt (patch #2) Date: Thu, 24 Apr 2008 16:28:46 +0200 User-Agent: KMail/1.9.5 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200804241628.47232.juan.guerrero@gmx.de> X-Y-GMX-Trusted: 0 Reply-To: djgpp-workers AT delorie DOT com According to C99 the NaN and Inf strings have been replaced by nan/NAN and inf/INF. Also isspeciall() no longer returns "Unnormal" instead of nan/NAN. This is to become compatible with gnu glibc and to avoid to make break configure scripts. The corresponding existing tests have been adjusted accordingly. Regards, Juan M. Guerrero 2008-04-23 Juan Manuel Guerrero Diffs against djgpp CVS head of 2008-04-23. * src/libc/ansi/stdio/doprnt.c: Use of nan/NAN and inf/INF (C99 strings) instead of Inf and NaN strings. Also return nan/NAN instead of "Unnormal". * tests/cygnus/convert.c (test_nan_inf): Tests adjusted for the use of nan/NAN and inf/INF (C99 strings) instead of Inf and NaN strings. * src/docs/kb/wc204.txi: Info about the replacement of "unnormal" by nan/NAN added. diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi --- djgpp.orig/src/docs/kb/wc204.txi 2008-04-23 23:07:22 +0000 +++ djgpp/src/docs/kb/wc204.txi 2008-04-23 23:10:26 +0000 @@ -1123,3 +1123,11 @@ input string. @findex printf AT r{, and C99 conversion flags} The @code{'} conversion flag is now supported by @code{_doprnt} and the @code{printf} family of functions. + +@findex _doprnt AT r{, and return string for special numbers like @code{pseudo-nan}} +@findex printf AT r{, and return string for special numbers like @code{pseudo-nan}} +To increase compatibility with GNU glibc's @code{printf}, @code{printf} will +return for the following special numbers @code{Quiet NaN}, @code{Signalling NaN}, +@code{Pseudo-Denormal}, @code{Pseudo-NaN}, @code{Pseudo-Infinity}, +@code{Pseudo-Zero} and denormalized numbers @code{nan} or @code{NAN} instead +of @code{Unnormal}. diff -aprNU3 djgpp.orig/src/libc/ansi/stdio/doprnt.c djgpp/src/libc/ansi/stdio/doprnt.c --- djgpp.orig/src/libc/ansi/stdio/doprnt.c 2008-04-23 23:07:22 +0000 +++ djgpp/src/libc/ansi/stdio/doprnt.c 2008-04-23 23:10:26 +0000 @@ -44,12 +44,12 @@ static char *grouping; flags&CHARINT ? (char basetype)va_arg(argp, int) : \ (basetype)va_arg(argp, int) -#define IS_FINITE(x) (((x).ldt.exponent < 0x7FFFU && (x).ldt.exponent > 0x0000U && (x).ldt.mantissah & 0x80000000UL) \ - || ((x).ldt.exponent == 0x0000U && !((x).ldt.mantissah & 0x80000000UL))) - -#define IS_ZERO(x) ((x).ldt.exponent == 0x0U && (x).ldt.mantissah == 0x0UL && (x).ldt.mantissal == 0x0UL) -#define IS_NAN(x) ((x).ldt.exponent == 0x7FFFU && ((x).ldt.mantissah & 0x7FFFFFFFUL || (x).ldt.mantissal)) - +#define IS_FINITE(x) (((x).ldt.exponent < 0x7FFFU && (x).ldt.exponent > 0x0000U && (x).ldt.mantissah & 0x80000000UL) \ + || ((x).ldt.exponent == 0x0000U && !((x).ldt.mantissah & 0x80000000UL))) +#define IS_ZERO(x) ((x).ldt.exponent == 0x0U && (x).ldt.mantissah == 0x0UL && (x).ldt.mantissal == 0x0UL) +#define IS_NAN(x) ((x).ldt.exponent == 0x7FFFU && ((x).ldt.mantissah & 0x7FFFFFFFUL || (x).ldt.mantissal)) +#define IS_PSEUDO_NUMBER(x) (((x).ldt.exponent != 0x0000U && !((x).ldt.mantissah & 0x80000000UL)) /* Pseudo-NaN, Pseudo-Infinity and Unnormal. */ \ + || ((x).ldt.exponent == 0x0000U && (x).ldt.mantissah & 0x80000000UL)) /* Pseudo-Denormal. */ static __inline__ int todigit(char c) { @@ -77,19 +77,19 @@ static __inline__ char tochar(int n) #define ZEROPAD 0x0100 /* zero (as opposed to blank) pad */ #define HEXPREFIX 0x0200 /* add 0x or 0X prefix */ #define GROUPING 0x0400 /* non monetary thousands grouping */ +#define UPPERCASE 0x0800 /* INF/NAN for [EFG] */ static int cvtl(long double number, int prec, int flags, char *signp, unsigned char fmtch, char *startp, char *endp); static char *doprnt_roundl(long double fract, int *expv, char *start, char *end, char ch, char *signp); -static char *exponentl(char *p, int expv, unsigned char fmtch); +static char *exponentl(char *p, int expv, unsigned char fmtch, int flags); #ifdef __GO32__ -static int isspeciall(long double d, char *bufp); +static int isspeciall(long double d, char *bufp, int flags); #endif static __inline__ char * __grouping_format(char *string_start, char *string_end, char *buffer_end, int flags); static char NULL_REP[] = "(null)"; -static char UNNORMAL_REP[] = "Unnormal"; int @@ -265,11 +265,12 @@ _doprnt(const char *fmt0, va_list argp, base = 10; flags |= FINITENUMBER; goto number; - case 'e': case 'E': + case 'G': + flags |= UPPERCASE; + case 'e': case 'f': case 'g': - case 'G': flags |= FLOAT; if (flags & LONGDBL) _ldouble = va_arg(argp, long double); @@ -311,14 +312,12 @@ _doprnt(const char *fmt0, va_list argp, } else { - _longdouble_union_t ip; - - ip.ld = _ldouble; + ieee_value.ld = _ldouble; - if (ip.ldt.sign) + if (ieee_value.ldt.sign) { neg_ldouble = 1; - if (IS_ZERO(ip) || IS_NAN(ip)) + if (IS_ZERO(ieee_value) || IS_NAN(ieee_value) || IS_PSEUDO_NUMBER(ieee_value)) softsign = '-'; } else @@ -410,6 +409,7 @@ _doprnt(const char *fmt0, va_list argp, goto nosign; case 'X': digs = "0123456789ABCDEF"; + flags |= UPPERCASE; /* FALLTHROUGH */ case 'x': ARG(unsigned); @@ -577,7 +577,7 @@ cvtl(long double number, int prec, int f int doingzero=0; /* We're displaying 0.0 */ long double integer, tmp; - if ((expcnt = isspeciall(number, startp))) + if ((expcnt = isspeciall(number, startp, flags))) return(expcnt); dotrim = expcnt = gformat = 0; @@ -768,7 +768,7 @@ cvtl(long double number, int prec, int f --t; ++t; } - t = exponentl(t, expcnt, fmtch); + t = exponentl(t, expcnt, fmtch, flags); break; case 'g': case 'G': @@ -913,7 +913,7 @@ doprnt_roundl(long double fract, int *ex } static char * -exponentl(char *p, int expv, unsigned char fmtch) +exponentl(char *p, int expv, unsigned char fmtch, int flags) { char *t; char expbuf[MAXEXPLD]; @@ -944,41 +944,54 @@ exponentl(char *p, int expv, unsigned ch } static int -isspeciall(long double d, char *bufp) +isspeciall(long double d, char *bufp, int flags) { - typedef struct { - unsigned manl:32; - unsigned manh:32; - unsigned exp:15; - unsigned sign:1; - } IEEExp; - - typedef union { - IEEExp ip; - long double ldouble; /* double and long double precision arguments */ - } ip_union; - - ip_union ip; - - ip.ldouble = d; - - - /* Unnormals: the MSB of mantissa is non-zero, but the exponent is - not zero either. */ - if ((ip.ip.manh & 0x80000000U) == 0 && ip.ip.exp != 0) - { - if (ip.ip.sign) - *bufp++ = '-'; - strcpy(bufp, UNNORMAL_REP); - return strlen(bufp) + ip.ip.sign; - } - if (ip.ip.exp != 0x7fff) - return(0); - if ((ip.ip.manh & 0x7fffffff) || ip.ip.manl) - strcpy(bufp, "NaN"); + /* + * For intel's 80 bit floating point number identify + * the following special values: + * + * Supported Floating-Point Encodings (generated by processor as an operation result) + * exp integer fraction + * Signalling NaN: 0x7FFF, 1, 0x0000000000000001 <=, <= 0x3FFFFFFFFFFFFFFF + * Quiet NaN: 0x7FFF, 1, 0x4000000000000000 <=, <= 0x7FFFFFFFFFFFFFFF + * Infinity: 0x7FFF, 1, 0 + * Pseudo-Denormal: 0x0000, 1, 0x0000000000000001 <=, <= 0x7FFFFFFFFFFFFFFF + * + * Unsupported Floating-Point Encodings (not generated by processor as an operation result) + * exp integer fraction + * Pseudo-NaN: 0x7FFF, 0, 0x0000000000000001 <=, <= 0x7FFFFFFFFFFFFFFF + * Pseudo-Infinity: 0x7FFF, 0, 0 + * Pseudo-Zero: 0x0001 <=, < 0x7FFF, 0, 0 + * Unnormal: 0x0001 <=, < 0x7FFF, 0, 0x0000000000000001 <=, <= 0x7FFFFFFFFFFFFFFF + * + * Patterns of the values according to: + * Intel IA-64 Architecture Software Developer's Manual, Volume 1: + * Application Architecture. + * 5.1.3 "Representation of Values in Floating-Point Registers" + * Table 5-2 "Floating-Point Register Encodings" + * Figure 5-11 "Floating-Point Exception Fault Prioritization" + * + * To be compatible with printf of GNU glibc Quiet NaN, signalling NaN, Pseudo-NaN, + * Pseudo-Infinity, Pseudo-Zero, Pseudo-Denormal and denormalized numbers (unnormal) + * will all return nan/NAN instead of "Unnormal" as used to be. + */ + + static const char INF_REP[2][4] = {"inf", "INF"}; + static const char NAN_REP[2][4] = {"nan", "NAN"}; + int style = (flags & UPPERCASE) ? 1 : 0; + _longdouble_union_t ieee_value; + + + ieee_value.ld = d; + if (IS_PSEUDO_NUMBER(ieee_value)) /* Pseudo-NaN, Pseudo-Infinity, Unnormal and Pseudo-Denormal. */ + strcpy(bufp, NAN_REP[style]); + else if (ieee_value.ldt.exponent != 0x7FFFU) + return 0; + else if (ieee_value.ldt.mantissah & 0x7FFFFFFFUL || ieee_value.ldt.mantissal) /* Quiet NaN and signalling NaN. */ + strcpy(bufp, NAN_REP[style]); else - (void)strcpy(bufp, "Inf"); - return(3); + strcpy(bufp, INF_REP[style]); + return 3; } static __inline__ char * diff -aprNU3 djgpp.orig/tests/cygnus/convert.c djgpp/tests/cygnus/convert.c --- djgpp.orig/tests/cygnus/convert.c 1999-04-04 08:13:22 +0000 +++ djgpp/tests/cygnus/convert.c 2008-04-23 23:10:26 +0000 @@ -283,16 +283,29 @@ _DEFUN_VOID(test_nan_inf) newfunc("nan print"); line(1); sprintf(buffer,"%e", nan()); - test_sok(buffer,"NaN"); + test_sok(buffer,"nan"); line(2); sprintf(buffer,"%e", -nan()); - test_sok(buffer,"NaN"); + test_sok(buffer,"nan"); line(3); sprintf(buffer,"%+e", nan()); - test_sok(buffer,"+NaN"); + test_sok(buffer,"+nan"); line(4); sprintf(buffer,"%+e", -nan()); - test_sok(buffer,"-NaN"); + test_sok(buffer,"-nan"); + newfunc("NAN print"); + line(1); + sprintf(buffer,"%E", nan()); + test_sok(buffer,"NAN"); + line(2); + sprintf(buffer,"%E", -nan()); + test_sok(buffer,"NAN"); + line(3); + sprintf(buffer,"%+E", nan()); + test_sok(buffer,"+NAN"); + line(4); + sprintf(buffer,"%+E", -nan()); + test_sok(buffer,"-NAN"); newfunc("nanf"); line(1); flt_inf_nan.value = nanf(); @@ -305,16 +318,29 @@ _DEFUN_VOID(test_nan_inf) newfunc("nanf print"); line(1); sprintf(buffer,"%f", nanf()); - test_sok(buffer,"NaN"); + test_sok(buffer,"nan"); line(2); sprintf(buffer,"%f", -nanf()); - test_sok(buffer,"NaN"); + test_sok(buffer,"nan"); line(3); sprintf(buffer,"%+f", nanf()); - test_sok(buffer,"+NaN"); + test_sok(buffer,"+nan"); line(4); sprintf(buffer,"%+f", -nanf()); - test_sok(buffer,"-NaN"); + test_sok(buffer,"-nan"); + newfunc("NANf print"); + line(1); + sprintf(buffer,"%F", nanf()); + test_sok(buffer,"NAN"); + line(2); + sprintf(buffer,"%F", -nanf()); + test_sok(buffer,"NAN"); + line(3); + sprintf(buffer,"%+F", nanf()); + test_sok(buffer,"+NAN"); + line(4); + sprintf(buffer,"%+F", -nanf()); + test_sok(buffer,"-NAN"); newfunc("infinity"); line(1); inf_nan.value = infinity(); @@ -327,16 +353,29 @@ _DEFUN_VOID(test_nan_inf) newfunc("infinity print"); line(1); sprintf(buffer,"%e", infinity()); - test_sok(buffer,"Inf"); + test_sok(buffer,"inf"); line(2); sprintf(buffer,"%e", -infinity()); - test_sok(buffer,"-Inf"); + test_sok(buffer,"-inf"); line(3); sprintf(buffer,"%+e", infinity()); - test_sok(buffer,"+Inf"); + test_sok(buffer,"+inf"); line(4); sprintf(buffer,"%+e", -infinity()); - test_sok(buffer,"-Inf"); + test_sok(buffer,"-inf"); + newfunc("INFINITY print"); + line(1); + sprintf(buffer,"%E", infinity()); + test_sok(buffer,"INF"); + line(2); + sprintf(buffer,"%E", -infinity()); + test_sok(buffer,"-INF"); + line(3); + sprintf(buffer,"%+E", infinity()); + test_sok(buffer,"+INF"); + line(4); + sprintf(buffer,"%+E", -infinity()); + test_sok(buffer,"-INF"); newfunc("infinityf"); line(1); flt_inf_nan.value = infinityf(); @@ -349,16 +388,29 @@ _DEFUN_VOID(test_nan_inf) newfunc("infinityf print"); line(1); sprintf(buffer,"%f", infinityf()); - test_sok(buffer,"Inf"); + test_sok(buffer,"inf"); line(2); sprintf(buffer,"%f", -infinityf()); - test_sok(buffer,"-Inf"); + test_sok(buffer,"-inf"); line(3); sprintf(buffer,"%+f", infinityf()); - test_sok(buffer,"+Inf"); + test_sok(buffer,"+inf"); line(4); sprintf(buffer,"%+f", -infinityf()); - test_sok(buffer,"-Inf"); + test_sok(buffer,"-inf"); + newfunc("INFINITYf print"); + line(1); + sprintf(buffer,"%F", infinityf()); + test_sok(buffer,"INF"); + line(2); + sprintf(buffer,"%F", -infinityf()); + test_sok(buffer,"-INF"); + line(3); + sprintf(buffer,"%+F", infinityf()); + test_sok(buffer,"+INF"); + line(4); + sprintf(buffer,"%+F", -infinityf()); + test_sok(buffer,"-INF"); #ifdef __DJGPP__ _fpreset(); #endif