use rug::Integer;
pub use self::parity::{is_even, is_odd};
pub use self::primes::{
bernoulli, is_prime, next_prime, nth_prime, prev_prime, prime_count, primes_up_to,
};
pub use self::rounding::{
RoundingMode, abs, abs_integer, ceil, floor, round, signum, signum_integer, trunc,
};
pub use self::totient::totient;
pub use self::traits::{Divisors, Gcd, Lcm};
pub mod parity;
pub mod primes;
pub mod rounding;
pub mod totient;
pub mod traits;
pub fn gcd(values: &[&Integer]) -> Integer {
if values.is_empty() {
return Integer::from(0);
}
if values.len() == 1 {
return values[0].clone();
}
let mut result = values[0].clone();
for value in &values[1..] {
result = result.gcd_ref(value).into();
}
result
}
pub fn lcm(values: &[&Integer]) -> Integer {
if values.is_empty() {
return Integer::from(0);
}
if values.len() == 1 {
return values[0].clone();
}
let mut result = values[0].clone();
for value in &values[1..] {
result = result.lcm_ref(value).into();
}
result
}
pub fn frac(numerator: i64, denominator: i64) -> (i64, i64) {
let int_part = numerator / denominator;
let frac_num = numerator - int_part * denominator;
(frac_num, denominator)
}
pub fn rem(a: i64, b: i64) -> i64 {
a % b
}
pub fn modulo(a: i64, b: i64) -> i64 {
((a % b) + b) % b
}
pub fn powmod(base: &Integer, exp: &Integer, modulus: &Integer) -> Integer {
if *exp < 0 {
if base.gcd(modulus) != 1 {
panic!("powmod with negative exponent requires gcd(base, modulus) == 1");
}
let base_inv = base
.clone()
.invert(modulus)
.expect("Modular inverse exists");
let abs_exp = exp.clone().abs();
return base_inv.pow_mod(&abs_exp, modulus).expect("Valid pow_mod");
}
base.pow_mod_ref(exp, modulus)
.expect("pow_mod failed")
.into()
}
pub const fn numerator(numerator: i64, _denominator: i64) -> i64 {
numerator
}
pub const fn denominator(_numerator: i64, denominator: i64) -> i64 {
denominator
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gcd() {
let a = Integer::from(48);
let b = Integer::from(18);
assert_eq!(gcd(&[&a, &b]), 6);
let c = Integer::from(17);
let d = Integer::from(23);
assert_eq!(gcd(&[&c, &d]), 1);
let e = Integer::from(0);
let f = Integer::from(5);
assert_eq!(gcd(&[&e, &f]), 5);
let g = Integer::from(48);
let h = Integer::from(18);
let i = Integer::from(30);
assert_eq!(gcd(&[&g, &h, &i]), 6);
}
#[test]
fn test_lcm() {
let a = Integer::from(21);
let b = Integer::from(6);
assert_eq!(lcm(&[&a, &b]), 42);
let c = Integer::from(5);
let d = Integer::from(7);
assert_eq!(lcm(&[&c, &d]), 35);
let e = Integer::from(4);
let f = Integer::from(6);
let g = Integer::from(8);
assert_eq!(lcm(&[&e, &f, &g]), 24);
}
#[test]
fn test_frac() {
assert_eq!(frac(7, 4), (3, 4));
assert_eq!(frac(-7, 4), (-3, 4));
assert_eq!(frac(8, 4), (0, 4));
}
#[test]
fn test_rem() {
assert_eq!(rem(7, 3), 1);
assert_eq!(rem(-7, 3), -1);
assert_eq!(rem(7, -3), 1);
}
#[test]
fn test_modulo() {
assert_eq!(modulo(7, 3), 1);
assert_eq!(modulo(-7, 3), 2);
assert_eq!(modulo(7, 5), 2);
}
#[test]
fn test_powmod() {
assert_eq!(
powmod(&Integer::from(4), &Integer::from(13), &Integer::from(497)),
445
);
assert_eq!(
powmod(&Integer::from(2), &Integer::from(10), &Integer::from(1000)),
24
);
}
#[test]
fn test_numerator_denominator() {
assert_eq!(numerator(7, 3), 7);
assert_eq!(denominator(7, 3), 3);
assert_eq!(numerator(-7, 3), -7);
assert_eq!(denominator(-7, 3), 3);
}
}