mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-24 10:23:31 +08:00
seq no longer mishandles cases like "seq 0 0.000001 0.000003",
where it would not print the desired last number. * doc/coreutils.texi (seq invocation): Remove advice about workaround for seq off-by-one problem, since the bug is fixed now. Replace it with more-generic advice about rounding errors. * src/seq.c (long_double_format, print_numbers): New arg NUMERIC_FORMAT. All uses changed.
This commit is contained in:
parent
01616c9404
commit
a0304574e9
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2007-06-22 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* NEWS: seq no longer mishandles obvious cases like
|
||||
"seq 0 0.000001 0.000003" by omitting the last output number.
|
||||
* doc/coreutils.texi (seq invocation): Remove advice about workaround
|
||||
for seq off-by-one problem, since the bug is fixed now. Replace
|
||||
it with more-generic advice about rounding errors.
|
||||
* src/seq.c (long_double_format, print_numbers):
|
||||
New arg NUMERIC_FORMAT. All uses changed.
|
||||
|
||||
2007-06-22 Pádraig Brady <P@draigBrady.com> (trivial change)
|
||||
|
||||
* tests/seq/basic: Add test cases for seq off-by-one problem.
|
||||
|
3
NEWS
3
NEWS
@ -48,6 +48,9 @@ GNU coreutils NEWS -*- outline -*-
|
||||
ln=target attribute) would mistakenly output the string "target"
|
||||
before the name of each symlink. [introduced in coreutils-6.0]
|
||||
|
||||
seq no longer mishandles obvious cases like "seq 0 0.000001 0.000003",
|
||||
so workarounds like "seq 0 0.000001 0.0000031" are no longer needed.
|
||||
|
||||
split --line-bytes=N (-C N) no longer creates an empty file
|
||||
[this bug is present at least as far back as textutils-1.22 (Jan, 1997)]
|
||||
|
||||
|
@ -14052,34 +14052,16 @@ $ seq 18446744073709551616 1 18446744073709551618
|
||||
18446744073709551618
|
||||
@end example
|
||||
|
||||
Be careful when using @command{seq} with a fractional @var{increment};
|
||||
otherwise you may see surprising results. Most people would expect to
|
||||
see @code{0.000003} printed as the last number in this example:
|
||||
Be careful when using @command{seq} with outlandish values: otherwise
|
||||
you may see surprising results, as @command{seq} uses floating point
|
||||
internally. For example, on the x86 platform, where the internal
|
||||
representation uses a 64-bit fraction, the command:
|
||||
|
||||
@example
|
||||
$ seq -s ' ' 0 0.000001 0.000003
|
||||
0.000000 0.000001 0.000002
|
||||
seq 1 0.0000000000000000001 1.0000000000000000009
|
||||
@end example
|
||||
|
||||
But that doesn't happen on many systems because @command{seq} is
|
||||
implemented using binary floating point arithmetic (via the C
|
||||
@code{long double} type)---which means decimal fractions like @code{0.000001}
|
||||
cannot be represented exactly. That in turn means some nonintuitive
|
||||
conditions like @w{@code{0.000001 * 3 > 0.000003}} will end up being true.
|
||||
|
||||
To work around that in the above example, use a slightly larger number as
|
||||
the @var{last} value:
|
||||
|
||||
@example
|
||||
$ seq -s ' ' 0 0.000001 0.0000031
|
||||
0.000000 0.000001 0.000002 0.000003
|
||||
@end example
|
||||
|
||||
In general, when using an @var{increment} with a fractional part, where
|
||||
(@var{last} - @var{first}) / @var{increment} is (mathematically) a whole
|
||||
number, specify a slightly larger (or smaller, if @var{increment} is negative)
|
||||
value for @var{last} to ensure that @var{last} is the final value printed
|
||||
by seq.
|
||||
outputs 1.0000000000000000007 twice and skips 1.0000000000000000008.
|
||||
|
||||
@exitstatus
|
||||
|
||||
|
42
src/seq.c
42
src/seq.c
@ -1,5 +1,5 @@
|
||||
/* seq - print sequence of numbers to standard output.
|
||||
Copyright (C) 1994-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 1994-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
|
||||
@ -210,15 +210,53 @@ print_numbers (char const *fmt,
|
||||
long double first, long double step, long double last)
|
||||
{
|
||||
long double i;
|
||||
long double x0 IF_LINT (= 0);
|
||||
|
||||
for (i = 0; /* empty */; i++)
|
||||
{
|
||||
long double x = first + i * step;
|
||||
|
||||
if (step < 0 ? x < last : last < x)
|
||||
break;
|
||||
{
|
||||
/* If we go one past the end, but that number prints the
|
||||
same way "last" does, and prints differently from the
|
||||
previous number, then print "last". This avoids problems
|
||||
with rounding. For example, with the x86 it causes "seq
|
||||
0 0.000001 0.000003" to print 0.000003 instead of
|
||||
stopping at 0.000002. */
|
||||
|
||||
if (i)
|
||||
{
|
||||
char *x_str = NULL;
|
||||
char *last_str = NULL;
|
||||
if (asprintf (&x_str, fmt, x) < 0
|
||||
|| asprintf (&last_str, fmt, last) < 0)
|
||||
xalloc_die ();
|
||||
|
||||
if (STREQ (x_str, last_str))
|
||||
{
|
||||
char *x0_str = NULL;
|
||||
if (asprintf (&x0_str, fmt, x0) < 0)
|
||||
xalloc_die ();
|
||||
if (!STREQ (x0_str, x_str))
|
||||
{
|
||||
fputs (separator, stdout);
|
||||
fputs (x_str, stdout);
|
||||
}
|
||||
free (x0_str);
|
||||
}
|
||||
|
||||
free (x_str);
|
||||
free (last_str);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i)
|
||||
fputs (separator, stdout);
|
||||
printf (fmt, x);
|
||||
x0 = x;
|
||||
}
|
||||
|
||||
if (i)
|
||||
|
Loading…
Reference in New Issue
Block a user