This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/4943] Inconsistent rounding behaviour for sprintf and IEEE doubles


------- 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 <math.h>
#include <string.h>
#include <stdio.h>

//______________________________________________________________________
// 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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]