use crate::int::types::Int;
#[inline]
fn mag_u128<const N: usize>(x: &Int<N>) -> u128 {
let limbs = x.unsigned_abs();
let l = limbs.as_limbs();
let lo = l[0] as u128;
let hi = if N >= 2 { l[1] as u128 } else { 0 };
lo | (hi << 64)
}
#[inline]
pub(crate) fn rem_native<const N: usize>(a: Int<N>, b: Int<N>) -> Int<N> {
assert!(
!b.is_zero(),
"attempt to calculate the remainder with a divisor of zero"
);
let neg_r = a.is_negative();
let r = mag_u128(&a) % mag_u128(&b);
let mut rem = [0u64; N];
rem[0] = r as u64;
if N >= 2 {
rem[1] = (r >> 64) as u64;
}
Int::<N>::from_mag_limbs(&rem, neg_r)
}
#[cfg(test)]
mod tests {
use super::rem_native;
use crate::int::types::Int;
#[test]
fn rem_native_known_values_n1() {
let cases: &[(i64, i64, i64)] = &[
(10, 3, 1),
(-10, 3, -1),
(10, -3, 1),
(-10, -3, -1),
(0, 7, 0),
(7, 7, 0),
(8, 7, 1),
(100, 13, 9),
(i64::MAX, 2, 1),
(i64::MIN + 1, 2, -1),
];
for &(a, b, want) in cases {
let got = rem_native::<1>(Int::<1>::from_i64(a), Int::<1>::from_i64(b));
assert_eq!(got.to_i64(), want, "rem_native({a}, {b})");
}
}
#[test]
fn rem_native_matches_rem_operator_n2() {
let cases: &[(i128, i128)] = &[
(0, 1),
(1, 1),
(-1, 1),
(100, 7),
(-100, 7),
(100, -7),
(-100, -7),
(i128::MAX, 3),
(i128::MIN + 1, 3),
(i128::MAX, i128::MAX - 1),
(1_000_000_000_000_i128, 999_999_937),
(0x0001_0000_0000_0000_0000_i128, 0xFFFF),
(
170_141_183_460_469_231_731_687_303_715_884_105_727_i128,
12345678901234567,
),
];
for &(a, b) in cases {
let got = rem_native::<2>(Int::<2>::from_i128(a), Int::<2>::from_i128(b));
assert_eq!(got.to_i128(), a % b, "rem_native({a}, {b})");
}
}
}