From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31563 invoked by alias); 25 Sep 2007 06:51:15 -0000 Received: (qmail 31507 invoked by uid 48); 25 Sep 2007 06:51:05 -0000 Date: Tue, 25 Sep 2007 06:51:00 -0000 Message-ID: <20070925065105.31506.qmail@sourceware.org> From: "paul at inet dot co dot za" To: glibc-bugs@sources.redhat.com In-Reply-To: <20070820142205.4943.paul@inet.co.za> References: <20070820142205.4943.paul@inet.co.za> Reply-To: sourceware-bugzilla@sourceware.org Subject: [Bug libc/4943] Inconsistent rounding behaviour for sprintf and IEEE doubles X-Bugzilla-Reason: CC Mailing-List: contact glibc-bugs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: glibc-bugs-owner@sourceware.org X-SW-Source: 2007-09/txt/msg00132.txt.bz2 ------- Additional Comments From paul at inet dot co dot za 2007-09-25 06:51 ------- Vincent, one last thing: Would you mind testing the following on your PPC? Just a one liner change effectively; the other changes are just buffer overrun traps. Many thanks, Paul #include #include #include //______________________________________________________________________ // Utility function converts an IEEE double precision number to a // fixed precision decimal format stored in a buffer. void tobuf(size_t max, int *len, char *buf, double x, int precision, double max_prec, double carry) { int sign = x < 0; // remember the sign double q = pow(10,-precision); // current mask double y = x==0?0:fmod(fabs(x), q); // modulus double l_div = round(y*max_prec)/max_prec+carry; // significant digit int l_dec = (int)round(l_div*10/q); // round to decimal carry = l_dec>=10?l_div:0; // carry forward? l_dec = l_dec % 10; // this decimal x = x>0?x-y:x+y; // subtract modulus if (fabs(x) > 0) // recurse while |x| > 0 tobuf(max, len, buf, x, precision-1, max_prec, carry); else { // x == 0 - first digit if (*len+1 < max && sign) { buf[*len] = '-'; *len = *len + 1; } if (*len+2 < max && precision >= 0) { buf[*len] = '0'; *len = *len + 1; buf[*len] = '.'; *len = *len + 1; } while (*len+1 < max && precision-- > 0) { buf[*len] = '0'; *len = *len + 1; } precision = -1; // don't place another period } if (*len+1 < max && precision == 0) { buf[*len] = '.'; *len = *len + 1; } // for first and subsequent digits, add the digit to the buffer if (*len+1 >= max) return; if (l_dec < 0) l_dec = 0; buf[*len] = '0' + l_dec; *len = *len + 1; } //______________________________________________________________________ // Convert the value x to a decimal representation stored in a buffer int dbl2buf(size_t max, char *buf, double x, int precision) { const int DECIMALS=15; // max significant digits int max_dec = DECIMALS-(int)(trunc(log10(fabs(x)))+1); double max_prec = pow(10,max_dec); // magnitude for precision loss int len = 0; // buffer length init double y = x==0?0:fmod(fabs(x), 1/max_prec); // determine error double l_carry = round(y*max_prec)/max_prec; // error is carried forward x = x>0?x-y:x+y; // subtract modulus if (x != x) { strncpy(buf, "NAN", max); return 0; } if ((x-x) != (x-x)) { strncpy(buf, "INF", max); return 0; } tobuf(max, &len, buf, x, precision-1, max_prec, l_carry); // fill in buffer buf[len] = 0; // terminate buffer return len; // return buffer length used } int main (void) { int n; double x; char buf[64]; x = 5000.525; dbl2buf(sizeof(buf), buf, x, 2); printf("%.15f = %s\n", x, buf); x = 2596.625; dbl2buf(sizeof(buf), buf, x, 2); printf("%.15f = %s\n", x, buf); x = 2596.525; dbl2buf(sizeof(buf), buf, x, 2); printf("%.15f = %s\n", x, buf); for (x = -8.5; x <= 8.5; ++x) { dbl2buf(sizeof(buf), buf, x, 0); printf("%.15f = %s\n", x, buf); } for (x = -8.5; x <= 8.5; ++x) { dbl2buf(sizeof(buf), buf, x, 24); printf("%.15f = %s\n", x, buf); } return 0; } -- http://sourceware.org/bugzilla/show_bug.cgi?id=4943 ------- You are receiving this mail because: ------- You are on the CC list for the bug, or are watching someone who is.