Skip to content

Commit 6290d5a

Browse files
committed
Fix IBig >> by >= bit length on DoubleWord magnitudes
are_dword_low_bits_nonzero capped its bit window at WORD_BITS instead of DWORD_BITS, so any query asking about bits in the upper word lost them. The arithmetic-shift path for negative values then dropped the floor-rounding correction term, returning 0 instead of -1. Concrete failure: IBig::from(i128::MIN) >> 128 returned 0.
1 parent d73e30d commit 6290d5a

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

integer/src/bits.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,13 @@ mod repr {
497497

498498
#[inline]
499499
fn are_dword_low_bits_nonzero(dword: DoubleWord, n: usize) -> bool {
500-
let n = n.min(WORD_BITS_USIZE) as u32;
501-
dword & ones_dword(n) != 0
500+
// For n >= DWORD_BITS, every bit of the dword is "low" so just test for any
501+
// set bit. `ones_dword(DWORD_BITS as u32)` would underflow its shift, so we
502+
// must early-return here rather than rely on it.
503+
if n >= DWORD_BITS_USIZE {
504+
return dword != 0;
505+
}
506+
dword & ones_dword(n as u32) != 0
502507
}
503508

504509
fn are_slice_low_bits_nonzero(words: &[Word], n: usize) -> bool {

integer/tests/shift.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ fn test_ibig_shr() {
198198
((ibig!(-0xff) << 1000) - ibig!(1), 1000, ibig!(-0x100)),
199199
((ibig!(-0xff) << 1000) - (ibig!(1) << 999), 1000, ibig!(-0x100)),
200200
(ibig!(-0xff) << 1000, 2000, ibig!(-1)),
201+
// A negative magnitude whose highest set bit sits in the upper word
202+
// of a DoubleWord, shifted by an amount that equals or exceeds its
203+
// bit length, must round toward -infinity to -1.
204+
(-(ibig!(1) << 127), 128, ibig!(-1)),
205+
(-(ibig!(1) << 127), 200, ibig!(-1)),
206+
(-(ibig!(1) << 64), 128, ibig!(-1)),
201207
];
202208
for (a, b, c) in &test_cases {
203209
assert_eq!(a >> b, *c);

0 commit comments

Comments
 (0)