Skip to content

arrow-buffer: i256: fix ilog off-by-one when self == base - #1

Merged
theirix merged 2 commits into
theirix:i256-powfrom
alamb:alamb/i256-ilog-fix
Jun 2, 2026
Merged

arrow-buffer: i256: fix ilog off-by-one when self == base#1
theirix merged 2 commits into
theirix:i256-powfrom
alamb:alamb/i256-ilog-fix

Conversation

@alamb

@alamb alamb commented Jun 2, 2026

Copy link
Copy Markdown

Rationale for this change

Builds on apache#9453. While reviewing that PR, I found that i256::checked_ilog (and therefore ilog/checked_ilog2/ilog2) returns 0 instead of 1 when self == base.

What changes are included in this PR?

Are these changes tested?

Yes — see the first commit. The added assertions fail before the fix and pass after.

Are there any user-facing changes?

Fixes incorrect results from i256::ilog/checked_ilog/ilog2/checked_ilog2 when self == base. No API changes.

alamb and others added 2 commits June 2, 2026 13:34
Extends the existing `test_ilog` with cases that the current tests do
not cover: small results (0 and 1) for non-base-10 bases, including
`self == base`. Per the std contract `n.ilog(n) == 1` (e.g.
`2u32.ilog(2) == 1`), but `i256::checked_ilog` currently returns 0 for
these inputs. Also cross-checks small results against `u128::ilog` as
ground truth.

These tests fail until the following fix is applied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`checked_ilog` returned the early `Some(0)` for `self == base`, but the
correct result is 1 (`base^1 == base <= self`), matching the std
contract `n.ilog(n) == 1`. The base-10 path was unaffected since it is
handled by `checked_ilog10`, so this affected every other base
(including `ilog2(2)`).

Narrow the early return from `self <= base` to `self < base`; the loop
already computes the correct value for `self == base`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the arrow label Jun 2, 2026
assert_eq!(i256::ZERO.checked_ilog2(), None);

// self == base, matches std: `n.ilog(n) == 1`
assert_eq!(i256::from(2).checked_ilog(i256::from(2)), Some(1));

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these tests fail without the code change

@theirix
theirix marked this pull request as ready for review June 2, 2026 18:02
@theirix
theirix merged commit eacba96 into theirix:i256-pow Jun 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants