Hi,

I've already sent this bug report to <[EMAIL PROTECTED]>,
but didn't get any response or confirmation up to now. From
what I've seen in the sh-utils ChangeLog, you seem to be
a key person for the sh-utils, so maybe you can at least
forward this message to someone, who's responsible for
maintaining the package.  

Problem:

seq does not always print all numbers from FIRST to LAST.
The output may vary with different systems.

Here is a screen dump on Linux-2.2.19 (i386):

juergen@anna:~ > seq -s " " 0 .1 1
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9   # 1 missing
juergen@anna:~ > seq -s " " 0 .1 1.1
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1   # ok.
juergen@anna:~ > seq -s " " 0 .1 1.2
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1   # 1.2 missing
juergen@anna:~ > seq -s " " 0 .1 1.3
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2   # 1.3 missing 
juergen@anna:~ > seq -s " " 0 .1 1.4
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3  # 1.4 missing 

And this is a screen dump on Solaris 8 (sparc)

lyra$ seq -s " " 0 .1 1
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1   # ok.
lyra$ seq -s " " 0 .1 1.1
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1   #ok.
lyra$ seq -s " " 0 .1 1.2
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1   # 1.2 missing
lyra$ seq -s " " 0 .1 1.3
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3  # ok.
lyra$ seq -s " " 0 .1 1.4
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3  # 1.4 missing


Reason:

Due to the general lack of absolute accuracy of floating point values
the loop termination condition in 

          double x = first + i * step;

          if (x > last)
            break;

can fail if the floating point representation of the value x is slightly
higher than the 'real' value (in a mathematical sence).


Solution:

Don't assume that floating-point values will be exact. Use a safety margin 
for the termination threshold, which is relative to the magnitude of the 
numbers being compared. (See attached patch.)

I have already sent a patch to <[EMAIL PROTECTED]> on Sep 15. However that one
may fail if (LAST-FIRST) is not an integer multiple of STEP (as I've noticed later).
This one introduces DBL_EPSILON from <float.h> for an appropriate margin.
It's patched against sh-utils-2.0j, which I've grabbed from the alpha FTP
server.

Thank you for considering my request.

Best regards - Juergen Salk

--- seq.c.orig  Wed Sep 19 21:24:02 2001
+++ seq.c       Wed Sep 19 21:24:33 2001
@@ -21,6 +21,7 @@
 #include <getopt.h>
 #include <math.h>
 #include <stdio.h>
+#include <float.h>
 #include <sys/types.h>
 
 #include "system.h"
@@ -177,6 +178,7 @@
   if (first > last)
     {
       int i;
+      double threshold;
 
       if (step >= 0)
        {
@@ -186,12 +188,21 @@
          usage (1);
        }
 
+      /* Don't assume that floating-point values will be exact.
+         Use an error margin which is relative to the magnitude 
+         of the numbers being compared. */
+
+      if ( last != 0.0 )
+       threshold = last - fabs(last) * sqrt(DBL_EPSILON);
+      else
+       threshold = last - fabs(step) * sqrt(DBL_EPSILON);
+
       printf (fmt, first);
       for (i = 1; /* empty */; i++)
        {
          double x = first + i * step;
 
-         if (x < last)
+         if (x < threshold)
            break;
 
          fputs (separator, stdout);
@@ -201,6 +212,7 @@
   else
     {
       int i;
+      double threshold;
 
       if (step <= 0)
        {
@@ -210,12 +222,21 @@
          usage (1);
        }
 
+      /* Don't assume that floating-point values will be exact.
+         Use an error margin which is relative to the magnitude 
+         of the numbers being compared. */
+
+      if ( last != 0.0 )
+       threshold = last + fabs(last) * sqrt(DBL_EPSILON);
+      else
+       threshold = last + fabs(step) * sqrt(DBL_EPSILON);
+
       printf (fmt, first);
       for (i = 1; /* empty */; i++)
        {
          double x = first + i * step;
 
-         if (x > last)
+         if (x > threshold)
            break;
 
          fputs (separator, stdout);

Reply via email to