bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: output rounding bug in vasnprintf %e format implementation


From: Bruno Haible
Subject: Re: output rounding bug in vasnprintf %e format implementation
Date: Sat, 19 Apr 2008 17:41:43 +0200
User-agent: KMail/1.5.4

Ben Pfaff wrote:
> [This issue arose in examination of bug 22924 against GNU PSPP,
> which may be viewed at https://savannah.gnu.org/bugs/?22924.]
> 
> The %e format implemented by gnulib's vasnprintf (when
> NEED_PRINTF_DOUBLE is defined) does not round properly in all
> cases.  Here is one example: 999.95 printed with %.4e should
> yield 9.9995e+02, but actually yields 1.0000e+03 with the gnulib
> implementation.

Thank you for reporting this. I'm committing the attached fix.

> The problem appears to be around line 3180 of vasnprintf.c.  This
> code calls floorlog10 to estimate the required exponent, which
> result can be off by 1, and then scale10_round_decimal_double to
> render the value with the selected exponent.  By adding a printf
> around here, I can see that floorlog10 chooses an exponent of 3.
> Of course then scale10_round_decimal_double renders that, quite
> reasonably, as 1.0000, and vasnprintf accepts that as correct.

Yes, this analysis is correct.

> A solution might be to make floorlog10 precise.  This might
> efficiently be possible by, for example, maintaining a table of
> powers of 10 generated at compile time or at program startup and
> performing binary search within it.

For 'long double', the binary exponent range goes from -16383 to 16384 on
many platforms. This means, you would need to store nearly 10000 powers of
10 in static storage. Not very practical.

Another solution would be to change floorlog10 so that for 10^n <= x < 10^(n+1)
it may return n or n-1 but not n+1. The result would then be correct because
the binary-to-decimal conversion would always be trying exponent = floorlog10(x)
before exponent = floorlog10(x)+1. In your example, it would be trying
exponent=2 before exponent=3.

But I don't really like this approach, because floorlog10 is computed through
floating-point, and it's hard to come up with sharp bounds. Basically
instead of returning  floor (approx-log (x)),  it would be returning
floor (approx-log (x) - 0.1) or so. But that would mean that with probability
0.1 it would be returning a value that is too small, without need, causing
an extra call to scale10_round_decimal_double.

Bruno


2008-04-19  Bruno Haible  <address@hidden>

        Fix rounding when a precision is given.
        * lib/vasnprintf.c (is_borderline): New function.
        (VASNPRINTF): For %e and %g, consider replacing the digits 10....0 with
        9...9x.
        * tests/test-vasnprintf-posix.c (test_function): Test rounding with %f,
        %e, %g.
        * tests/test-vasprintf-posix.c (test_function): Likewise.
        * tests/test-snprintf-posix.h (test_function): Likewise.
        * tests/test-sprintf-posix.h (test_function): Likewise.
        * tests/test-fprintf-posix.h (test_function): Test rounding with %f.
        * tests/test-printf-posix.h (test_function): Likewise.
        * tests/test-printf-posix.output: Update.
        Reported by John Darrington <address@hidden> via
        Ben Pfaff <address@hidden>.

*** lib/vasnprintf.c.orig       2008-04-19 16:56:21.000000000 +0200
--- lib/vasnprintf.c    2008-04-19 16:47:16.000000000 +0200
***************
*** 1404,1409 ****
--- 1404,1423 ----
  
  # endif
  
+ /* Tests whether a string of digits consists of exactly PRECISION zeroes and
+    a single '1' digit.  */
+ static int
+ is_borderline (const char *digits, size_t precision)
+ {
+   for (; precision > 0; precision--, digits++)
+     if (*digits != '0')
+       return 0;
+   if (*digits != '1')
+     return 0;
+   digits++;
+   return *digits == '\0';
+ }
+ 
  #endif
  
  DCHAR_T *
***************
*** 2853,2860 ****
                                          exponent += 1;
                                        adjusted = 1;
                                      }
- 
                                    /* Here ndigits = precision+1.  */
                                    *p++ = digits[--ndigits];
                                    if ((flags & FLAG_ALT) || precision > 0)
                                      {
--- 2867,2898 ----
                                          exponent += 1;
                                        adjusted = 1;
                                      }
                                    /* Here ndigits = precision+1.  */
+                                   if (is_borderline (digits, precision))
+                                     {
+                                       /* Maybe the exponent guess was too high
+                                          and a smaller exponent can be reached
+                                          by turning a 10...0 into 9...9x.  */
+                                       char *digits2 =
+                                         scale10_round_decimal_long_double 
(arg,
+                                                                            
(int)precision - exponent + 1);
+                                       if (digits2 == NULL)
+                                         {
+                                           free (digits);
+                                           END_LONG_DOUBLE_ROUNDING ();
+                                           goto out_of_memory;
+                                         }
+                                       if (strlen (digits2) == precision + 1)
+                                         {
+                                           free (digits);
+                                           digits = digits2;
+                                           exponent -= 1;
+                                         }
+                                       else
+                                         free (digits2);
+                                     }
+                                   /* Here ndigits = precision+1.  */
+ 
                                    *p++ = digits[--ndigits];
                                    if ((flags & FLAG_ALT) || precision > 0)
                                      {
***************
*** 2966,2971 ****
--- 3004,3033 ----
                                        adjusted = 1;
                                      }
                                    /* Here ndigits = precision.  */
+                                   if (is_borderline (digits, precision - 1))
+                                     {
+                                       /* Maybe the exponent guess was too high
+                                          and a smaller exponent can be reached
+                                          by turning a 10...0 into 9...9x.  */
+                                       char *digits2 =
+                                         scale10_round_decimal_long_double 
(arg,
+                                                                            
(int)(precision - 1) - exponent + 1);
+                                       if (digits2 == NULL)
+                                         {
+                                           free (digits);
+                                           END_LONG_DOUBLE_ROUNDING ();
+                                           goto out_of_memory;
+                                         }
+                                       if (strlen (digits2) == precision)
+                                         {
+                                           free (digits);
+                                           digits = digits2;
+                                           exponent -= 1;
+                                         }
+                                       else
+                                         free (digits2);
+                                     }
+                                   /* Here ndigits = precision.  */
  
                                    /* Determine the number of trailing zeroes
                                       that have to be dropped.  */
***************
*** 3206,3213 ****
                                          exponent += 1;
                                        adjusted = 1;
                                      }
- 
                                    /* Here ndigits = precision+1.  */
                                    *p++ = digits[--ndigits];
                                    if ((flags & FLAG_ALT) || precision > 0)
                                      {
--- 3268,3298 ----
                                          exponent += 1;
                                        adjusted = 1;
                                      }
                                    /* Here ndigits = precision+1.  */
+                                   if (is_borderline (digits, precision))
+                                     {
+                                       /* Maybe the exponent guess was too high
+                                          and a smaller exponent can be reached
+                                          by turning a 10...0 into 9...9x.  */
+                                       char *digits2 =
+                                         scale10_round_decimal_double (arg,
+                                                                       
(int)precision - exponent + 1);
+                                       if (digits2 == NULL)
+                                         {
+                                           free (digits);
+                                           goto out_of_memory;
+                                         }
+                                       if (strlen (digits2) == precision + 1)
+                                         {
+                                           free (digits);
+                                           digits = digits2;
+                                           exponent -= 1;
+                                         }
+                                       else
+                                         free (digits2);
+                                     }
+                                   /* Here ndigits = precision+1.  */
+ 
                                    *p++ = digits[--ndigits];
                                    if ((flags & FLAG_ALT) || precision > 0)
                                      {
***************
*** 3332,3337 ****
--- 3417,3445 ----
                                        adjusted = 1;
                                      }
                                    /* Here ndigits = precision.  */
+                                   if (is_borderline (digits, precision - 1))
+                                     {
+                                       /* Maybe the exponent guess was too high
+                                          and a smaller exponent can be reached
+                                          by turning a 10...0 into 9...9x.  */
+                                       char *digits2 =
+                                         scale10_round_decimal_double (arg,
+                                                                       
(int)(precision - 1) - exponent + 1);
+                                       if (digits2 == NULL)
+                                         {
+                                           free (digits);
+                                           goto out_of_memory;
+                                         }
+                                       if (strlen (digits2) == precision)
+                                         {
+                                           free (digits);
+                                           digits = digits2;
+                                           exponent -= 1;
+                                         }
+                                       else
+                                         free (digits2);
+                                     }
+                                   /* Here ndigits = precision.  */
  
                                    /* Determine the number of trailing zeroes
                                       that have to be dropped.  */
*** tests/test-fprintf-posix.h.orig     2008-04-19 16:56:21.000000000 +0200
--- tests/test-fprintf-posix.h  2008-04-19 16:00:47.000000000 +0200
***************
*** 1,5 ****
  /* Test of POSIX compatible vsprintf() and sprintf() functions.
!    Copyright (C) 2007 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,5 ----
  /* Test of POSIX compatible vsprintf() and sprintf() functions.
!    Copyright (C) 2007-2008 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 65,70 ****
--- 65,76 ----
    /* Precision.  */
    my_fprintf (stdout, "%.f %d\n", 1234.0, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_fprintf (stdout, "%.2f %d\n", 999.95, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_fprintf (stdout, "%.2f %d\n", 999.996, 33, 44, 55);
+ 
    /* A positive number.  */
    my_fprintf (stdout, "%Lf %d\n", 12.75L, 33, 44, 55);
  
***************
*** 83,88 ****
--- 89,100 ----
    /* Precision.  */
    my_fprintf (stdout, "%.Lf %d\n", 1234.0L, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_fprintf (stdout, "%.2Lf %d\n", 999.95L, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_fprintf (stdout, "%.2Lf %d\n", 999.996L, 33, 44, 55);
+ 
    /* Test the support of the %F format directive.  */
  
    /* A positive number.  */
***************
*** 103,108 ****
--- 115,126 ----
    /* Precision.  */
    my_fprintf (stdout, "%.F %d\n", 1234.0, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_fprintf (stdout, "%.2F %d\n", 999.95, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_fprintf (stdout, "%.2F %d\n", 999.996, 33, 44, 55);
+ 
    /* A positive number.  */
    my_fprintf (stdout, "%LF %d\n", 12.75L, 33, 44, 55);
  
***************
*** 121,126 ****
--- 139,150 ----
    /* Precision.  */
    my_fprintf (stdout, "%.LF %d\n", 1234.0L, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_fprintf (stdout, "%.2LF %d\n", 999.95L, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_fprintf (stdout, "%.2LF %d\n", 999.996L, 33, 44, 55);
+ 
    /* Test the support of the POSIX/XSI format strings with positions.  */
  
    my_fprintf (stdout, "%2$d %1$d\n", 33, 55);
*** tests/test-printf-posix.h.orig      2008-04-19 16:56:21.000000000 +0200
--- tests/test-printf-posix.h   2008-04-19 16:00:20.000000000 +0200
***************
*** 1,5 ****
  /* Test of POSIX compatible vsprintf() and sprintf() functions.
!    Copyright (C) 2007 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,5 ----
  /* Test of POSIX compatible vsprintf() and sprintf() functions.
!    Copyright (C) 2007-2008 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 67,72 ****
--- 67,78 ----
    /* Precision.  */
    my_printf ("%.f %d\n", 1234.0, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_printf ("%.2f %d\n", 999.95, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_printf ("%.2f %d\n", 999.996, 33, 44, 55);
+ 
    /* A positive number.  */
    my_printf ("%Lf %d\n", 12.75L, 33, 44, 55);
  
***************
*** 85,90 ****
--- 91,102 ----
    /* Precision.  */
    my_printf ("%.Lf %d\n", 1234.0L, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_printf ("%.2Lf %d\n", 999.95L, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_printf ("%.2Lf %d\n", 999.996L, 33, 44, 55);
+ 
    /* Test the support of the %F format directive.  */
  
    /* A positive number.  */
***************
*** 105,110 ****
--- 117,128 ----
    /* Precision.  */
    my_printf ("%.F %d\n", 1234.0, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_printf ("%.2F %d\n", 999.95, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_printf ("%.2F %d\n", 999.996, 33, 44, 55);
+ 
    /* A positive number.  */
    my_printf ("%LF %d\n", 12.75L, 33, 44, 55);
  
***************
*** 123,128 ****
--- 141,152 ----
    /* Precision.  */
    my_printf ("%.LF %d\n", 1234.0L, 33, 44, 55);
  
+   /* Precision with no rounding.  */
+   my_printf ("%.2LF %d\n", 999.95L, 33, 44, 55);
+ 
+   /* Precision with rounding.  */
+   my_printf ("%.2LF %d\n", 999.996L, 33, 44, 55);
+ 
    /* Test the support of the POSIX/XSI format strings with positions.  */
  
    my_printf ("%2$d %1$d\n", 33, 55);
*** tests/test-printf-posix.output.orig 2008-04-19 16:56:21.000000000 +0200
--- tests/test-printf-posix.output      2008-04-19 13:58:28.000000000 +0200
***************
*** 11,32 ****
--- 11,40 ----
  0.000000 33
  00001234.000000 33
  1234 33
+ 999.95 33
+ 1000.00 33
  12.750000 33
  1234567.000000 33
  -0.031250 33
  0.000000 33
  00001234.000000 33
  1234 33
+ 999.95 33
+ 1000.00 33
  12.750000 33
  1234567.000000 33
  -0.031250 33
  0.000000 33
  00001234.000000 33
  1234 33
+ 999.95 33
+ 1000.00 33
  12.750000 33
  1234567.000000 33
  -0.031250 33
  0.000000 33
  00001234.000000 33
  1234 33
+ 999.95 33
+ 1000.00 33
  55 33
*** tests/test-snprintf-posix.h.orig    2008-04-19 16:56:21.000000000 +0200
--- tests/test-snprintf-posix.h 2008-04-19 15:34:09.000000000 +0200
***************
*** 1004,1009 ****
--- 1004,1025 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2f %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2f %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[100];
      int retval =
***************
*** 1338,1343 ****
--- 1354,1375 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2Lf %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2Lf %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %F format directive.  */
  
    { /* A positive number.  */
***************
*** 1434,1439 ****
--- 1466,1487 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2F %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2F %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[100];
      int retval =
***************
*** 1528,1533 ****
--- 1576,1597 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2LF %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.2LF %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %e format directive.  */
  
    { /* A positive number.  */
***************
*** 1802,1807 ****
--- 1866,1889 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.4e %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0
+           || strcmp (result, "9.9995e+002 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.4e %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0
+           || strcmp (result, "1.0000e+003 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[100];
      int retval =
***************
*** 2138,2143 ****
--- 2220,2241 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.4Le %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.4Le %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %g format directive.  */
  
    { /* A positive number.  */
***************
*** 2401,2406 ****
--- 2499,2520 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.5g %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.5g %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[100];
      int retval =
***************
*** 2737,2742 ****
--- 2851,2872 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.5Lg %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_snprintf (result, sizeof (result), "%.5Lg %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %n format directive.  */
  
    {
*** tests/test-sprintf-posix.h.orig     2008-04-19 16:56:21.000000000 +0200
--- tests/test-sprintf-posix.h  2008-04-19 16:04:33.000000000 +0200
***************
*** 984,989 ****
--- 984,1005 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2f %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2f %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[1000];
      int retval =
***************
*** 1312,1317 ****
--- 1328,1349 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2Lf %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2Lf %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %F format directive.  */
  
    { /* A positive number.  */
***************
*** 1408,1413 ****
--- 1440,1461 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2F %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2F %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[1000];
      int retval =
***************
*** 1502,1507 ****
--- 1550,1571 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2LF %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.2LF %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %e format directive.  */
  
    { /* A positive number.  */
***************
*** 1776,1781 ****
--- 1840,1863 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.4e %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0
+           || strcmp (result, "9.9995e+002 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.4e %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0
+           || strcmp (result, "1.0000e+003 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[1000];
      int retval =
***************
*** 2112,2117 ****
--- 2194,2215 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.4Le %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.4Le %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %g format directive.  */
  
    { /* A positive number.  */
***************
*** 2375,2380 ****
--- 2473,2494 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.5g %d", 999.951, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.5g %d", 999.996, 33, 44, 55);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    { /* A positive number.  */
      char result[1000];
      int retval =
***************
*** 2711,2716 ****
--- 2825,2846 ----
      ASSERT (retval == strlen (result));
    }
  
+   { /* Precision with no rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.5Lg %d", 999.951L, 33, 44, 55);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
+   { /* Precision with rounding.  */
+     char result[100];
+     int retval =
+       my_sprintf (result, "%.5Lg %d", 999.996L, 33, 44, 55);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+   }
+ 
    /* Test the support of the %n format directive.  */
  
    {
*** tests/test-vasnprintf-posix.c.orig  2008-04-19 16:56:21.000000000 +0200
--- tests/test-vasnprintf-posix.c       2008-04-19 16:15:14.000000000 +0200
***************
*** 1189,1194 ****
--- 1189,1214 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2f %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2f %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      size_t length;
      char *result =
***************
*** 1569,1574 ****
--- 1589,1614 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2Lf %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2Lf %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %F format directive.  */
  
    { /* A positive number.  */
***************
*** 1687,1692 ****
--- 1727,1752 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2F %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2F %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      size_t length;
      char *result =
***************
*** 1803,1808 ****
--- 1863,1888 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2LF %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.2LF %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %e format directive.  */
  
    { /* A positive number.  */
***************
*** 2116,2121 ****
--- 2196,2223 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.4e %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0
+           || strcmp (result, "9.9995e+002 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.4e %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0
+           || strcmp (result, "1.0000e+003 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      size_t length;
      char *result =
***************
*** 2506,2511 ****
--- 2608,2633 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.4Le %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.4Le %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %g format directive.  */
  
    { /* A positive number.  */
***************
*** 2809,2814 ****
--- 2931,2956 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.5g %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.5g %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      size_t length;
      char *result =
***************
*** 3199,3204 ****
--- 3341,3366 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.5Lg %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     size_t length;
+     char *result =
+       my_asnprintf (NULL, &length, "%.5Lg %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (length == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %n format directive.  */
  
    {
*** tests/test-vasprintf-posix.c.orig   2008-04-19 16:56:21.000000000 +0200
--- tests/test-vasprintf-posix.c        2008-04-19 16:10:17.000000000 +0200
***************
*** 1170,1175 ****
--- 1170,1195 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2f %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2f %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      char *result;
      int retval =
***************
*** 1550,1555 ****
--- 1570,1595 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2Lf %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2Lf %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %F format directive.  */
  
    { /* A positive number.  */
***************
*** 1668,1673 ****
--- 1708,1733 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2F %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2F %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      char *result;
      int retval =
***************
*** 1784,1789 ****
--- 1844,1869 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2LF %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.2LF %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000.00 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %e format directive.  */
  
    { /* A positive number.  */
***************
*** 2097,2102 ****
--- 2177,2204 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.4e %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0
+           || strcmp (result, "9.9995e+002 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.4e %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0
+           || strcmp (result, "1.0000e+003 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      char *result;
      int retval =
***************
*** 2487,2492 ****
--- 2589,2614 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.4Le %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "9.9995e+02 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.4Le %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1.0000e+03 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %g format directive.  */
  
    { /* A positive number.  */
***************
*** 2790,2795 ****
--- 2912,2937 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.5g %d", 999.951, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.5g %d", 999.996, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    { /* A positive number.  */
      char *result;
      int retval =
***************
*** 3180,3185 ****
--- 3322,3347 ----
      free (result);
    }
  
+   { /* Precision with no rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.5Lg %d", 999.951L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "999.95 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
+   { /* Precision with rounding.  */
+     char *result;
+     int retval =
+       my_asprintf (&result, "%.5Lg %d", 999.996L, 33, 44, 55);
+     ASSERT (result != NULL);
+     ASSERT (strcmp (result, "1000 33") == 0);
+     ASSERT (retval == strlen (result));
+     free (result);
+   }
+ 
    /* Test the support of the %n format directive.  */
  
    {





reply via email to

[Prev in Thread] Current Thread [Next in Thread]