From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24518 invoked by alias); 4 Jun 2007 13:00:19 -0000 Received: (qmail 24499 invoked by uid 22791); 4 Jun 2007 13:00:19 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 04 Jun 2007 13:00:16 +0000 Received: from sunsite.mff.cuni.cz (localhost.localdomain [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.8/8.13.8) with ESMTP id l54D2AE9001578; Mon, 4 Jun 2007 15:02:10 +0200 Received: (from jakub@localhost) by sunsite.mff.cuni.cz (8.13.8/8.13.8/Submit) id l54D29H3001575; Mon, 4 Jun 2007 15:02:09 +0200 Date: Mon, 04 Jun 2007 13:00:00 -0000 From: Jakub Jelinek To: Ulrich Drepper , Steven Munroe Cc: Glibc hackers Subject: [PATCH] Fix *printf %La with IBM long double format Message-ID: <20070604130209.GM3081@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2007-06/txt/msg00002.txt.bz2 Hi! As the attached testcase shows, printf_fphex for ldbl-128ibm has a bunch of issues when the lower double is denormal or has exponent 1. E.g. the implicit mantissa bit needs to be also set for exponent 1, the difference between exponents might be smaller than 53 (when the smaller double is denormal and the bigger double has exponent less than 53, etc. I've also included the unrelated workaround for test-misc.c failures - the tests from 2007-05-03 aren't really testable on ppc/ppc64. 2007-06-04 Jakub Jelinek * sysdeps/ieee754/ldbl-128ibm/printf_fphex.c (PRINT_FPHEX_LONG_DOUBLE): Fix printing numbers where lower double is non-zero, but smaller than 2 * __DBL_MIN__. * stdio-common/tst-sprintf2.c: New test. * stdio-common/Makefile (tests): Add tst-sprintf2. * math/test-misc.c (main): Don't run last batch of tests with IBM long double format. --- libc/sysdeps/ieee754/ldbl-128ibm/printf_fphex.c.jj 2006-01-28 01:07:25.000000000 +0100 +++ libc/sysdeps/ieee754/ldbl-128ibm/printf_fphex.c 2007-06-04 14:02:12.000000000 +0200 @@ -1,5 +1,5 @@ /* Print floating point number in hexadecimal notation according to ISO C99. - Copyright (C) 1997,1998,1999,2000,2001,2002,2004,2006 + Copyright (C) 1997,1998,1999,2000,2001,2002,2004,2006,2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. @@ -35,21 +35,24 @@ do { \ \ lo = ((long long)eldbl.ieee.mantissa2 << 32) | eldbl.ieee.mantissa3; \ hi = ((long long)eldbl.ieee.mantissa0 << 32) | eldbl.ieee.mantissa1; \ - /* If the lower double is not a denomal or zero then set the hidden \ - 53rd bit. */ \ - if (eldbl.ieee.exponent2 > 0x001) \ - { \ - lo |= (1ULL << 52); \ - lo = lo << 7; /* pre-shift lo to match ieee854. */ \ - /* The lower double is normalized separately from the upper. We \ - may need to adjust the lower manitissa to reflect this. */ \ - ediff = eldbl.ieee.exponent - eldbl.ieee.exponent2; \ - if (ediff > 53) \ - lo = lo >> (ediff-53); \ - } \ - \ - if ((eldbl.ieee.negative != eldbl.ieee.negative2) \ - && ((eldbl.ieee.exponent2 != 0) && (lo != 0L))) \ + lo <<= 7; /* pre-shift lo to match ieee854. */ \ + /* If the lower double is not a denomal or zero then set the hidden \ + 53rd bit. */ \ + if (eldbl.ieee.exponent2 != 0) \ + lo |= (1ULL << (52 + 7)); \ + else \ + lo <<= 1; \ + /* The lower double is normalized separately from the upper. We \ + may need to adjust the lower manitissa to reflect this. */ \ + ediff = eldbl.ieee.exponent - eldbl.ieee.exponent2; \ + if (ediff > 53 + 63) \ + lo = 0; \ + else if (ediff > 53) \ + lo = lo >> (ediff - 53); \ + else if (eldbl.ieee.exponent2 == 0 && ediff < 53) \ + lo = lo << (53 - ediff); \ + if (eldbl.ieee.negative != eldbl.ieee.negative2 \ + && (eldbl.ieee.exponent2 != 0 || lo != 0L)) \ { \ lo = (1ULL << 60) - lo; \ if (hi == 0L) \ --- libc/stdio-common/Makefile.jj 2007-03-19 17:43:12.000000000 +0100 +++ libc/stdio-common/Makefile 2007-06-04 14:05:02.000000000 +0200 @@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \ - tst-fwrite bug16 bug17 tst-swscanf + tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 test-srcs = tst-unbputc tst-printf --- libc/stdio-common/tst-sprintf2.c.jj 2007-06-04 14:03:18.000000000 +0200 +++ libc/stdio-common/tst-sprintf2.c 2007-06-04 14:04:35.000000000 +0200 @@ -0,0 +1,59 @@ +#include +#include +#include + +int +main (void) +{ + volatile union { long double l; long long x[2]; } u; + char buf[64]; + int result = 0; + +#define TEST(val) \ + do \ + { \ + u.l = (val); \ + snprintf (buf, sizeof buf, "%LaL", u.l); \ + if (strcmp (buf, #val) != 0) \ + { \ + printf ("Error on line %d: %s != %s\n", __LINE__, buf, #val); \ + result = 1; \ + } \ + /* printf ("%s %La %016Lx %016Lx\n", #val, u.l, u.x[0], u.x[1]); */ \ + } \ + while (0) + +#if LDBL_MANT_DIG >= 106 +# if LDBL_MANT_DIG == 106 + TEST (0x0.ffffffffffffp-1022L); + TEST (0x0.ffffffffffff1p-1022L); + TEST (0x0.fffffffffffffp-1022L); +# endif + TEST (0x1p-1022L); + TEST (0x1.0000000000001p-1022L); + TEST (0x1.00000000001e7p-1022L); + TEST (0x1.fffffffffffffp-1022L); + TEST (0x1p-1021L); + TEST (0x1.00000000000008p-1021L); + TEST (0x1.0000000000001p-1021L); + TEST (0x1.00000000000018p-1021L); + TEST (0x1.0000000000000f8p-1017L); + TEST (0x1.0000000000001p-1017L); + TEST (0x1.000000000000108p-1017L); + TEST (0x1.000000000000dcf8p-1013L); + TEST (0x1.000000000000ddp-1013L); + TEST (0x1.000000000000dd08p-1013L); + TEST (0x1.ffffffffffffffffffffffffffp-1L); + TEST (0x1.ffffffffffffffffffffffffff8p-1L); + TEST (0x1p+0L); + TEST (0x1.000000000000000000000000008p+0L); + TEST (0x1.00000000000000000000000001p+0L); + TEST (0x1.000000000000000000000000018p+0L); + TEST (0x1.23456789abcdef123456789abc8p+0L); + TEST (0x1.23456789abcde7123456789abc8p+0L); + TEST (0x1.23456789abcdef123456789abc8p+64L); + TEST (0x1.23456789abcde7123456789abc8p+64L); + TEST (0x1.123456789abcdef123456789p-969L); +#endif + return result; +} --- libc/math/test-misc.c.jj 2007-05-24 16:41:05.000000000 +0200 +++ libc/math/test-misc.c 2007-06-01 18:28:29.000000000 +0200 @@ -1235,7 +1235,12 @@ main (void) } #endif -#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG >= DBL_MANT_DIG + 4 +/* Skip testing IBM long double format, for 2 reasons: + 1) it only supports FE_TONEAREST + 2) nextafter (0.0, 1.0) == nextafterl (0.0L, 1.0L), so + nextafter (0.0, 1.0) / 16.0L will be 0.0L. */ +#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG >= DBL_MANT_DIG + 4 \ + && LDBL_MANT_DIG != 106 int oldmode = fegetround (); int j; for (j = 0; j < 4; j++) Jakub