uutils / uutils/coreutils

seq -w: positive exponents in scientific-notation operands produce wrong padding width (leading zero not cancelled)

Open Beginner friendly
#14,153 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

U - seq
Dominant language
Rust
Stars
24.1k
Forks
2k
Avg merge
1d 5h
Merged PRs (30d)
365

Description

Summary

compute_num_digits in src/uu/seq/src/numberparse.rs counts integral digits of an operand, then adds a positive decimal exponent to that count. When the mantissa has a leading 0 (the .X / -0.X special case), shifting the decimal point past that zero annihilates it, but the code still keeps the counted digit and adds the exponent on top. The inflated integral-digit count makes seq -w pad output one character wider than the widest rendered value.

Static-analysis finding based on reading main; not executed here.

Location

  • File: src/uu/seq/src/numberparse.rs
  • Function: compute_num_digits
  • Relevant code:
let (mut int_digits, mut frac_digits) = match parts[0].find('.') {
    Some(i) => {
        // Cover special case .X and -.X where we behave as if there was a leading 0:
        // 0.X, -0.X.
        let int_digits = match i {
            0 => 1,
            1 if parts[0].starts_with('-') => 2,
            _ => i,
        };
        (int_digits, parts[0].len() - i - 1)
    }
    None => (parts[0].len(), 0),
};
...
if exp > 0 {
    int_digits += exp.try_into().unwrap_or(0);
}

Problem

For the operand "0.5e1" (value 5):

  1. find('.') -> i = 1; the special case yields int_digits = 1 (the counted leading 0) and frac_digits = 1.
  2. exp = 1 > 0 -> int_digits += 1 -> 2.
  3. But 0.5e1 == 5, whose rendered form "5" has exactly 1 integral digit: shifting the point past the leading zero removes that zero (05e1 would be 5, not 05). The correct count is therefore max(1, i + exp - 1)-style logic that first cancels the pad digit; instead both are summed.
  4. Downstream, seq -w 0.5e1 0.5e1 derives padding = max(integral digits) = 2 and prints 05.

The file's own tests encode the same over-count (e.g. -0.1e2 expected to contribute width 4, while -10 renders as 3 characters).

Trigger / Reproduction

Based on source reading:

$ seq -w 0.5e1 0.5e1
05          # actual
5           # expected

Same class: .5e2, -0.1e2, any operand whose mantissa starts with 0/. and whose exponent is at least the number of fractional digits.

Expected Behavior

The equal-width padding should equal the width of the widest actually-rendered value among all sequence elements - here 5, so no padding.

Actual Behavior

Padding is computed from an inflated digit count that double-counts the special-cased leading zero once the exponent moves past it, producing spurious leading zeros / overwide fields.

Impact

Wrong textual output for documented input syntax (scientific notation is accepted by seq's parser). Cosmetic rather than data-destructive, but deterministic and visible in scripts relying on fixed-width columns.

Suggested Direction

When i corresponds to the leading-zero special case, subtract the consumed pad digit from int_digits before applying a positive exponent (or compute the integer-part width from the normalized value mantissa * 10^exp directly).

Evidence

  • Lines 60-66 explicitly count the synthesized leading zero as an integral digit.
  • Lines 77-78 add the exponent unconditionally for exp > 0; there is no interaction between the two adjustments anywhere in the function.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/uu/seq/src/numberparse.rs at compute_num_digits and inspect the existing tests for scientific-notation operands. Run the seq tests and reproduce seq -w 0.5e1 0.5e1, then verify that leading-zero cases such as .5e2 and -0.1e2 no longer produce wider-than-needed output.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.