Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion arbi/src/comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ pub(crate) fn s_cmp_impl(
}
}

#[allow(dead_code)]
pub(crate) fn s_cmp(a: &[Digit], b: &[Digit]) -> Ordering {
s_cmp_impl(a, b, false)
}
Expand All @@ -77,6 +76,18 @@ pub(crate) fn s_cmp_normalized(a: &[Digit], b: &[Digit]) -> Ordering {
s_cmp_impl(a, b, true)
}

#[allow(dead_code)]
pub(crate) fn s_cmp_aligned(a: &[Digit], b: &[Digit]) -> Ordering {
debug_assert_eq!(a.len(), b.len());
for i in (0..a.len()).rev() {
match a[i].cmp(&b[i]) {
Ordering::Equal => continue,
other => return other,
}
}
Ordering::Equal
}

impl Arbi {
// Assumes x, y >= 0
pub(crate) fn cmp_abs(x: &Self, y: &Self) -> Ordering {
Expand Down
6 changes: 3 additions & 3 deletions arbi/src/invert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ mod tests {
while r != 0 {
let quotient = old_r / r;
old_r = old_r - quotient * r;
std::mem::swap(&mut old_r, &mut r);
core::mem::swap(&mut old_r, &mut r);
old_s = old_s - quotient * s;
std::mem::swap(&mut old_s, &mut s);
core::mem::swap(&mut old_s, &mut s);
old_t = old_t - quotient * t;
std::mem::swap(&mut old_t, &mut t);
core::mem::swap(&mut old_t, &mut t);
}
if old_r < 0 {
(-old_r, -old_s, -old_t)
Expand Down
1 change: 0 additions & 1 deletion arbi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ mod is_signed;
mod is_zero;
mod left_shift;
mod macros;
mod multiplication;
mod negate;
mod new;
mod ops;
Expand Down
9 changes: 4 additions & 5 deletions arbi/src/ops/add/arbi_x_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::util::IntoArbiLikeArray;
use crate::Arbi;
use core::ops::{Add, AddAssign, Sub, SubAssign};

/* !impl_bit_with_int */
/* !impl_add_with_int */
macro_rules! impl_add_with_int {
($($int:ty),*) => {
$(
Expand Down Expand Up @@ -98,12 +98,11 @@ impl Sub<&Arbi> for $int {
)*
};
}
/* impl_bit_with_int! */
/* impl_add_with_int! */

for_all_ints!(impl_add_with_int);

// Implements the same combinations as impl_add_with_int but with &i instead of
// i, using the above implementations.
/* !impl_add_with_int_ref */
macro_rules! impl_add_with_int_ref {
($($int:ty),*) => {
$(
Expand Down Expand Up @@ -189,6 +188,6 @@ impl Sub<&Arbi> for &$int {
)*
};
}
/* impl_bit_with_int_ref! */
/* impl_add_with_int_ref! */

for_all_ints!(impl_add_with_int_ref);
125 changes: 120 additions & 5 deletions arbi/src/ops/add/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ pub(crate) fn s_inc(a: &mut [Digit]) -> bool {
}

/// a[0:n] += b, true if overflow
#[allow(dead_code)]
pub(crate) fn s_iadd_digit(a: &mut [Digit], b: Digit) -> bool {
let (first, rest) = match a.split_first_mut() {
Some(s) => s,
Expand Down Expand Up @@ -70,12 +69,71 @@ pub(crate) fn s_iadd(a: &mut [Digit], b: &[Digit]) -> bool {
}
}

/// r[0:n] = a[0:n] + b, returns carry
pub(crate) fn s_add_digit(r: &mut [Digit], a: &[Digit], b: Digit) -> bool {
debug_assert_eq!(r.len(), a.len());
debug_assert!(!a.is_empty());
let mut carry = b;
for (r_digit, &a_digit) in r.iter_mut().zip(a.iter()) {
let sum = a_digit.wrapping_add(carry);
carry = (sum < carry) as Digit;
*r_digit = sum;
}
carry != 0
}

/// r[0:n] = a[0:n] + b[0:n], returns carry
pub(crate) fn s_add_aligned(r: &mut [Digit], a: &[Digit], b: &[Digit]) -> bool {
debug_assert_eq!(r.len(), a.len());
debug_assert_eq!(r.len(), b.len());
let mut carry = 0;
for ((r_digit, &a_digit), &b_digit) in
r.iter_mut().zip(a.iter()).zip(b.iter())
{
let tmp = a_digit.wrapping_add(carry);
carry = (tmp < carry) as Digit;
let sum = tmp.wrapping_add(b_digit);
carry += (sum < b_digit) as Digit;
*r_digit = sum;
}
carry != 0
}

/// r[0:m] = a[0:m] + b[0:n], assumes m >= n, returns carry
#[allow(dead_code)]
pub(crate) fn s_add(r: &mut [Digit], a: &[Digit], b: &[Digit]) -> bool {
debug_assert!(a.len() >= b.len());
debug_assert_eq!(r.len(), a.len());
let carry = s_add_aligned(&mut r[..b.len()], &a[..b.len()], b);
if a.len() > b.len() {
s_add_digit(&mut r[b.len()..], &a[b.len()..], carry as Digit)
} else {
carry
}
}

/// r[0:n] = a[0:n] + b[0:n] + carry_in, returns carry_out
#[allow(dead_code)]
pub(crate) fn s_add_aligned_carry(
r: &mut [Digit],
a: &[Digit],
b: &[Digit],
carry_in: Digit,
) -> Digit {
debug_assert_eq!(r.len(), a.len());
debug_assert_eq!(r.len(), b.len());
debug_assert!(carry_in <= 1, "carry_in must be 0 or 1");
let mut carry = s_add_aligned(r, a, b) as Digit;
carry += s_iadd_digit(r, carry_in) as Digit;
carry
}

/* Low-Level Subtraction Routines */

fn usubb(r: &mut Digit, a: Digit, b: Digit, borrow: &mut bool) {
let temp = a.wrapping_sub(b);
*r = temp.wrapping_sub(*borrow as Digit);
*borrow = *r > temp || temp > a;
let tmp = a.wrapping_sub(b);
*r = tmp.wrapping_sub(*borrow as Digit);
*borrow = *r > tmp || tmp > a;
}

/// a[0:n] -= 1, true if borrow
Expand All @@ -93,7 +151,6 @@ pub(crate) fn s_dec(a: &mut [Digit]) -> bool {
}

/// a[0:n] -= b, true if borrow
#[allow(dead_code)]
pub(crate) fn s_isub_digit(a: &mut [Digit], b: Digit) -> bool {
let (first, rest) = match a.split_first_mut() {
Some(s) => s,
Expand Down Expand Up @@ -133,6 +190,7 @@ pub(crate) fn s_isub_aligned_from_other(a: &mut [Digit], b: &[Digit]) -> bool {
borrow
}

// TODO: rename.
/// Assuming m >= n, a[0:m] -= b[0:n], true if borrow (which implies b > a)
pub(crate) fn s_isub(a: &mut [Digit], b: &[Digit]) -> bool {
assert!(a.len() >= b.len());
Expand All @@ -143,6 +201,63 @@ pub(crate) fn s_isub(a: &mut [Digit], b: &[Digit]) -> bool {
}
}

// r[0:n] = a[0:n] - b, returns borrow
pub(crate) fn s_sub_digit(r: &mut [Digit], a: &[Digit], b: Digit) -> bool {
debug_assert_eq!(r.len(), a.len());
debug_assert!(!a.is_empty());
let mut borrow = b;
for (r_digit, &a_digit) in r.iter_mut().zip(a.iter()) {
let cy = (a_digit < borrow) as Digit;
*r_digit = a_digit.wrapping_sub(borrow);
borrow = cy;
}
borrow != 0
}

/// r[0:n] = a[0:n] - b[0:n], returns borrow
pub(crate) fn s_sub_aligned(r: &mut [Digit], a: &[Digit], b: &[Digit]) -> bool {
debug_assert_eq!(r.len(), a.len());
debug_assert_eq!(r.len(), b.len());
let mut borrow = 0;
for ((r_digit, &a_digit), &b_digit) in
r.iter_mut().zip(a.iter()).zip(b.iter())
{
let tmp = b_digit.wrapping_add(borrow);
borrow = (tmp < borrow) as Digit;
borrow += (a_digit < tmp) as Digit;
*r_digit = a_digit.wrapping_sub(tmp);
}
borrow != 0
}

/// r[0:m] = a[0:m] - b[0:n], assumes m >= n, returns borrow
pub(crate) fn s_sub(r: &mut [Digit], a: &[Digit], b: &[Digit]) -> bool {
debug_assert!(a.len() >= b.len());
debug_assert_eq!(r.len(), a.len());
let borrow = s_sub_aligned(&mut r[..b.len()], &a[..b.len()], b);
if a.len() > b.len() {
s_sub_digit(&mut r[b.len()..], &a[b.len()..], borrow as Digit)
} else {
borrow
}
}

/// r[0:n] = a[0:n] - b[0:n] - borrow_in, returns borrow_out
#[allow(dead_code)]
pub(crate) fn s_sub_aligned_borrow(
r: &mut [Digit],
a: &[Digit],
b: &[Digit],
borrow_in: Digit,
) -> Digit {
debug_assert_eq!(r.len(), a.len());
debug_assert_eq!(r.len(), b.len());
debug_assert!(borrow_in <= 1, "borrow_in must be 0 or 1");
let mut borrow = s_sub_aligned(r, a, b) as Digit;
borrow += s_isub_digit(r, borrow_in) as Digit;
borrow
}

impl Arbi {
/// |self| = |self| + |b|
pub(crate) fn iadd_mag(&mut self, b: &[Digit]) {
Expand Down
2 changes: 1 addition & 1 deletion arbi/src/ops/add/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ SPDX-License-Identifier: Apache-2.0 OR MIT

mod arbi_x_arbi;
mod arbi_x_int;
mod impls;
pub(crate) mod impls;
mod test;
mod util;
2 changes: 2 additions & 0 deletions arbi/src/ops/add/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ Copyright 2024-2025 Owain Davies
SPDX-License-Identifier: Apache-2.0 OR MIT
*/

#[cfg(test)]
use crate::{Arbi, DDigit, Digit};

#[cfg(test)]
impl Arbi {
// A nonnegative integer with n digits in base-B >= 2 has maximum value
// B^{n} - 1.
Expand Down
28 changes: 28 additions & 0 deletions arbi/src/ops/div/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright 2025 Owain Davies
SPDX-License-Identifier: Apache-2.0 OR MIT
*/

use crate::{DDigit, Digit};

#[allow(dead_code)]
pub(crate) fn s_divrem_digit(q: &mut [Digit], u: &[Digit], v: Digit) -> Digit {
let mut rem: DDigit = 0;
for i in (0..u.len()).rev() {
let temp = (rem << Digit::BITS) | u[i] as DDigit;
q[i] = (temp / v as DDigit) as Digit;
rem = temp % v as DDigit;
}
rem as Digit
}

#[allow(dead_code)]
pub(crate) fn s_idivrem_digit(q: &mut [Digit], v: Digit) -> Digit {
let mut rem: DDigit = 0;
for i in (0..q.len()).rev() {
let temp = (rem << Digit::BITS) | q[i] as DDigit;
q[i] = (temp / v as DDigit) as Digit;
rem = temp % v as DDigit;
}
rem as Digit
}
6 changes: 6 additions & 0 deletions arbi/src/ops/div/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
Copyright 2025 Owain Davies
SPDX-License-Identifier: Apache-2.0 OR MIT
*/

pub(crate) mod impls;
4 changes: 4 additions & 0 deletions arbi/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT

mod add;
mod bit;
mod div;
pub(crate) mod mul;
mod shl;
mod shr;
70 changes: 70 additions & 0 deletions arbi/src/ops/mul/arbi_x_arbi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Copyright 2025 Owain Davies
SPDX-License-Identifier: Apache-2.0 OR MIT
*/

use crate::Arbi;
use core::ops::{Mul, MulAssign};

/// `a *= &b`
impl<'a> MulAssign<&'a Arbi> for Arbi {
fn mul_assign(&mut self, other: &'a Arbi) {
self.mul_assign_(other);
}
}

/// `a *= b`
impl MulAssign<Arbi> for Arbi {
fn mul_assign(&mut self, mut other: Arbi) {
if other.capacity() > self.capacity() {
core::mem::swap(self, &mut other);
}
*self *= &other;
}
}

/// `a * b`
impl Mul<Arbi> for Arbi {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
let mut ret = Arbi::zero();
Self::mul_(&mut ret, &self, &other);
ret
// self *= other;
// self
}
}

/// `a * &b`
impl<'a> Mul<&'a Arbi> for Arbi {
type Output = Self;
fn mul(self, other: &'a Arbi) -> Self {
let mut ret = Arbi::zero();
Self::mul_(&mut ret, &self, other);
ret
// self *= other;
// self
}
}

/// `&a * b`
impl Mul<Arbi> for &Arbi {
type Output = Arbi;
fn mul(self, other: Arbi) -> Arbi {
let mut ret = Arbi::zero();
Arbi::mul_(&mut ret, self, &other);
ret
// other *= self;
// other
}
}

/// `&a * &b`
impl<'b> Mul<&'b Arbi> for &Arbi {
type Output = Arbi;
fn mul(self, other: &'b Arbi) -> Self::Output {
let mut ret = Arbi::zero();
Arbi::mul_(&mut ret, self, other);
ret
}
}
Loading
Loading