use super::int::BigInt;
use super::uint::BigUint;
use super::{mod_arith, primality};
use oxinum_core::{
FromRadix, ModularArithmetic, OxiNum, OxiNumResult, OxiSigned, OxiUnsigned, Pow, Primality,
Roots, Sign, ToRadix,
};
impl OxiNum for BigUint {
#[inline]
fn is_zero(&self) -> bool {
BigUint::is_zero(self)
}
#[inline]
fn is_one(&self) -> bool {
BigUint::is_one(self)
}
}
impl OxiUnsigned for BigUint {}
impl FromRadix for BigUint {
fn from_radix(src: &str, radix: u32) -> OxiNumResult<Self> {
BigUint::from_str_radix(src, radix)
}
}
impl ToRadix for BigUint {
fn to_radix(&self, radix: u32) -> OxiNumResult<String> {
BigUint::to_radix(self, radix)
}
}
impl Roots for BigUint {
#[inline]
fn sqrt(&self) -> Self {
BigUint::sqrt(self)
}
#[inline]
fn cbrt(&self) -> Self {
BigUint::nth_root(self, 3).expect("cbrt: n=3 is always valid")
}
#[inline]
fn nth_root(&self, n: u32) -> Self {
BigUint::nth_root(self, n).expect("nth_root: n must be >= 1")
}
}
impl Pow<u32> for BigUint {
type Output = BigUint;
#[inline]
fn pow(&self, exp: u32) -> BigUint {
BigUint::pow(self, exp)
}
}
impl ModularArithmetic for BigUint {
fn mod_add(&self, rhs: &Self, modulus: &Self) -> Self {
assert!(!modulus.is_zero(), "mod_add: modulus must be non-zero");
let sum = self + rhs;
&sum % modulus
}
fn mod_sub(&self, rhs: &Self, modulus: &Self) -> Self {
assert!(!modulus.is_zero(), "mod_sub: modulus must be non-zero");
if self >= rhs {
let diff = self - rhs;
diff % modulus
} else {
let diff = rhs - self;
let r = diff % modulus;
if r.is_zero() {
BigUint::ZERO
} else {
modulus - &r
}
}
}
fn mod_mul(&self, rhs: &Self, modulus: &Self) -> Self {
mod_arith::mod_mul(self, rhs, modulus).expect("mod_mul: modulus must be non-zero")
}
fn mod_pow(&self, exp: &Self, modulus: &Self) -> Self {
mod_arith::mod_pow(self, exp, modulus).expect("mod_pow: modulus must be non-zero")
}
}
impl Primality for BigUint {
fn is_probably_prime(&self, _witnesses: u32) -> bool {
primality::is_probably_prime(self)
}
fn next_prime(&self) -> Self {
if self.is_zero() || self.is_one() {
return BigUint::from_u64(2);
}
let one = BigUint::from_u64(1);
let two = BigUint::from_u64(2);
let mut candidate = self + &one;
if !candidate.test_bit(0) {
candidate += &one;
}
loop {
if primality::is_probably_prime(&candidate) {
return candidate;
}
candidate += &two;
}
}
}
impl OxiNum for BigInt {
#[inline]
fn is_zero(&self) -> bool {
BigInt::is_zero(self)
}
#[inline]
fn is_one(&self) -> bool {
BigInt::is_one(self)
}
}
impl OxiSigned for BigInt {
#[inline]
fn signum(&self) -> Sign {
BigInt::signum(self)
}
#[inline]
fn abs(&self) -> Self {
BigInt::abs(self)
}
}
impl FromRadix for BigInt {
fn from_radix(src: &str, radix: u32) -> OxiNumResult<Self> {
let (negative, digits) = match src.strip_prefix('-') {
Some(rest) => (true, rest),
None => (false, src),
};
let mag = BigUint::from_str_radix(digits, radix)?;
let sign = if negative && !mag.is_zero() {
Sign::Negative
} else {
Sign::Positive
};
Ok(BigInt::from_parts(sign, mag))
}
}
impl ToRadix for BigInt {
fn to_radix(&self, radix: u32) -> OxiNumResult<String> {
let mag_str = self.magnitude().to_radix(radix)?;
if self.is_negative() {
Ok(format!("-{mag_str}"))
} else {
Ok(mag_str)
}
}
}
impl Pow<u32> for BigInt {
type Output = BigInt;
fn pow(&self, exp: u32) -> BigInt {
let mag = BigUint::pow(self.magnitude(), exp);
let sign = if self.is_negative() && exp % 2 == 1 {
Sign::Negative
} else {
Sign::Positive
};
BigInt::from_parts(sign, mag)
}
}