bug-coreutils
[Top][All Lists]
Advanced

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

[PATCH] Fix automatic formating in seq


From: Pádraig Brady
Subject: [PATCH] Fix automatic formating in seq
Date: Mon, 9 Jul 2007 10:17:45 +0100
User-agent: Thunderbird 1.5.0.8 (X11/20061116)

While I was looking at the floating point rounding issues in seq
a couple of weeks ago, I noticed some anomalies with the width
automatically determined for floating point numbers,
and even for some integer number formats.
The changes this patch makes can be seen in the following
before and after examples.

cheers,
Pádraig.

#seq-after sets precision (format) automatically from scientific formats
#currently you see different widths
$ seq-before .8 1e-2 .9 | tail -2
0.89
0.9
$ seq-after .8 1e-2 .9 | tail -2
0.89
0.90

#seq-after sets precision (format) automatically from scientific formats
#currently you see inappropriate rounding
$ seq-before .89999 1e-7 .9 | tail -10
0.899999
0.899999
0.899999
0.899999
0.899999
0.9
0.9
0.9
0.9
0.9
$ seq-after .89999 1e-7 .9 | tail -10
0.8999991
0.8999992
0.8999993
0.8999994
0.8999995
0.8999996
0.8999997
0.8999998
0.8999999
0.9000000

#seq-after sets width appropriately when -w specified
#currently (I'm not sure as the code was seriously confusing),
#the format is just set to %Lg unless the precision
#of the first and step are the same.
$ seq-before 1 .5 2
1.0
1.5
2.0
$ seq-before -w 1 .5 2
1
1.5
2
$ seq-after -w 1 .5 2
1.0
1.5
2.0

#seq-after sets width appropriately when -w specified
#when plus included in the operands.
$ seq-before -w +1 2
01
02
$ seq-after -w +1 2
1
2

#seq-after sets width appropriately when -w specified
#when spaces included in the operands.
#Note fields here have only 4 spaces, but output width is 7.
$ seq-before  -w "    .1"  "    .1"
00000.1
$ seq-after  -w "    .1"  "    .1"
0.1
diff --git a/src/seq.c b/src/seq.c
index d5d5c53..ceb0e16 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -135,23 +135,33 @@ scan_arg (const char *arg)
       usage (EXIT_FAILURE);
     }
 
+  //We don't output ' ' or '+' so don't include in width
+  arg += strspn (arg, " +");
+
   ret.width = strlen (arg);
   ret.precision = INT_MAX;
 
-  if (! arg[strcspn (arg, "eExX")] && isfinite (ret.value))
+  if (! arg[strcspn (arg, "xX")] && isfinite (ret.value))
     {
       char const *decimal_point = strchr (arg, '.');
       if (! decimal_point)
        ret.precision = 0;
       else
        {
-         size_t fraction_len = strlen (decimal_point + 1);
+         size_t fraction_len = strcspn (decimal_point+1, "eE");
          if (fraction_len <= INT_MAX)
            ret.precision = fraction_len;
-         ret.width += (fraction_len == 0
+         ret.width += (fraction_len == 0                      //#.      -> #
                        ? -1
-                       : (decimal_point == arg
-                          || ! ISDIGIT (decimal_point[-1])));
+                       : (decimal_point == arg                //.#      -> 0.#
+                          || ! ISDIGIT (decimal_point[-1]))); //[ +-].# -> 0.#
+       }
+      char const *e = strchr(arg, 'e');
+      if (! e) e = strchr(arg, 'E');
+      if (e)
+       {
+         long exponent = strtol (e+1, NULL, 10);
+         ret.precision += exponent < 0 ? -exponent: 0;
        }
     }
 
@@ -275,18 +285,18 @@ get_default_format (operand first, operand step, operand 
last)
     {
       if (equal_width)
        {
+         //increase first_width by any increased precision in step
          size_t first_width = first.width + (prec - first.precision);
+         //adjust last_width to use precision from first/step
          size_t last_width = last.width + (prec - last.precision);
-         if (first.width <= first_width
-             && (last.width < last_width) == (prec < last.precision))
+         if (last.precision && prec == 0)
+           last_width--; //don't include space for '.'
+         size_t width = MAX (first_width, last_width);
+         if (width <= INT_MAX)
            {
-             size_t width = MAX (first_width, last_width);
-             if (width <= INT_MAX)
-               {
-                 int w = width;
-                 sprintf (format_buf, "%%0%d.%dLf", w, prec);
-                 return format_buf;
-               }
+             int w = width;
+             sprintf (format_buf, "%%0%d.%dLf", w, prec);
+             return format_buf;
            }
        }
       else
diff --git a/tests/seq/basic b/tests/seq/basic
index a710e19..505710a 100755
--- a/tests/seq/basic
+++ b/tests/seq/basic
@@ -56,12 +56,18 @@ my @Tests =
    ['float-5', qw(0.8 1e-1 0.9),       {OUT => [qw(0.8 0.9)]}],
    ['float-6', qw(0.8 0.1 0.90000000000000000000),     {OUT => [qw(0.8 0.9)]}],
 
-   ['eq-wid-1',        qw(-w 1 -1 -1), {OUT => [qw(01 00 -1)]}],
+   ['wid-1',   qw(.8 1e-2 .81),  {OUT => [qw(0.80 0.81)]}],
+   ['wid-2',   qw(.89999 1e-7 .8999901),  {OUT => [qw(0.8999900 0.8999901)]}],
 
+   ['eq-wid-1',        qw(-w 1 -1 -1), {OUT => [qw(01 00 -1)]}],
    # Prior to 2.0g, this test would fail on e.g., HPUX systems
    # because it'd end up using %3.1f as the format instead of %4.1f.
-   # ['eq-wid-2',      qw(-w -.1 .1 .11),{OUT => [qw(-0.1 00.0 00.1)]}],
-   # ['eq-wid-3',      qw(-w 1 3.0),  {OUT => [qw(1 2 3)]}],
+   ['eq-wid-2',        qw(-w -.1 .1 .11),{OUT => [qw(-0.1 00.0 00.1)]}],
+   ['eq-wid-3',        qw(-w 1 3.0),  {OUT => [qw(1 2 3)]}],
+   ['eq-wid-5',        qw(-w .8 1e-2 .81),  {OUT => [qw(0.80 0.81)]}],
+   ['eq-wid-6',        qw(-w 1 .5 2),  {OUT => [qw(1.0 1.5 2.0)]}],
+   ['eq-wid-7',        qw(-w +1 2),  {OUT => [qw(1 2)]}],
+   ['eq-wid-8',        qw(-w "    .1"  "    .1"),  {OUT => [qw(0.1)]}],
 
    # Prior to coreutils-4.5.11, some of these were not accepted.
    ['fmt-1',   qw(-f %2.1f 1.5 .5 2),{OUT => [qw(1.5 2.0)]}],

reply via email to

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