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);