use Assign;
use ext::gmp as xgmp;
use inner::{Inner, InnerMut};
use ops::{AddFrom, BitAndFrom, BitOrFrom, BitXorFrom, DivFrom, MulFrom,
NegAssign, NotAssign, Pow, PowAssign, RemFrom, SubFrom};
#[cfg(feature = "rand")]
use rand::RandState;
use gmp_mpfr_sys::gmp::{self, mpz_t};
use std::{i32, u32};
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Binary, Debug, Display, Formatter, LowerHex, Octal,
UpperHex};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign,
BitXor, BitXorAssign, Deref, Div, DivAssign, Mul, MulAssign,
Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
SubAssign};
use std::os::raw::{c_char, c_int, c_long, c_ulong};
use std::slice;
use std::str::FromStr;
pub struct Integer {
inner: mpz_t,
}
impl Default for Integer {
#[inline]
fn default() -> Integer {
Integer::new()
}
}
impl Clone for Integer {
#[inline]
fn clone(&self) -> Integer {
let mut ret = Integer::new();
ret.assign(self);
ret
}
#[inline]
fn clone_from(&mut self, source: &Integer) {
self.assign(source);
}
}
impl Drop for Integer {
#[inline]
fn drop(&mut self) {
unsafe {
gmp::mpz_clear(self.inner_mut());
}
}
}
impl Hash for Integer {
fn hash<H: Hasher>(&self, state: &mut H) {
let size = self.inner().size;
size.hash(state);
if size != 0 {
let limbs = size.checked_abs().expect("overflow") as usize;
let slice = unsafe { slice::from_raw_parts(self.inner().d, limbs) };
slice.hash(state);
}
}
}
impl Integer {
#[inline]
pub fn new() -> Integer {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init(ret.inner_mut());
ret
}
}
#[inline]
pub fn with_capacity(bits: usize) -> Integer {
assert_eq!(bits as gmp::bitcnt_t as usize, bits, "overflow");
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init2(ret.inner_mut(), bits as gmp::bitcnt_t);
ret
}
}
#[inline]
pub fn capacity(&self) -> usize {
let limbs = self.inner().alloc;
let bits = limbs as usize * gmp::LIMB_BITS as usize;
assert_eq!(
limbs,
(bits / gmp::LIMB_BITS as usize) as c_int,
"overflow"
);
bits
}
pub fn reserve(&mut self, additional: usize) {
if additional == 0 {
return;
}
let used_bits = if self.inner().size == 0 {
0
} else {
unsafe { gmp::mpz_sizeinbase(self.inner(), 2) }
};
let req_bits = used_bits.checked_add(additional).expect("overflow");
assert_eq!(req_bits as gmp::bitcnt_t as usize, req_bits, "overflow");
unsafe {
gmp::mpz_realloc2(self.inner_mut(), req_bits as gmp::bitcnt_t);
}
}
pub fn shrink_to_fit(&mut self) {
let used_bits = unsafe { gmp::mpz_sizeinbase(self.inner(), 2) };
assert_eq!(used_bits as gmp::bitcnt_t as usize, used_bits, "overflow");
unsafe {
gmp::mpz_realloc2(self.inner_mut(), used_bits as gmp::bitcnt_t);
}
}
#[inline]
pub fn from_f32(val: f32) -> Option<Integer> {
Integer::from_f64(val as f64)
}
#[inline]
pub fn from_f64(val: f64) -> Option<Integer> {
if val.is_finite() {
unsafe {
let mut i: Integer = mem::uninitialized();
gmp::mpz_init_set_d(i.inner_mut(), val);
Some(i)
}
} else {
None
}
}
#[inline]
pub fn from_str_radix(
src: &str,
radix: i32,
) -> Result<Integer, ParseIntegerError> {
let mut i = Integer::new();
i.assign_str_radix(src, radix)?;
Ok(i)
}
pub fn valid_str_radix(
src: &str,
radix: i32,
) -> Result<ValidInteger, ParseIntegerError> {
use self::ParseIntegerError as Error;
use self::ParseErrorKind as Kind;
assert!(radix >= 2 && radix <= 36, "radix out of range");
let bytes = src.as_bytes();
let (skip_plus, iter) = match bytes.get(0) {
Some(&b'+') => (&bytes[1..], bytes[1..].iter()),
Some(&b'-') => (bytes, bytes[1..].iter()),
_ => (bytes, bytes.iter()),
};
let mut got_digit = false;
for b in iter {
let digit_value = match *b {
b'0'...b'9' => *b - b'0',
b'a'...b'z' => *b - b'a' + 10,
b'A'...b'Z' => *b - b'A' + 10,
_ => {
return Err(Error {
kind: Kind::InvalidDigit,
})
}
};
if digit_value >= radix as u8 {
return Err(Error {
kind: Kind::InvalidDigit,
});
}
got_digit = true;
}
if !got_digit {
return Err(Error {
kind: Kind::NoDigits,
});
}
let v = ValidInteger {
bytes: skip_plus,
radix,
};
Ok(v)
}
#[inline]
pub fn to_i32(&self) -> Option<i32> {
if unsafe { xgmp::mpz_fits_i32(self.inner()) } {
Some(self.to_i32_wrapping())
} else {
None
}
}
#[inline]
pub fn to_i64(&self) -> Option<i64> {
if unsafe { xgmp::mpz_fits_i64(self.inner()) } {
Some(self.to_i64_wrapping())
} else {
None
}
}
#[inline]
pub fn to_u32(&self) -> Option<u32> {
if unsafe { xgmp::mpz_fits_u32(self.inner()) } {
Some(self.to_u32_wrapping())
} else {
None
}
}
#[inline]
pub fn to_u64(&self) -> Option<u64> {
if unsafe { xgmp::mpz_fits_u64(self.inner()) } {
Some(self.to_u64_wrapping())
} else {
None
}
}
#[inline]
pub fn to_i32_wrapping(&self) -> i32 {
self.to_u32_wrapping() as i32
}
#[inline]
pub fn to_i64_wrapping(&self) -> i64 {
self.to_u64_wrapping() as i64
}
#[inline]
pub fn to_u32_wrapping(&self) -> u32 {
let u = unsafe { xgmp::mpz_get_abs_u32(self.inner()) };
if self.sign() == Ordering::Less {
u.wrapping_neg()
} else {
u
}
}
#[inline]
pub fn to_u64_wrapping(&self) -> u64 {
let u = unsafe { xgmp::mpz_get_abs_u64(self.inner()) };
if self.sign() == Ordering::Less {
u.wrapping_neg()
} else {
u
}
}
#[inline]
pub fn to_f32(&self) -> f32 {
trunc_f64_to_f32(self.to_f64())
}
#[inline]
pub fn to_f64(&self) -> f64 {
unsafe { gmp::mpz_get_d(self.inner()) }
}
#[inline]
pub fn to_f32_exp(&self) -> (f32, u32) {
let (f, exp) = self.to_f64_exp();
let trunc_f = trunc_f64_to_f32(f);
(trunc_f, exp)
}
#[inline]
pub fn to_f64_exp(&self) -> (f64, u32) {
let mut exp: c_long = 0;
let f = unsafe { gmp::mpz_get_d_2exp(&mut exp, self.inner()) };
assert_eq!(exp as u32 as c_long, exp, "overflow");
(f, exp as u32)
}
#[inline]
pub fn to_string_radix(&self, radix: i32) -> String {
make_string(self, radix, false)
}
#[inline]
pub fn assign_f32(&mut self, val: f32) -> Result<(), ()> {
self.assign_f64(val as f64)
}
#[inline]
pub fn assign_f64(&mut self, val: f64) -> Result<(), ()> {
if val.is_finite() {
unsafe {
gmp::mpz_set_d(self.inner_mut(), val);
}
Ok(())
} else {
Err(())
}
}
#[inline]
pub fn assign_str(&mut self, src: &str) -> Result<(), ParseIntegerError> {
self.assign_str_radix(src, 10)
}
#[inline]
pub fn assign_str_radix(
&mut self,
src: &str,
radix: i32,
) -> Result<(), ParseIntegerError> {
self.assign(Integer::valid_str_radix(src, radix)?);
Ok(())
}
#[inline]
pub fn as_neg(&self) -> BorrowInteger {
let mut ret = BorrowInteger {
inner: self.inner,
phantom: PhantomData,
};
ret.inner.size = self.inner.size.checked_neg().expect("overflow");
ret
}
#[inline]
pub fn as_abs(&self) -> BorrowInteger {
let mut ret = BorrowInteger {
inner: self.inner,
phantom: PhantomData,
};
ret.inner.size = self.inner.size.checked_abs().expect("overflow");
ret
}
#[inline]
pub fn is_even(&self) -> bool {
unsafe { gmp::mpz_even_p(self.inner()) != 0 }
}
#[inline]
pub fn is_odd(&self) -> bool {
unsafe { gmp::mpz_odd_p(self.inner()) != 0 }
}
#[inline]
pub fn is_divisible(&self, divisor: &Integer) -> bool {
unsafe { gmp::mpz_divisible_p(self.inner(), divisor.inner()) != 0 }
}
#[inline]
pub fn is_divisible_u(&self, divisor: u32) -> bool {
unsafe { gmp::mpz_divisible_ui_p(self.inner(), divisor.into()) != 0 }
}
#[inline]
pub fn is_divisible_2pow(&self, b: u32) -> bool {
unsafe { gmp::mpz_divisible_2exp_p(self.inner(), b.into()) != 0 }
}
#[inline]
pub fn is_congruent(&self, c: &Integer, divisor: &Integer) -> bool {
unsafe {
gmp::mpz_congruent_p(self.inner(), c.inner(), divisor.inner()) != 0
}
}
#[inline]
pub fn is_congruent_u(&self, c: u32, divisor: u32) -> bool {
unsafe {
gmp::mpz_congruent_ui_p(self.inner(), c.into(), divisor.into()) != 0
}
}
#[inline]
pub fn is_congruent_2pow(&self, c: &Integer, b: u32) -> bool {
unsafe {
gmp::mpz_congruent_2exp_p(self.inner(), c.inner(), b.into()) != 0
}
}
#[inline]
pub fn is_perfect_power(&self) -> bool {
unsafe { gmp::mpz_perfect_power_p(self.inner()) != 0 }
}
#[inline]
pub fn is_perfect_square(&self) -> bool {
unsafe { gmp::mpz_perfect_square_p(self.inner()) != 0 }
}
#[inline]
pub fn sign(&self) -> Ordering {
unsafe { gmp::mpz_sgn(self.inner()).cmp(&0) }
}
#[inline]
pub fn cmp_abs(&self, other: &Integer) -> Ordering {
unsafe { gmp::mpz_cmpabs(self.inner(), other.inner()).cmp(&0) }
}
#[inline]
pub fn significant_bits(&self) -> u32 {
let bits = unsafe { gmp::mpz_sizeinbase(self.inner(), 2) };
if bits > u32::MAX as usize {
panic!("overflow");
}
if bits == 1 && *self == 0 {
0
} else {
bits as u32
}
}
#[inline]
pub fn count_ones(&self) -> Option<u32> {
bitcount_to_u32(unsafe { gmp::mpz_popcount(self.inner()) })
}
#[inline]
pub fn count_zeros(&self) -> Option<u32> {
bitcount_to_u32(unsafe { xgmp::mpz_zerocount(self.inner()) })
}
#[inline]
pub fn find_zero(&self, start: u32) -> Option<u32> {
bitcount_to_u32(unsafe { gmp::mpz_scan0(self.inner(), start.into()) })
}
#[inline]
pub fn find_one(&self, start: u32) -> Option<u32> {
bitcount_to_u32(unsafe { gmp::mpz_scan1(self.inner(), start.into()) })
}
#[inline]
pub fn set_bit(&mut self, index: u32, val: bool) -> &mut Integer {
unsafe {
if val {
gmp::mpz_setbit(self.inner_mut(), index.into());
} else {
gmp::mpz_clrbit(self.inner_mut(), index.into());
}
}
self
}
#[inline]
pub fn get_bit(&self, index: u32) -> bool {
unsafe { gmp::mpz_tstbit(self.inner(), index.into()) != 0 }
}
#[inline]
pub fn toggle_bit(&mut self, index: u32) -> &mut Integer {
unsafe {
gmp::mpz_combit(self.inner_mut(), index.into());
}
self
}
#[inline]
pub fn hamming_dist(&self, other: &Integer) -> Option<u32> {
bitcount_to_u32(
unsafe { gmp::mpz_hamdist(self.inner(), other.inner()) },
)
}
math_op1! {
Integer;
gmp::mpz_abs;
fn abs();
fn abs_mut;
fn abs_ref -> AbsRef;
}
math_op1! {
Integer;
gmp::mpz_fdiv_r_2exp;
fn keep_bits(n: u32);
fn keep_bits_mut;
fn keep_bits_ref -> KeepBitsRef;
}
math_op1! {
Integer;
xgmp::mpz_next_pow_of_two;
fn next_power_of_two();
fn next_power_of_two_mut;
fn next_power_of_two_ref -> NextPowerTwoRef;
}
math_op2_2! {
Integer;
xgmp::mpz_tdiv_qr_check_0;
fn div_rem(divisor);
fn div_rem_mut;
fn div_rem_ref -> DivRemRef;
}
math_op2! {
Integer;
xgmp::mpz_divexact_check_0;
fn div_exact(divisor);
fn div_exact_mut;
fn div_exact_ref -> DivExactRef;
}
math_op1! {
Integer;
xgmp::mpz_divexact_ui_check_0;
fn div_exact_u(divisor: u32);
fn div_exact_u_mut;
fn div_exact_u_ref -> DivExactURef;
}
#[inline]
pub fn invert(mut self, modulo: &Integer) -> Result<Integer, Integer> {
if self.invert_mut(modulo) {
Ok(self)
} else {
Err(self)
}
}
#[inline]
pub fn invert_mut(&mut self, modulo: &Integer) -> bool {
unsafe {
xgmp::mpz_invert_check_0(
self.inner_mut(),
self.inner(),
modulo.inner(),
) != 0
}
}
#[inline]
pub fn invert_ref<'a>(&'a self, modulo: &'a Integer) -> InvertRef<'a> {
InvertRef {
ref_self: self,
modulo,
}
}
#[inline]
pub fn pow_mod(
mut self,
power: &Integer,
modulo: &Integer,
) -> Result<Integer, Integer> {
if self.pow_mod_mut(power, modulo) {
Ok(self)
} else {
Err(self)
}
}
pub fn pow_mod_mut(&mut self, power: &Integer, modulo: &Integer) -> bool {
let abs_pow;
let pow_inner = if power.sign() == Ordering::Less {
if !(self.invert_mut(modulo)) {
return false;
}
abs_pow = power.as_neg();
abs_pow.inner()
} else {
power.inner()
};
unsafe {
gmp::mpz_powm(
self.inner_mut(),
self.inner(),
pow_inner,
modulo.inner(),
);
}
true
}
#[inline]
pub fn pow_mod_ref<'a>(
&'a self,
power: &'a Integer,
modulo: &'a Integer,
) -> PowModRef<'a> {
PowModRef {
ref_self: self,
power,
modulo,
}
}
#[inline]
pub fn assign_u_pow_u(&mut self, base: u32, power: u32) {
unsafe {
gmp::mpz_ui_pow_ui(self.inner_mut(), base.into(), power.into());
}
}
#[inline]
pub fn assign_i_pow_u(&mut self, base: i32, power: u32) {
if base >= 0 {
self.assign_u_pow_u(base as u32, power);
} else {
self.assign_u_pow_u(base.wrapping_neg() as u32, power);
if (power & 1) == 1 {
self.neg_assign();
}
}
}
math_op1! {
Integer;
gmp::mpz_root;
fn root(n: u32);
fn root_mut;
fn root_ref -> RootRef;
}
math_op1_2! {
Integer;
gmp::mpz_rootrem;
fn root_rem(remainder, n: u32);
fn root_rem_mut;
fn root_rem_ref -> RootRemRef;
}
math_op1! {
Integer;
gmp::mpz_sqrt;
fn sqrt();
fn sqrt_mut;
fn sqrt_ref -> SqrtRef;
}
math_op1_2! {
Integer;
gmp::mpz_sqrtrem;
fn sqrt_rem(remainder);
fn sqrt_rem_mut;
fn sqrt_rem_ref -> SqrtRemRef;
}
#[inline]
pub fn is_probably_prime(&self, reps: u32) -> IsPrime {
let p = unsafe { gmp::mpz_probab_prime_p(self.inner(), reps as c_int) };
match p {
0 => IsPrime::No,
1 => IsPrime::Probably,
2 => IsPrime::Yes,
_ => unreachable!(),
}
}
math_op1! {
Integer;
gmp::mpz_nextprime;
fn next_prime();
fn next_prime_mut;
fn next_prime_ref -> NextPrimeRef;
}
math_op2! {
Integer;
gmp::mpz_gcd;
fn gcd(other);
fn gcd_mut;
fn gcd_ref -> GcdRef;
}
math_op2! {
Integer;
gmp::mpz_lcm;
fn lcm(other);
fn lcm_mut;
fn lcm_ref -> LcmRef;
}
#[inline]
pub fn jacobi(&self, n: &Integer) -> i32 {
unsafe { gmp::mpz_jacobi(self.inner(), n.inner()) as i32 }
}
#[inline]
pub fn legendre(&self, p: &Integer) -> i32 {
unsafe { gmp::mpz_legendre(self.inner(), p.inner()) as i32 }
}
#[inline]
pub fn kronecker(&self, n: &Integer) -> i32 {
unsafe { gmp::mpz_kronecker(self.inner(), n.inner()) as i32 }
}
#[inline]
pub fn remove_factor(mut self, factor: &Integer) -> (Integer, u32) {
let count = self.remove_factor_mut(factor);
(self, count)
}
#[inline]
pub fn remove_factor_mut(&mut self, factor: &Integer) -> u32 {
let cnt = unsafe {
gmp::mpz_remove(self.inner_mut(), self.inner(), factor.inner())
};
assert_eq!(cnt as u32 as gmp::bitcnt_t, cnt, "overflow");
cnt as u32
}
#[inline]
pub fn remove_factor_ref<'a>(
&'a self,
factor: &'a Integer,
) -> RemoveFactorRef<'a> {
RemoveFactorRef {
ref_self: self,
factor,
}
}
#[inline]
pub fn assign_factorial(&mut self, n: u32) {
unsafe {
gmp::mpz_fac_ui(self.inner_mut(), n.into());
}
}
#[inline]
pub fn assign_factorial_2(&mut self, n: u32) {
unsafe {
gmp::mpz_2fac_ui(self.inner_mut(), n.into());
}
}
#[inline]
pub fn assign_factorial_m(&mut self, n: u32, m: u32) {
unsafe {
gmp::mpz_mfac_uiui(self.inner_mut(), n.into(), m.into());
}
}
#[inline]
pub fn assign_primorial(&mut self, n: u32) {
unsafe {
gmp::mpz_primorial_ui(self.inner_mut(), n.into());
}
}
math_op1! {
Integer;
gmp::mpz_bin_ui;
fn binomial(k: u32);
fn binomial_mut;
fn binomial_ref -> BinomialRef;
}
#[inline]
pub fn assign_binomial_u(&mut self, n: u32, k: u32) {
unsafe {
gmp::mpz_bin_uiui(self.inner_mut(), n.into(), k.into());
}
}
#[inline]
pub fn assign_fibonacci(&mut self, n: u32) {
unsafe {
gmp::mpz_fib_ui(self.inner_mut(), n.into());
}
}
#[inline]
pub fn assign_fibonacci_2(&mut self, previous: &mut Integer, n: u32) {
unsafe {
gmp::mpz_fib2_ui(self.inner_mut(), previous.inner_mut(), n.into());
}
}
#[inline]
pub fn assign_lucas(&mut self, n: u32) {
unsafe {
gmp::mpz_lucnum_ui(self.inner_mut(), n.into());
}
}
#[inline]
pub fn assign_lucas_2(&mut self, previous: &mut Integer, n: u32) {
unsafe {
gmp::mpz_lucnum2_ui(
self.inner_mut(),
previous.inner_mut(),
n.into(),
);
}
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_bits(&mut self, bits: u32, rng: &mut RandState) {
unsafe {
gmp::mpz_urandomb(self.inner_mut(), rng.inner_mut(), bits.into());
}
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_below(mut self, rng: &mut RandState) -> Integer {
self.random_below_mut(rng);
self
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_below_mut(&mut self, rng: &mut RandState) {
assert_eq!(self.sign(), Ordering::Greater, "cannot be below zero");
unsafe {
gmp::mpz_urandomm(self.inner_mut(), rng.inner_mut(), self.inner());
}
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_below(
&mut self,
bound: &Integer,
rng: &mut RandState,
) {
assert_eq!(bound.sign(), Ordering::Greater, "cannot be below zero");
unsafe {
gmp::mpz_urandomm(self.inner_mut(), rng.inner_mut(), bound.inner());
}
}
}
impl<'a> From<&'a Integer> for Integer {
#[inline]
fn from(val: &Integer) -> Integer {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init_set(ret.inner_mut(), val.inner());
ret
}
}
}
impl From<i32> for Integer {
#[inline]
fn from(val: i32) -> Integer {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init_set_si(ret.inner_mut(), val.into());
ret
}
}
}
impl From<i64> for Integer {
#[inline]
fn from(val: i64) -> Integer {
if mem::size_of::<c_long>() >= 8 {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init_set_si(ret.inner_mut(), val as c_long);
ret
}
} else {
let mut i = Integer::new();
i.assign(val);
i
}
}
}
impl From<u32> for Integer {
#[inline]
fn from(val: u32) -> Integer {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init_set_ui(ret.inner_mut(), val.into());
ret
}
}
}
impl From<u64> for Integer {
#[inline]
fn from(val: u64) -> Integer {
if mem::size_of::<c_ulong>() >= 8 {
unsafe {
let mut ret: Integer = mem::uninitialized();
gmp::mpz_init_set_ui(ret.inner_mut(), val as c_ulong);
ret
}
} else {
let mut i = Integer::new();
i.assign(val);
i
}
}
}
impl FromStr for Integer {
type Err = ParseIntegerError;
#[inline]
fn from_str(src: &str) -> Result<Integer, ParseIntegerError> {
let mut i = Integer::new();
i.assign_str(src)?;
Ok(i)
}
}
impl Display for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "")
}
}
impl Debug for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "")
}
}
impl Binary for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 2, false, "0b")
}
}
impl Octal for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 8, false, "0o")
}
}
impl LowerHex for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, false, "0x")
}
}
impl UpperHex for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, true, "0x")
}
}
impl Assign for Integer {
#[inline]
fn assign(&mut self, mut other: Integer) {
mem::swap(self, &mut other);
}
}
impl<'a> Assign<&'a Integer> for Integer {
#[inline]
fn assign(&mut self, other: &'a Integer) {
unsafe {
gmp::mpz_set(self.inner_mut(), other.inner());
}
}
}
impl Assign<i32> for Integer {
#[inline]
fn assign(&mut self, val: i32) {
unsafe {
xgmp::mpz_set_i32(self.inner_mut(), val);
}
}
}
impl Assign<i64> for Integer {
#[inline]
fn assign(&mut self, val: i64) {
unsafe {
xgmp::mpz_set_i64(self.inner_mut(), val);
}
}
}
impl Assign<u32> for Integer {
#[inline]
fn assign(&mut self, val: u32) {
unsafe {
xgmp::mpz_set_u32(self.inner_mut(), val);
}
}
}
impl Assign<u64> for Integer {
#[inline]
fn assign(&mut self, val: u64) {
unsafe {
xgmp::mpz_set_u64(self.inner_mut(), val);
}
}
}
ref_math_op1! { Integer; gmp::mpz_abs; struct AbsRef {} }
ref_math_op1! { Integer; gmp::mpz_fdiv_r_2exp; struct KeepBitsRef { n: u32 } }
ref_math_op1! { Integer; xgmp::mpz_next_pow_of_two; struct NextPowerTwoRef {} }
ref_math_op2_2! {
Integer; xgmp::mpz_tdiv_qr_check_0; struct DivRemRef { divisor }
}
ref_math_op2! {
Integer; xgmp::mpz_divexact_check_0; struct DivExactRef { divisor }
}
ref_math_op1! {
Integer; xgmp::mpz_divexact_ui_check_0; struct DivExactURef { divisor: u32 }
}
#[derive(Clone, Copy)]
pub struct PowModRef<'a> {
ref_self: &'a Integer,
power: &'a Integer,
modulo: &'a Integer,
}
impl<'a> From<PowModRef<'a>> for Result<Integer, Integer> {
fn from(src: PowModRef<'a>) -> Result<Integer, Integer> {
if src.power.sign() == Ordering::Less {
let mut ret = Result::from(src.ref_self.invert_ref(src.modulo));
if let Ok(ref mut inv) = ret {
let abs_pow = src.power.as_neg();
unsafe {
gmp::mpz_powm(
inv.inner_mut(),
inv.inner(),
abs_pow.inner(),
src.modulo.inner(),
);
}
}
ret
} else {
let mut ret = Ok(Integer::new());
if let Ok(ref mut dest) = ret {
unsafe {
gmp::mpz_powm(
dest.inner_mut(),
src.ref_self.inner(),
src.power.inner(),
src.modulo.inner(),
);
}
}
ret
}
}
}
impl<'a> Assign<PowModRef<'a>> for Result<Integer, Integer> {
fn assign(&mut self, src: PowModRef<'a>) {
if src.power.sign() == Ordering::Less {
self.assign(src.ref_self.invert_ref(src.modulo));
if let Ok(ref mut inv) = *self {
let abs_pow = src.power.as_neg();
unsafe {
gmp::mpz_powm(
inv.inner_mut(),
inv.inner(),
abs_pow.inner(),
src.modulo.inner(),
);
}
}
} else {
if self.is_err() {
result_swap(self);
}
if let Ok(ref mut dest) = *self {
unsafe {
gmp::mpz_powm(
dest.inner_mut(),
src.ref_self.inner(),
src.power.inner(),
src.modulo.inner(),
);
}
}
}
}
}
ref_math_op1! { Integer; gmp::mpz_root; struct RootRef { n: u32 } }
ref_math_op1_2! { Integer; gmp::mpz_rootrem; struct RootRemRef { n: u32 } }
ref_math_op1! { Integer; gmp::mpz_sqrt; struct SqrtRef {} }
ref_math_op1_2! { Integer; gmp::mpz_sqrtrem; struct SqrtRemRef {} }
ref_math_op1! { Integer; gmp::mpz_nextprime; struct NextPrimeRef {} }
ref_math_op2! { Integer; gmp::mpz_gcd; struct GcdRef { other } }
ref_math_op2! { Integer; gmp::mpz_lcm; struct LcmRef { other } }
#[derive(Clone, Copy)]
pub struct InvertRef<'a> {
ref_self: &'a Integer,
modulo: &'a Integer,
}
impl<'a> From<InvertRef<'a>> for Result<Integer, Integer> {
#[inline]
fn from(src: InvertRef<'a>) -> Result<Integer, Integer> {
let mut i = Integer::new();
let exists = unsafe {
xgmp::mpz_invert_check_0(
i.inner_mut(),
src.ref_self.inner(),
src.modulo.inner(),
) != 0
};
if exists {
Ok(i)
} else {
Err(i)
}
}
}
impl<'a> Assign<InvertRef<'a>> for Result<Integer, Integer> {
#[inline]
fn assign(&mut self, src: InvertRef<'a>) {
let exists = {
let dest = match *self {
Ok(ref mut i) | Err(ref mut i) => i,
};
unsafe {
xgmp::mpz_invert_check_0(
dest.inner_mut(),
src.ref_self.inner(),
src.modulo.inner(),
) != 0
}
};
if exists != self.is_ok() {
result_swap(self);
}
}
}
#[derive(Clone, Copy)]
pub struct RemoveFactorRef<'a> {
ref_self: &'a Integer,
factor: &'a Integer,
}
impl<'a> Assign<RemoveFactorRef<'a>> for (&'a mut Integer, &'a mut u32) {
#[inline]
fn assign(&mut self, src: RemoveFactorRef<'a>) {
let cnt = unsafe {
gmp::mpz_remove(
self.0.inner_mut(),
src.ref_self.inner(),
src.factor.inner(),
)
};
assert_eq!(cnt as u32 as gmp::bitcnt_t, cnt, "overflow");
*self.1 = cnt as u32;
}
}
ref_math_op1! { Integer; gmp::mpz_bin_ui; struct BinomialRef { k: u32 } }
#[derive(Clone, Copy)]
pub struct BorrowInteger<'a> {
inner: mpz_t,
phantom: PhantomData<&'a Integer>,
}
impl<'a> Deref for BorrowInteger<'a> {
type Target = Integer;
#[inline]
fn deref(&self) -> &Integer {
let ptr = (&self.inner) as *const _ as *const _;
unsafe { &*ptr }
}
}
arith_unary! { Integer; gmp::mpz_neg; Neg neg; NegAssign neg_assign; NegRef }
arith_binary! {
Integer;
gmp::mpz_add;
Add add;
AddAssign add_assign;
AddFrom add_from;
AddRef
}
arith_binary! {
Integer;
gmp::mpz_sub;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
SubRef
}
arith_binary! {
Integer;
gmp::mpz_mul;
Mul mul;
MulAssign mul_assign;
MulFrom mul_from;
MulRef
}
arith_binary! {
Integer;
xgmp::mpz_tdiv_q_check_0;
Div div;
DivAssign div_assign;
DivFrom div_from;
DivRef
}
arith_binary! {
Integer;
xgmp::mpz_tdiv_r_check_0;
Rem rem;
RemAssign rem_assign;
RemFrom rem_from;
RemRef
}
arith_unary! { Integer; gmp::mpz_com; Not not; NotAssign not_assign; NotRef }
arith_binary! {
Integer;
gmp::mpz_and;
BitAnd bitand;
BitAndAssign bitand_assign;
BitAndFrom bitand_from;
BitAndRef
}
arith_binary! {
Integer;
gmp::mpz_ior;
BitOr bitor;
BitOrAssign bitor_assign;
BitOrFrom bitor_from;
BitOrRef
}
arith_binary! {
Integer;
gmp::mpz_xor;
BitXor bitxor;
BitXorAssign bitxor_assign;
BitXorFrom bitxor_from;
BitXorRef
}
arith_prim_commut! {
Integer;
xgmp::mpz_add_si;
Add add;
AddAssign add_assign;
AddFrom add_from;
i32;
AddRefI32
}
arith_prim_noncommut! {
Integer;
xgmp::mpz_sub_si, xgmp::mpz_si_sub;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
i32;
SubRefI32 SubFromRefI32
}
arith_prim_commut! {
Integer;
gmp::mpz_mul_si;
Mul mul;
MulAssign mul_assign;
MulFrom mul_from;
i32;
MulRefI32
}
arith_prim_noncommut! {
Integer;
xgmp::mpz_tdiv_q_si_check_0, xgmp::mpz_si_tdiv_q_check_0;
Div div;
DivAssign div_assign;
DivFrom div_from;
i32;
DivRefI32 DivFromRefI32
}
arith_prim_noncommut! {
Integer;
xgmp::mpz_tdiv_r_si_check_0, xgmp::mpz_si_tdiv_r_check_0;
Rem rem;
RemAssign rem_assign;
RemFrom rem_from;
i32;
RemRefI32 RemFromRefI32
}
arith_prim! {
Integer; xgmp::mpz_lshift_si; Shl shl; ShlAssign shl_assign; i32; ShlRefI32
}
arith_prim! {
Integer; xgmp::mpz_rshift_si; Shr shr; ShrAssign shr_assign; i32; ShrRefI32
}
arith_prim_commut! {
Integer;
xgmp::bitand_si;
BitAnd bitand;
BitAndAssign bitand_assign;
BitAndFrom bitand_from;
i32;
BitAndRefI32
}
arith_prim_commut! {
Integer;
xgmp::bitor_si;
BitOr bitor;
BitOrAssign bitor_assign;
BitOrFrom bitor_from;
i32;
BitOrRefI32
}
arith_prim_commut! {
Integer;
xgmp::bitxor_si;
BitXor bitxor;
BitXorAssign bitxor_assign;
BitXorFrom bitxor_from;
i32;
BitXorRefI32
}
arith_prim_commut! {
Integer;
gmp::mpz_add_ui;
Add add;
AddAssign add_assign;
AddFrom add_from;
u32;
AddRefU32
}
arith_prim_noncommut! {
Integer;
gmp::mpz_sub_ui, gmp::mpz_ui_sub;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
u32;
SubRefU32 SubFromRefU32
}
arith_prim_commut! {
Integer;
gmp::mpz_mul_ui;
Mul mul;
MulAssign mul_assign;
MulFrom mul_from;
u32;
MulRefU32
}
arith_prim_noncommut! {
Integer;
xgmp::mpz_tdiv_q_ui_check_0, xgmp::mpz_ui_tdiv_q_check_0;
Div div;
DivAssign div_assign;
DivFrom div_from;
u32;
DivRefU32 DivFromRefU32
}
arith_prim_noncommut! {
Integer;
xgmp::mpz_tdiv_r_ui_check_0, xgmp::mpz_ui_tdiv_r_check_0;
Rem rem;
RemAssign rem_assign;
RemFrom rem_from;
u32;
RemRefU32 RemFromRefU32
}
arith_prim! {
Integer; gmp::mpz_mul_2exp; Shl shl; ShlAssign shl_assign; u32; ShlRefU32
}
arith_prim! {
Integer; gmp::mpz_fdiv_q_2exp; Shr shr; ShrAssign shr_assign; u32; ShrRefU32
}
arith_prim! {
Integer; gmp::mpz_pow_ui; Pow pow; PowAssign pow_assign; u32; PowRefU32
}
arith_prim_commut! {
Integer;
xgmp::bitand_ui;
BitAnd bitand;
BitAndAssign bitand_assign;
BitAndFrom bitand_from;
u32;
BitAndRefU32
}
arith_prim_commut! {
Integer;
xgmp::bitor_ui;
BitOr bitor;
BitOrAssign bitor_assign;
BitOrFrom bitor_from;
u32;
BitOrRefU32
}
arith_prim_commut! {
Integer;
xgmp::bitxor_ui;
BitXor bitxor;
BitXorAssign bitxor_assign;
BitXorFrom bitxor_from;
u32;
BitXorRefU32
}
mul_op_commut! {
Integer;
gmp::mpz_addmul;
Add add;
AddAssign add_assign;
AddFrom add_from;
MulRef, inner;
AddMulRef
}
mul_op_commut! {
Integer;
gmp::mpz_addmul_ui;
Add add;
AddAssign add_assign;
AddFrom add_from;
MulRefU32, into;
AddMulRefU32
}
mul_op_commut! {
Integer;
xgmp::mpz_addmul_si;
Add add;
AddAssign add_assign;
AddFrom add_from;
MulRefI32, into;
AddMulRefI32
}
mul_op_noncommut! {
Integer;
gmp::mpz_submul, xgmp::mpz_mulsub;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
MulRef, inner;
SubMulRef SubMulRefFrom
}
mul_op_noncommut! {
Integer;
gmp::mpz_submul_ui, xgmp::mpz_mulsub_ui;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
MulRefU32, into;
SubMulRefU32 SubMulRefFromU32
}
mul_op_noncommut! {
Integer;
xgmp::mpz_submul_si, xgmp::mpz_mulsub_si;
Sub sub;
SubAssign sub_assign;
SubFrom sub_from;
MulRefI32, into;
SubMulRefI32 SubMulRefFromI32
}
impl Eq for Integer {}
impl Ord for Integer {
#[inline]
fn cmp(&self, other: &Integer) -> Ordering {
let ord = unsafe { gmp::mpz_cmp(self.inner(), other.inner()) };
ord.cmp(&0)
}
}
impl PartialEq for Integer {
#[inline]
fn eq(&self, other: &Integer) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl PartialOrd for Integer {
#[inline]
fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
Some(self.cmp(other))
}
}
macro_rules! cmp {
{ $T:ty, $func:path } => {
impl PartialEq<$T> for Integer {
#[inline]
fn eq(&self, other: &$T) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialEq<Integer> for $T {
#[inline]
fn eq(&self, other: &Integer) -> bool {
other.eq(self)
}
}
impl PartialOrd<$T> for Integer {
#[inline]
fn partial_cmp(&self, other: &$T) -> Option<Ordering> {
let ord = unsafe { $func(self.inner(), (*other).into()) };
Some(ord.cmp(&0))
}
}
impl PartialOrd<Integer> for $T {
#[inline]
fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
};
}
cmp! { i32, xgmp::mpz_cmp_i32 }
cmp! { i64, xgmp::mpz_cmp_i64 }
cmp! { u32, xgmp::mpz_cmp_u32 }
cmp! { u64, xgmp::mpz_cmp_u64 }
impl PartialEq<f32> for Integer {
#[inline]
fn eq(&self, other: &f32) -> bool {
let o = *other as f64;
self.eq(&o)
}
}
impl PartialEq<Integer> for f32 {
#[inline]
fn eq(&self, other: &Integer) -> bool {
other.eq(self)
}
}
impl PartialOrd<f32> for Integer {
#[inline]
fn partial_cmp(&self, other: &f32) -> Option<Ordering> {
let o = *other as f64;
self.partial_cmp(&o)
}
}
impl PartialOrd<Integer> for f32 {
#[inline]
fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
impl PartialEq<f64> for Integer {
#[inline]
fn eq(&self, other: &f64) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialEq<Integer> for f64 {
#[inline]
fn eq(&self, other: &Integer) -> bool {
other.eq(self)
}
}
impl PartialOrd<f64> for Integer {
#[inline]
fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
if other.is_nan() {
None
} else {
let ord = unsafe { gmp::mpz_cmp_d(self.inner(), *other) };
Some(ord.cmp(&0))
}
}
}
impl PartialOrd<Integer> for f64 {
#[inline]
fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
sum_prod! { Integer, Integer::new(), Integer::from(1) }
fn make_string(i: &Integer, radix: i32, to_upper: bool) -> String {
assert!(radix >= 2 && radix <= 36, "radix out of range");
let i_size = unsafe { gmp::mpz_sizeinbase(i.inner(), radix) };
let size = i_size.checked_add(2).unwrap();
let mut buf = Vec::<u8>::with_capacity(size);
let case_radix = if to_upper { -radix } else { radix };
unsafe {
buf.set_len(size);
gmp::mpz_get_str(
buf.as_mut_ptr() as *mut c_char,
case_radix as c_int,
i.inner(),
);
let nul_index = buf.iter().position(|&x| x == 0).unwrap();
buf.set_len(nul_index);
String::from_utf8_unchecked(buf)
}
}
fn fmt_radix(
i: &Integer,
f: &mut Formatter,
radix: i32,
to_upper: bool,
prefix: &str,
) -> fmt::Result {
let s = make_string(i, radix, to_upper);
let (neg, buf) = if s.starts_with('-') {
(true, &s[1..])
} else {
(false, &s[..])
};
f.pad_integral(!neg, prefix, buf)
}
#[derive(Clone, Debug)]
pub struct ValidInteger<'a> {
bytes: &'a [u8],
radix: i32,
}
from_borrow! { ValidInteger<'a> => Integer }
impl<'a> Assign<ValidInteger<'a>> for Integer {
#[inline]
fn assign(&mut self, rhs: ValidInteger) {
let mut v = Vec::<u8>::with_capacity(rhs.bytes.len() + 1);
v.extend_from_slice(rhs.bytes);
v.push(0);
let err = unsafe {
let c_str = CStr::from_bytes_with_nul_unchecked(&v);
gmp::mpz_set_str(self.inner_mut(), c_str.as_ptr(), rhs.radix.into())
};
assert_eq!(err, 0);
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ParseIntegerError {
kind: ParseErrorKind,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum ParseErrorKind {
InvalidDigit,
NoDigits,
}
impl Error for ParseIntegerError {
fn description(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
InvalidDigit => "invalid digit found in string",
NoDigits => "string has no digits",
}
}
}
impl Display for ParseIntegerError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IsPrime {
No,
Probably,
Yes,
}
unsafe impl Send for Integer {}
unsafe impl Sync for Integer {}
fn bitcount_to_u32(bits: gmp::bitcnt_t) -> Option<u32> {
let max: gmp::bitcnt_t = !0;
if bits == max {
None
} else {
assert_eq!(bits as u32 as gmp::bitcnt_t, bits, "overflow");
Some(bits as u32)
}
}
impl Inner for Integer {
type Output = mpz_t;
#[inline]
fn inner(&self) -> &mpz_t {
&self.inner
}
}
impl InnerMut for Integer {
#[inline]
unsafe fn inner_mut(&mut self) -> &mut mpz_t {
&mut self.inner
}
}
fn trunc_f64_to_f32(f: f64) -> f32 {
if !f.is_nan() {
let u = unsafe { mem::transmute::<_, u64>(f) };
let trunc_u = u & (!0 << 29);
let trunc_f = unsafe { mem::transmute::<_, f64>(trunc_u) };
trunc_f as f32
} else {
f as f32
}
}
fn result_swap<T>(r: &mut Result<T, T>) {
if r.is_ok() {
let val = match *r {
Ok(ref mut val) => {
mem::replace(val, unsafe { mem::uninitialized() })
}
Err(_) => unreachable!(),
};
mem::forget(mem::replace(r, Err(val)));
} else {
let val = match *r {
Err(ref mut val) => {
mem::replace(val, unsafe { mem::uninitialized() })
}
Ok(_) => unreachable!(),
};
mem::forget(mem::replace(r, Ok(val)));
}
}