From patchwork Thu Mar 17 21:41:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Paul E. Murphy" X-Patchwork-Id: 11366 X-Patchwork-Delegate: joseph@codesourcery.com Received: (qmail 5421 invoked by alias); 17 Mar 2016 21:41:20 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 5385 invoked by uid 89); 17 Mar 2016 21:41:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=no version=3.3.2 spammy=ud, aide, hexadecimal, differ X-HELO: e32.co.us.ibm.com X-IBM-Helo: d03dlp01.boulder.ibm.com X-IBM-MailFrom: murphyp@linux.vnet.ibm.com X-IBM-RcptTo: libc-alpha@sourceware.org From: "Paul E. Murphy" Subject: [PATCH] Increase internal precision of ldbl-128ibm decimal printf To: "libc-alpha@sourceware.org" Cc: Tulio Magno Quites Machado Filho Message-ID: <56EB246E.4050504@linux.vnet.ibm.com> Date: Thu, 17 Mar 2016 16:41:02 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16031721-0005-0000-0000-00001E7410E0 When the signs differ, the precision of the conversion could drop below 106 bits. This strategy is identical to the hexadecimal variant. 0x1.ffffffffffffffffffffffffff80p111L is an example of a number which should, but does not round trip through printf as a decimal number when printing with 32 digits of precision. Note, the printf test did not pick this up, as it only tests up to 30 digits. Long double can have more at nominal precision. 2016-03-17 Paul E. Murphy * sysdeps/ieee754/ldbl-128ibm/ldbl2pm.c: (__mpn_extract_long_double): Carry 7 extra intermediate bits of precision to aide computing difference when signs differ. --- sysdeps/ieee754/ldbl-128ibm/ldbl2mpn.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sysdeps/ieee754/ldbl-128ibm/ldbl2mpn.c b/sysdeps/ieee754/ldbl-128ibm/ldbl2mpn.c index 4f550ef..afe6cf2 100644 --- a/sysdeps/ieee754/ldbl-128ibm/ldbl2mpn.c +++ b/sysdeps/ieee754/ldbl-128ibm/ldbl2mpn.c @@ -45,12 +45,17 @@ __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, lo = ((long long) u.d[1].ieee.mantissa0 << 32) | u.d[1].ieee.mantissa1; hi = ((long long) u.d[0].ieee.mantissa0 << 32) | u.d[0].ieee.mantissa1; + /* Hold 7 extra bits of precision in the mantissa. This allows + the normalizing shifts below to prevent losing precision when + the signs differ and the exponents are sufficiently far apart. */ + lo <<= 7; + /* If the lower double is not a denormal or zero then set the hidden 53rd bit. */ if (u.d[1].ieee.exponent != 0) - lo |= 1ULL << 52; + lo |= 1ULL << (52 + 7); else - lo = lo << 1; + lo = lo << (1 + 7); /* The lower double is normalized separately from the upper. We may need to adjust the lower manitissa to reflect this. */ @@ -72,12 +77,12 @@ __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, if (u.d[0].ieee.negative != u.d[1].ieee.negative && lo != 0) { - lo = (1ULL << 53) - lo; + lo = (1ULL << (53 + 7)) - lo; if (hi == 0) { /* we have a borrow from the hidden bit, so shift left 1. */ - hi = 0x0ffffffffffffeLL | (lo >> 51); - lo = 0x1fffffffffffffLL & (lo << 1); + hi = 0x000ffffffffffffeLL | (lo >> (52 + 7)); + lo = 0x0fffffffffffffffLL & (lo << 1); (*expt)--; } else @@ -85,14 +90,14 @@ __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, } #if BITS_PER_MP_LIMB == 32 /* Combine the mantissas to be contiguous. */ - res_ptr[0] = lo; - res_ptr[1] = (hi << (53 - 32)) | (lo >> 32); + res_ptr[0] = lo >> 7; + res_ptr[1] = (hi << (53 - 32)) | (lo >> (32 + 7)); res_ptr[2] = hi >> 11; res_ptr[3] = hi >> (32 + 11); #define N 4 #elif BITS_PER_MP_LIMB == 64 /* Combine the two mantissas to be contiguous. */ - res_ptr[0] = (hi << 53) | lo; + res_ptr[0] = (hi << 53) | (lo >> 7); res_ptr[1] = hi >> 11; #define N 2 #else