]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - stdio-common/printf_fp.c
.
[thirdparty/glibc.git] / stdio-common / printf_fp.c
index e4e32f9c2815d6180a2849b6407f3158064e83a2..b48b6896614b347eb5b6d9c81b5b5979caa7ba3e 100644 (file)
@@ -1,6 +1,5 @@
 /* Floating point output for `printf'.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2006
-   Free Software Foundation, Inc.
+   Copyright (C) 1995-2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
@@ -793,7 +792,7 @@ ___printf_fp (FILE *fp,
   else
     {
       /* This is a special case.  We don't need a factor because the
-        numbers are in the range of 0.0 <= fp < 8.0.  We simply
+        numbers are in the range of 1.0 <= |fp| < 8.0.  We simply
         shift it to the right place and divide it by 1.0 to get the
         leading digit.  (Of course this division is not really made.)  */
       assert (0 <= exponent && exponent < 3 &&
@@ -811,12 +810,14 @@ ___printf_fp (FILE *fp,
     int chars_needed;
     int expscale;
     int intdig_max, intdig_no = 0;
-    int fracdig_min, fracdig_max, fracdig_no = 0;
+    int fracdig_min;
+    int fracdig_max;
     int dig_max;
     int significant;
     int ngroups = 0;
+    char spec = _tolower (info->spec);
 
-    if (_tolower (info->spec) == 'e')
+    if (spec == 'e')
       {
        type = info->spec;
        intdig_max = 1;
@@ -826,7 +827,7 @@ ___printf_fp (FILE *fp,
        dig_max = INT_MAX;              /* Unlimited.  */
        significant = 1;                /* Does not matter here.  */
       }
-    else if (_tolower (info->spec) == 'f')
+    else if (spec == 'f')
       {
        type = 'f';
        fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
@@ -923,7 +924,9 @@ ___printf_fp (FILE *fp,
       }
 
     /* Generate the needed number of fractional digits.         */
-    while (fracdig_no < fracdig_min
+    int fracdig_no = 0;
+    int added_zeros = 0;
+    while (fracdig_no < fracdig_min + added_zeros
           || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0)))
       {
        ++fracdig_no;
@@ -934,7 +937,7 @@ ___printf_fp (FILE *fp,
          {
            ++fracdig_max;
            if (fracdig_min > 0)
-             ++fracdig_min;
+             ++added_zeros;
          }
       }
 
@@ -971,11 +974,25 @@ ___printf_fp (FILE *fp,
          {
            /* Process fractional digits.  Terminate if not rounded or
               radix character is reached.  */
+           int removed = 0;
            while (*--wtp != decimalwc && *wtp == L'9')
-             *wtp = '0';
+             {
+               *wtp = L'0';
+               ++removed;
+             }
+           if (removed == fracdig_min && added_zeros > 0)
+             --added_zeros;
            if (*wtp != decimalwc)
              /* Round up.  */
              (*wtp)++;
+           else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt
+                                      && wtp == wstartp + 1
+                                      && wstartp[0] == L'0',
+                                      0))
+             /* This is a special case: the rounded number is 1.0,
+                the format is 'g' or 'G', and the alternative format
+                is selected.  This means the result must be "1.".  */
+             --added_zeros;
          }
 
        if (fracdig_no == 0 || *wtp == decimalwc)
@@ -997,6 +1014,12 @@ ___printf_fp (FILE *fp,
                  {
                    *wstartp = '1';
                    exponent += expsign == 0 ? 1 : -1;
+
+                   /* The above exponent adjustment could lead to 1.0e-00,
+                      e.g. for 0.999999999.  Make sure exponent 0 always
+                      uses + sign.  */
+                   if (exponent == 0)
+                     expsign = 0;
                  }
                else if (intdig_no == dig_max)
                  {
@@ -1042,7 +1065,7 @@ ___printf_fp (FILE *fp,
 
   do_expo:
     /* Now remove unnecessary '0' at the end of the string.  */
-    while (fracdig_no > fracdig_min && *(wcp - 1) == L'0')
+    while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L'0')
       {
        --wcp;
        --fracdig_no;
@@ -1060,26 +1083,46 @@ ___printf_fp (FILE *fp,
     /* Write the exponent if it is needed.  */
     if (type != 'f')
       {
-       *wcp++ = (wchar_t) type;
-       *wcp++ = expsign ? L'-' : L'+';
+       if (__builtin_expect (expsign != 0 && exponent == 4 && spec == 'g', 0))
+         {
+           /* This is another special case.  The exponent of the number is
+              really smaller than -4, which requires the 'e'/'E' format.
+              But after rounding the number has an exponent of -4.  */
+           assert (wcp >= wstartp + 1);
+           assert (wstartp[0] == L'1');
+           __wmemcpy (wstartp, L"0.0001", 6);
+           wstartp[1] = decimalwc;
+           if (wcp >= wstartp + 2)
+             {
+               wmemset (wstartp + 6, L'0', wcp - (wstartp + 2));
+               wcp += 4;
+             }
+           else
+             wcp += 5;
+         }
+       else
+         {
+           *wcp++ = (wchar_t) type;
+           *wcp++ = expsign ? L'-' : L'+';
 
-       /* Find the magnitude of the exponent.  */
-       expscale = 10;
-       while (expscale <= exponent)
-         expscale *= 10;
+           /* Find the magnitude of the exponent.      */
+           expscale = 10;
+           while (expscale <= exponent)
+             expscale *= 10;
 
-       if (exponent < 10)
-         /* Exponent always has at least two digits.  */
-         *wcp++ = L'0';
-       else
-         do
-           {
-             expscale /= 10;
-             *wcp++ = L'0' + (exponent / expscale);
-             exponent %= expscale;
-           }
-         while (expscale > 10);
-       *wcp++ = L'0' + exponent;
+           if (exponent < 10)
+             /* Exponent always has at least two digits.  */
+             *wcp++ = L'0';
+           else
+             do
+               {
+                 expscale /= 10;
+                 *wcp++ = L'0' + (exponent / expscale);
+                 exponent %= expscale;
+               }
+             while (expscale > 10);
+           *wcp++ = L'0' + exponent;
+         }
       }
 
     /* Compute number of characters which must be filled with the padding