Subject: bug#79369: seq generates wrong sequences for big numbers

From: Pádraig Brady <[email-masked]>
Date: Tue, 2 Sep 2025 16:52:50 +0100

On 02/09/2025 13:11, [email-masked] wrote:
> It looks like seq for integers bigger than 2^64 sometimes generate wrong
> results. There are few examples of wrong output I have found:
> 
> 
> $ seq 18446744073709551617 inf | head -3
> 
> 18446744073709551616
> 18446744073709551617
> 18446744073709551618
> 
> 
> 
> 
> 
> $  seq 10000000000000000000000000000 inf | head -3
> 
> 
> 9999999999999999999731564544
> 9999999999999999999731564545
> 9999999999999999999731564546

We can improve for the above 2 cases anyway,
with something like the attached.

Large magnitude negative start values are still problematic.

cheers,
Padraig

From bf3c75911d1b50d557960943daaeb20a65f0140f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Tue, 2 Sep 2025 16:35:52 +0100
Subject: [PATCH] seq: be more accurate with large integer start values

* src/seq.c (main): Use seq_fast() with large integer only
start values, by avoiding innacurate conversion to double.
* NEWS: Mention the improvement.
---
 NEWS      | 6 +++++-
 src/seq.c | 8 ++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index dd8c1a4cf..e732e3ddd 100644
--- a/NEWS
+++ b/NEWS
@@ -116,11 +116,15 @@ GNU coreutils NEWS                                    -*- outline -*-
 
   tsort now accepts and ignores -w.
 
-** Performance improvements
+** Improvements
 
   'factor' is now much faster at identifying large prime numbers,
   and significantly faster on composite numbers greater than 2^128.
 
+  'seq' is faster and more accurate with large integer start values.
+  Previously 'seq 18446744073709551617 inf | head -n3' would start
+  with the number before the user specified start value.
+
 ** Build-related
 
   cksum was not compilable by Apple LLVM 10.0.0 x86-64, which
diff --git a/src/seq.c b/src/seq.c
index ea9b7d8a4..59de49798 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -628,6 +628,8 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
+  char const *user_start = n_args == 1 ? "1" : argv[optind];
+
   /* If the following hold:
      - no format string, [FIXME: relax this, eventually]
      - integer start (or no start)
@@ -648,7 +650,7 @@ main (int argc, char **argv)
                          && all_digits_p (argv[optind + 2])))
       && !equal_width && !format_str && strlen (separator) == 1)
     {
-      char const *s1 = n_args == 1 ? "1" : argv[optind];
+      char const *s1 = user_start;
       char const *s2 = argv[optind + (n_args - 1)];
       seq_fast (s1, s2, step.value);
     }
@@ -683,7 +685,9 @@ main (int argc, char **argv)
     {
       char *s1;
       char *s2;
-      if (asprintf (&s1, "%0.Lf", first.value) < 0)
+      if (all_digits_p (user_start))
+        s1 = xstrdup (user_start);
+      else if (asprintf (&s1, "%0.Lf", first.value) < 0)
         xalloc_die ();
       if (! isfinite (last.value))
         s2 = xstrdup ("inf"); /* Ensure "inf" is used.  */
-- 
2.50.1