Skip to content

perf(assert): compare assert_within_delta in fixed point, not via bc - #979

Merged
Chemaclass merged 2 commits into
mainfrom
perf/fixed-point-numeric-comparison
Aug 7, 2026
Merged

perf(assert): compare assert_within_delta in fixed point, not via bc#979
Chemaclass merged 2 commits into
mainfrom
perf/fixed-point-numeric-comparison

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

assert_within_delta called bashunit::math::calculate twice, and each call is a subshell wrapping a bc (or awk) process — four forks per assertion, on a per-assertion path.

before after
assert_within_delta ×200 1092 ms 165 ms
fork-free floor 108 ms 108 ms

💡 Changes

The comparison is |expected - actual| <= delta, which needs no floating point at all. All three operands are padded to one decimal scale and compared as integers, in pure bash.

The fast path is deliberately narrow and refuses what it cannot represent exactly — exponent notation, a sign anywhere but the front, or enough digits to risk 64-bit overflow — so those fall through to the existing bc/awk chain rather than getting a quietly wrong answer.

bashunit::math::is_le gets the same fast path; it had the identical bc > awk > strip-decimals chain for the same reason.

🐛 Also fixes a bug, rather than moving it

_is_numeric accepts a leading +, but bc cannot parse one: +5 - 5 returned an empty string, which compared unequal to "1", so assert_within_delta +5 5 1 failed. The sign is now stripped once before either path — so the fallback is fixed too, not just bypassed.

✅ How agreement was verified

Forcing the fixed-point path to always refuse leaves the entire numeric suite green on the bc/awk path. That's the check that the two paths agree, rather than just that the new one passes.

Slots rather than echoes for the three helpers — not stylistic: the caller needs the decimal count three times per assertion, and three $( ) captures would cost more than the two bc forks this change exists to remove.

🔒 Verification

Bash 3.0 safe — parameter expansion, case and integer arithmetic only; compat gate green (14/14). Fork budgets unchanged. make sa · make lint · bash build.sh bin -v✅ Build verified ✅ · 1661 sequential / 1620 parallel-simple-strict.

assert_within_delta called bashunit::math::calculate twice, and each call is a
subshell wrapping a `bc` (or `awk`) process. Four forks per assertion on a
per-assertion path: 200 calls took 1092ms where the fork-free floor is ~108ms.
They now take 165ms.

The comparison is |expected - actual| <= delta, which needs no floating point at
all. All three operands are padded to one decimal scale and compared as
integers, in pure bash.

The fast path is deliberately narrow and refuses what it cannot represent
exactly -- exponent notation, a sign anywhere but the front, or enough digits to
risk 64-bit overflow -- so those fall through to the existing bc/awk chain
rather than getting a quietly wrong answer. Both paths were run against the full
numeric suite: forcing the fixed-point path to always refuse leaves every test
green, which is the check that they agree.

This also fixes a bug rather than only moving it. _is_numeric accepts a leading
`+`, but bc cannot parse one: `+5 - 5` returned an empty string, which compared
unequal to "1", so `assert_within_delta +5 5 1` failed. The sign is now stripped
once before either path, so the fallback is fixed too and not just bypassed.

bashunit::math::is_le gets the same fast path; it had the identical bc > awk >
strip-decimals chain for the same reason.

The three helpers return through slots rather than echoing. That is not
stylistic here: the caller needs the decimal count three times per assertion,
and three `$( )` captures would cost more than the two bc forks the whole change
exists to remove.

Bash 3.0 safe: parameter expansion, `case` and integer arithmetic only. Fork
budgets unchanged; compat gate green; 1661 sequential / 1620 parallel.
@Chemaclass Chemaclass added the enhancement New feature or request label Aug 6, 2026
@Chemaclass Chemaclass self-assigned this Aug 6, 2026
@Chemaclass

Copy link
Copy Markdown
Member Author

Reopening to re-trigger CI; no pull_request runs were created.

@Chemaclass Chemaclass closed this Aug 6, 2026
@Chemaclass Chemaclass reopened this Aug 6, 2026
@Chemaclass
Chemaclass force-pushed the perf/fixed-point-numeric-comparison branch from bc0e872 to 9608465 Compare August 6, 2026 19:54
@Chemaclass
Chemaclass merged commit 5b31658 into main Aug 7, 2026
37 checks passed
@Chemaclass
Chemaclass deleted the perf/fixed-point-numeric-comparison branch August 7, 2026 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant