├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── ffi.rs ├── lib.rs ├── mpf.rs ├── mpq.rs ├── mpz.rs ├── rand.rs ├── sign.rs └── test.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | Cargo.lock 3 | *.swp 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sudo apt-get update -qq 3 | - sudo apt-get install -y libgmp3-dev 4 | language: rust -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-gmp" 3 | version = "0.5.0" 4 | authors = [ "thestinger ", "Bartłomiej Kamiński " ] 5 | description = "Rust bindings for GMP" 6 | repository = "https://github.com/fizyk20/rust-gmp" 7 | documentation = "https://docs.rs/rust-gmp" 8 | license = "MIT" 9 | keywords = [ "gmp", "multi", "precision", "arithmetic", "bignum" ] 10 | 11 | [lib] 12 | name = "gmp" 13 | 14 | [dependencies] 15 | libc = "~0.2" 16 | num-traits = "0.1" 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2014 Daniel Micay 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/fizyk20/rust-gmp.svg?branch=master)](https://travis-ci.org/fizyk20/rust-gmp) 2 | 3 | [Documentation](https://docs.rs/rust-gmp) 4 | 5 | The following functions are intentionally left out of the bindings: 6 | 7 | * `gmp_randinit` (not thread-safe, obsolete) 8 | * `mpz_random` (not thread-safe, obsolete) 9 | * `mpz_random2` (not thread-safe, obsolete) 10 | * `mpf_set_default_prec` (not thread-safe) 11 | * `mpf_get_default_prec` (not thread-safe) 12 | * `mpf_init` (not thread-safe) 13 | * `mpf_inits` (not thread-safe, va_list wrapper) 14 | * `mpf_clears` (va_list wrapper) 15 | * `mpf_swap` (no better than rust's swap) 16 | * `mpf_set_prec_raw` (could be exposed with an `unsafe` function if needed) 17 | * `mpz_inits` (va_list wrapper) 18 | * `mpz_clears` (va_list wrapper) 19 | * `mpz_swap` (no better than rust's swap) 20 | * `mpq_inits` (va_list wrapper) 21 | * `mpq_clears` (va_list wrapper) 22 | * `mpq_swap` (no better than rust's swap) 23 | -------------------------------------------------------------------------------- /src/ffi.rs: -------------------------------------------------------------------------------- 1 | use mpz::*; 2 | 3 | #[link(name = "gmp")] 4 | extern "C" { 5 | pub fn __gmpz_fdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 6 | pub fn __gmpz_cdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 7 | } 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "gmp"] 2 | 3 | #![warn(deprecated)] 4 | #![allow(non_camel_case_types)] 5 | 6 | extern crate libc; 7 | extern crate num_traits; 8 | 9 | mod ffi; 10 | pub mod mpz; 11 | pub mod mpq; 12 | pub mod mpf; 13 | pub mod rand; 14 | pub mod sign; 15 | 16 | #[cfg(test)] 17 | mod test; 18 | -------------------------------------------------------------------------------- /src/mpf.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char, free}; 2 | use std; 3 | use std::mem::uninitialized; 4 | use std::cmp; 5 | use std::cmp::Ordering::{self, Greater, Less, Equal}; 6 | use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg}; 7 | use std::ffi::CString; 8 | use std::string::String; 9 | use super::mpz::mp_bitcnt_t; 10 | use super::mpz::{Mpz, mpz_srcptr}; 11 | use super::mpq::{Mpq, mpq_srcptr}; 12 | use super::sign::Sign; 13 | use num_traits::{Zero, One}; 14 | 15 | type mp_exp_t = c_long; 16 | 17 | #[repr(C)] 18 | pub struct mpf_struct { 19 | _mp_prec: c_int, 20 | _mp_size: c_int, 21 | _mp_exp: mp_exp_t, 22 | _mp_d: *mut c_void 23 | } 24 | 25 | pub type mpf_srcptr = *const mpf_struct; 26 | pub type mpf_ptr = *mut mpf_struct; 27 | 28 | #[link(name = "gmp")] 29 | extern "C" { 30 | fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t); 31 | fn __gmpf_init_set(rop: mpf_ptr, op: mpf_srcptr); 32 | fn __gmpf_clear(x: mpf_ptr); 33 | fn __gmpf_get_prec(op: mpf_srcptr) -> mp_bitcnt_t; 34 | fn __gmpf_set_prec(rop: mpf_ptr, prec: mp_bitcnt_t); 35 | fn __gmpf_set(rop: mpf_ptr, op: mpf_srcptr); 36 | fn __gmpf_set_z(rop: mpf_ptr, op: mpz_srcptr); 37 | fn __gmpf_set_q(rop: mpf_ptr, op: mpq_srcptr); 38 | 39 | fn __gmpf_set_str(rop: mpf_ptr, str: *const c_char, base: c_int); 40 | fn __gmpf_set_si(rop: mpf_ptr, op: c_long); 41 | fn __gmpf_get_str(str: *const c_char, expptr: *const mp_exp_t, base: i32, n_digits: i32, op: mpf_ptr) -> *mut c_char; 42 | 43 | fn __gmpf_cmp(op1: mpf_srcptr, op2: mpf_srcptr) -> c_int; 44 | fn __gmpf_cmp_d(op1: mpf_srcptr, op2: c_double) -> c_int; 45 | fn __gmpf_cmp_ui(op1: mpf_srcptr, op2: c_ulong) -> c_int; 46 | fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int; 47 | fn __gmpf_reldiff(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr); 48 | fn __gmpf_add(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr); 49 | fn __gmpf_sub(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr); 50 | fn __gmpf_mul(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr); 51 | fn __gmpf_div(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr); 52 | fn __gmpf_neg(rop: mpf_ptr, op: mpf_srcptr); 53 | fn __gmpf_abs(rop: mpf_ptr, op: mpf_srcptr); 54 | fn __gmpf_ceil(rop: mpf_ptr, op: mpf_srcptr); 55 | fn __gmpf_floor(rop: mpf_ptr, op: mpf_srcptr); 56 | fn __gmpf_trunc(rop: mpf_ptr, op: mpf_srcptr); 57 | fn __gmpf_sqrt(rop: mpf_ptr, op: mpf_srcptr); 58 | } 59 | 60 | pub struct Mpf { 61 | mpf: mpf_struct, 62 | } 63 | 64 | unsafe impl Send for Mpf { } 65 | unsafe impl Sync for Mpf { } 66 | 67 | impl Drop for Mpf { 68 | fn drop(&mut self) { unsafe { __gmpf_clear(&mut self.mpf) } } 69 | } 70 | 71 | impl Mpf { 72 | pub unsafe fn inner(&self) -> mpf_srcptr { 73 | &self.mpf 74 | } 75 | 76 | pub unsafe fn inner_mut(&mut self) -> mpf_ptr { 77 | &mut self.mpf 78 | } 79 | 80 | pub fn zero() -> Mpf { Mpf::new(32) } 81 | 82 | pub fn new(precision: usize) -> Mpf { 83 | unsafe { 84 | let mut mpf = uninitialized(); 85 | __gmpf_init2(&mut mpf, precision as c_ulong); 86 | Mpf { mpf: mpf } 87 | } 88 | } 89 | 90 | pub fn set(&mut self, other: &Mpf) { 91 | unsafe { __gmpf_set(&mut self.mpf, &other.mpf) } 92 | } 93 | 94 | pub fn set_z(&mut self, other: &Mpz) { 95 | unsafe { __gmpf_set_z(&mut self.mpf, other.inner()) } 96 | } 97 | 98 | pub fn set_q(&mut self, other: &Mpq) { 99 | unsafe { __gmpf_set_q(&mut self.mpf, other.inner()) } 100 | } 101 | 102 | pub fn get_prec(&self) -> usize { 103 | unsafe { __gmpf_get_prec(&self.mpf) as usize } 104 | } 105 | 106 | pub fn set_prec(&mut self, precision: usize) { 107 | unsafe { __gmpf_set_prec(&mut self.mpf, precision as c_ulong) } 108 | } 109 | 110 | pub fn set_from_str(&mut self, string: &str, base: i32){ 111 | let c_str = CString::new(string).unwrap(); 112 | unsafe { 113 | __gmpf_set_str(&mut self.mpf, c_str.as_ptr(), base as c_int); 114 | } 115 | } 116 | 117 | pub fn set_from_si(&mut self, int: i64){ 118 | unsafe{ 119 | __gmpf_set_si(&mut self.mpf,int as c_long); 120 | } 121 | } 122 | 123 | pub fn get_str(&mut self, n_digits: i32, base: i32, exp: &mut c_long) -> String{ 124 | let out; 125 | unsafe{ 126 | out = CString::from_raw(__gmpf_get_str(std::ptr::null(), exp, base, n_digits, &mut self.mpf)); 127 | } 128 | let r = out.to_str().unwrap().to_string(); 129 | // Free the pointer returned to us, as r already took a copy of the data inside of it 130 | // Stops memory leaking 131 | unsafe { free(out.into_raw() as _) }; 132 | r 133 | } 134 | 135 | pub fn abs(&self) -> Mpf { 136 | unsafe { 137 | let mut res = Mpf::new(self.get_prec()); 138 | __gmpf_abs(&mut res.mpf, &self.mpf); 139 | res 140 | } 141 | } 142 | 143 | pub fn ceil(&self) -> Mpf { 144 | unsafe { 145 | let mut res = Mpf::new(self.get_prec()); 146 | __gmpf_ceil(&mut res.mpf, &self.mpf); 147 | res 148 | } 149 | } 150 | 151 | pub fn floor(&self) -> Mpf { 152 | unsafe { 153 | let mut res = Mpf::new(self.get_prec()); 154 | __gmpf_floor(&mut res.mpf, &self.mpf); 155 | res 156 | } 157 | } 158 | 159 | pub fn trunc(&self) -> Mpf { 160 | unsafe { 161 | let mut res = Mpf::new(self.get_prec()); 162 | __gmpf_trunc(&mut res.mpf, &self.mpf); 163 | res 164 | } 165 | } 166 | 167 | pub fn reldiff(&self, other: &Mpf) -> Mpf { 168 | unsafe { 169 | let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec())); 170 | __gmpf_reldiff(&mut res.mpf, &self.mpf, &other.mpf); 171 | res 172 | } 173 | } 174 | 175 | pub fn sqrt(self) -> Mpf { 176 | let mut retval:Mpf; 177 | unsafe { 178 | retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize); 179 | retval.set_from_si(0); 180 | if __gmpf_cmp_si(&self.mpf, 0) > 0 { 181 | __gmpf_sqrt(&mut retval.mpf, &self.mpf); 182 | } else { 183 | panic!("Square root of negative/zero"); 184 | } 185 | } 186 | retval 187 | } 188 | 189 | pub fn sign(&self) -> Sign { 190 | let size = self.mpf._mp_size; 191 | if size == 0 { 192 | Sign::Zero 193 | } else if size > 0 { 194 | Sign::Positive 195 | } else { 196 | Sign::Negative 197 | } 198 | } 199 | } 200 | 201 | impl Clone for Mpf { 202 | fn clone(&self) -> Mpf { 203 | unsafe { 204 | let mut mpf = uninitialized(); 205 | __gmpf_init_set(&mut mpf, &self.mpf); 206 | Mpf { mpf: mpf } 207 | } 208 | } 209 | } 210 | 211 | impl Eq for Mpf { } 212 | impl PartialEq for Mpf { 213 | fn eq(&self, other: &Mpf) -> bool { 214 | unsafe { __gmpf_cmp(&self.mpf, &other.mpf) == 0 } 215 | } 216 | } 217 | 218 | impl Ord for Mpf { 219 | fn cmp(&self, other: &Mpf) -> Ordering { 220 | let cmp = unsafe { __gmpf_cmp(&self.mpf, &other.mpf) }; 221 | if cmp == 0 { 222 | Equal 223 | } else if cmp > 0 { 224 | Greater 225 | } else { 226 | Less 227 | } 228 | } 229 | } 230 | 231 | impl PartialOrd for Mpf { 232 | fn partial_cmp(&self, other: &Mpf) -> Option { 233 | Some(self.cmp(other)) 234 | } 235 | } 236 | 237 | macro_rules! div_guard { 238 | (Div, $is_zero: expr) => { 239 | if $is_zero { 240 | panic!("divide by zero") 241 | } 242 | }; 243 | ($tr: ident, $what: expr) => {} 244 | } 245 | 246 | macro_rules! impl_oper { 247 | ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { 248 | impl<'a> $tr for &'a Mpf { 249 | type Output = Mpf; 250 | #[inline] 251 | fn $meth(self, other: Mpf) -> Mpf { 252 | self.$meth(&other) 253 | } 254 | } 255 | 256 | impl<'a> $tr<&'a Mpf> for Mpf { 257 | type Output = Mpf; 258 | #[inline] 259 | fn $meth(mut self, other: &Mpf) -> Mpf { 260 | self.$meth_assign(other); 261 | self 262 | } 263 | } 264 | 265 | impl $tr for Mpf { 266 | type Output = Mpf; 267 | #[inline] 268 | fn $meth(self, other: Mpf) -> Mpf { 269 | self.$meth(&other) 270 | } 271 | } 272 | 273 | impl<'a, 'b> $tr<&'a Mpf> for &'b Mpf { 274 | type Output = Mpf; 275 | fn $meth(self, other: &Mpf) -> Mpf { 276 | unsafe { 277 | div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0); 278 | let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec())); 279 | $fun(&mut res.mpf, &self.mpf, &other.mpf); 280 | res 281 | } 282 | } 283 | } 284 | 285 | impl<'a> $tr_assign for Mpf { 286 | #[inline] 287 | fn $meth_assign(&mut self, other: Mpf) { 288 | self.$meth_assign(&other) 289 | } 290 | } 291 | 292 | impl<'a> $tr_assign<&'a Mpf> for Mpf { 293 | #[inline] 294 | fn $meth_assign(&mut self, other: &Mpf) { 295 | unsafe { 296 | div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0); 297 | $fun(&mut self.mpf, &self.mpf, &other.mpf) 298 | } 299 | } 300 | } 301 | } 302 | } 303 | 304 | impl_oper!(Add, add, AddAssign, add_assign, __gmpf_add); 305 | impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpf_sub); 306 | impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpf_mul); 307 | impl_oper!(Div, div, DivAssign, div_assign, __gmpf_div); 308 | 309 | 310 | impl<'b> Neg for &'b Mpf { 311 | type Output = Mpf; 312 | fn neg(self) -> Mpf { 313 | unsafe { 314 | let mut res = Mpf::new(self.get_prec()); 315 | __gmpf_neg(&mut res.mpf, &self.mpf); 316 | res 317 | } 318 | } 319 | } 320 | 321 | impl Neg for Mpf { 322 | type Output = Mpf; 323 | #[inline] 324 | fn neg(mut self) -> Mpf { 325 | unsafe { 326 | __gmpf_neg(&mut self.mpf, &self.mpf); 327 | self 328 | } 329 | } 330 | } 331 | 332 | impl Zero for Mpf { 333 | #[inline] 334 | fn zero() -> Mpf { 335 | Mpf::zero() 336 | } 337 | 338 | #[inline] 339 | fn is_zero(&self) -> bool { 340 | unsafe { 341 | __gmpf_cmp_ui(&self.mpf, 0) == 0 342 | } 343 | } 344 | } 345 | 346 | impl One for Mpf { 347 | #[inline] 348 | fn one() -> Mpf { 349 | let mut res = Mpf::new(32); 350 | res.set_from_si(1); 351 | res 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /src/mpq.rs: -------------------------------------------------------------------------------- 1 | use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr}; 2 | use super::mpf::{Mpf, mpf_srcptr}; 3 | use super::sign::Sign; 4 | use ffi::*; 5 | use libc::{c_char, c_double, c_int, c_ulong}; 6 | use std::ffi::CString; 7 | use std::str::FromStr; 8 | use std::error::Error; 9 | use std::convert::From; 10 | use std::mem::uninitialized; 11 | use std::fmt; 12 | use std::cmp::Ordering::{self, Greater, Less, Equal}; 13 | use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg}; 14 | use num_traits::{Zero, One}; 15 | 16 | #[repr(C)] 17 | pub struct mpq_struct { 18 | _mp_num: mpz_struct, 19 | _mp_den: mpz_struct 20 | } 21 | 22 | pub type mpq_srcptr = *const mpq_struct; 23 | pub type mpq_ptr = *mut mpq_struct; 24 | 25 | #[link(name = "gmp")] 26 | extern "C" { 27 | fn __gmpq_init(x: mpq_ptr); 28 | fn __gmpq_clear(x: mpq_ptr); 29 | fn __gmpq_set(rop: mpq_ptr, op: mpq_srcptr); 30 | fn __gmpq_set_z(rop: mpq_ptr, op: mpz_srcptr); 31 | fn __gmpq_set_ui(rop: mpq_ptr, op1: c_ulong, op2: c_ulong); 32 | fn __gmpq_set_d(rop: mpq_ptr, op: c_double); 33 | fn __gmpq_set_f(rop: mpq_ptr, op: mpf_srcptr); 34 | fn __gmpq_cmp(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int; 35 | fn __gmpq_cmp_ui(op1: mpq_srcptr, num2: c_ulong, den2: c_ulong) -> c_int; 36 | fn __gmpq_equal(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int; 37 | fn __gmpq_add(sum: mpq_ptr, addend1: mpq_srcptr, addend2: mpq_srcptr); 38 | fn __gmpq_sub(difference: mpq_ptr, minuend: mpq_srcptr, subtrahend: mpq_srcptr); 39 | fn __gmpq_mul(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr); 40 | fn __gmpq_div(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr); 41 | fn __gmpq_neg(negated_operand: mpq_ptr, operand: mpq_srcptr); 42 | fn __gmpq_abs(rop: mpq_ptr, op: mpq_srcptr); 43 | fn __gmpq_inv(inverted_number: mpq_ptr, number: mpq_srcptr); 44 | fn __gmpq_get_num(numerator: mpz_ptr, rational: mpq_srcptr); 45 | fn __gmpq_get_den(denominator: mpz_ptr, rational: mpq_srcptr); 46 | fn __gmpq_set_num(rational: mpq_ptr, numerator: mpz_srcptr); 47 | fn __gmpq_set_den(rational: mpq_ptr, denominator: mpz_srcptr); 48 | fn __gmpq_canonicalize(rational: mpq_ptr); 49 | fn __gmpq_get_d(rational: mpq_srcptr) -> c_double; 50 | fn __gmpq_set_str(rop: mpq_ptr, str: *const c_char, base: c_int) -> c_int; 51 | } 52 | 53 | pub struct Mpq { 54 | mpq: mpq_struct, 55 | } 56 | 57 | unsafe impl Send for Mpq { } 58 | unsafe impl Sync for Mpq { } 59 | 60 | impl Drop for Mpq { 61 | fn drop(&mut self) { unsafe { __gmpq_clear(&mut self.mpq) } } 62 | } 63 | 64 | impl Mpq { 65 | pub unsafe fn inner(&self) -> mpq_srcptr { 66 | &self.mpq 67 | } 68 | 69 | pub unsafe fn inner_mut(&mut self) -> mpq_ptr { 70 | &mut self.mpq 71 | } 72 | 73 | pub fn new() -> Mpq { 74 | unsafe { 75 | let mut mpq = uninitialized(); 76 | __gmpq_init(&mut mpq); 77 | Mpq { mpq: mpq } 78 | } 79 | } 80 | 81 | pub fn ratio(num: &Mpz, den: &Mpz) -> Mpq { 82 | unsafe { 83 | let mut res = Mpq::new(); 84 | __gmpq_set_num(&mut res.mpq, num.inner()); 85 | __gmpq_set_den(&mut res.mpq, den.inner()); 86 | // Not canonicalizing is unsafe 87 | __gmpq_canonicalize(&mut res.mpq); 88 | res 89 | } 90 | } 91 | 92 | pub fn from_str_radix(s: &str, base: u8) -> Result { 93 | let s = CString::new(s).map_err(|_| ParseMpqError { _priv: () })?; 94 | let mut res = Mpq::new(); 95 | unsafe { 96 | assert!(base == 0 || (base >= 2 && base <= 62)); 97 | let r = __gmpq_set_str(&mut res.mpq, s.as_ptr(), base as c_int); 98 | 99 | if r == 0 { 100 | // Not canonicalizing is unsafe 101 | __gmpq_canonicalize(&mut res.mpq); 102 | Ok(res) 103 | } else { 104 | Err(ParseMpqError { _priv: () }) 105 | } 106 | } 107 | } 108 | 109 | pub fn set(&mut self, other: &Mpq) { 110 | unsafe { __gmpq_set(&mut self.mpq, &other.mpq) } 111 | } 112 | 113 | pub fn set_z(&mut self, other: &Mpz) { 114 | unsafe { __gmpq_set_z(&mut self.mpq, other.inner()) } 115 | } 116 | 117 | pub fn set_d(&mut self, other: f64) { 118 | unsafe { __gmpq_set_d(&mut self.mpq, other) } 119 | } 120 | 121 | pub fn set_f(&mut self, other: &Mpf) { 122 | unsafe { __gmpq_set_f(&mut self.mpq, other.inner()) } 123 | } 124 | 125 | pub fn get_num(&self) -> Mpz { 126 | unsafe { 127 | let mut res = Mpz::new(); 128 | __gmpq_get_num(res.inner_mut(), &self.mpq); 129 | res 130 | } 131 | } 132 | 133 | pub fn get_den(&self) -> Mpz { 134 | unsafe { 135 | let mut res = Mpz::new(); 136 | __gmpq_get_den(res.inner_mut(), &self.mpq); 137 | res 138 | } 139 | } 140 | 141 | pub fn abs(&self) -> Mpq { 142 | unsafe { 143 | let mut res = Mpq::new(); 144 | __gmpq_abs(&mut res.mpq, &self.mpq); 145 | res 146 | } 147 | } 148 | 149 | pub fn invert(&self) -> Mpq { 150 | unsafe { 151 | if self.is_zero() { 152 | panic!("divide by zero") 153 | } 154 | 155 | let mut res = Mpq::new(); 156 | __gmpq_inv(&mut res.mpq, &self.mpq); 157 | res 158 | } 159 | } 160 | 161 | pub fn floor(&self) -> Mpz { 162 | let mut res = Mpz::new(); 163 | unsafe { 164 | __gmpz_fdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den); 165 | } 166 | res 167 | } 168 | 169 | pub fn ceil(&self) -> Mpz { 170 | let mut res = Mpz::new(); 171 | unsafe { 172 | __gmpz_cdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den); 173 | } 174 | res 175 | } 176 | 177 | pub fn sign(&self) -> Sign { 178 | self.get_num().sign() 179 | } 180 | 181 | pub fn one() -> Mpq { 182 | let mut res = Mpq::new(); 183 | unsafe { __gmpq_set_ui(&mut res.mpq, 1, 1) } 184 | res 185 | } 186 | 187 | pub fn zero() -> Mpq { Mpq::new() } 188 | pub fn is_zero(&self) -> bool { 189 | unsafe { __gmpq_cmp_ui(&self.mpq, 0, 1) == 0 } 190 | } 191 | } 192 | 193 | #[derive(Debug)] 194 | pub struct ParseMpqError { 195 | _priv: () 196 | } 197 | 198 | impl fmt::Display for ParseMpqError { 199 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 200 | self.description().fmt(f) 201 | } 202 | } 203 | 204 | impl Error for ParseMpqError { 205 | fn description(&self) -> &'static str { 206 | "invalid rational number" 207 | } 208 | 209 | fn cause(&self) -> Option<&'static Error> { 210 | None 211 | } 212 | } 213 | 214 | impl Clone for Mpq { 215 | fn clone(&self) -> Mpq { 216 | let mut res = Mpq::new(); 217 | res.set(self); 218 | res 219 | } 220 | } 221 | 222 | impl Eq for Mpq { } 223 | impl PartialEq for Mpq { 224 | fn eq(&self, other: &Mpq) -> bool { 225 | unsafe { __gmpq_equal(&self.mpq, &other.mpq) != 0 } 226 | } 227 | } 228 | 229 | impl Ord for Mpq { 230 | fn cmp(&self, other: &Mpq) -> Ordering { 231 | let cmp = unsafe { __gmpq_cmp(&self.mpq, &other.mpq) }; 232 | if cmp == 0 { 233 | Equal 234 | } else if cmp < 0 { 235 | Less 236 | } else { 237 | Greater 238 | } 239 | } 240 | } 241 | impl PartialOrd for Mpq { 242 | fn partial_cmp(&self, other: &Mpq) -> Option { 243 | Some(self.cmp(other)) 244 | } 245 | } 246 | 247 | macro_rules! div_guard { 248 | (Div, $what: expr) => { 249 | if $what.is_zero() { 250 | panic!("divide by zero") 251 | } 252 | }; 253 | ($tr: ident, $what: expr) => {} 254 | } 255 | 256 | macro_rules! impl_oper { 257 | ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { 258 | impl $tr for Mpq { 259 | type Output = Mpq; 260 | #[inline] 261 | fn $meth(self, other: Mpq) -> Mpq { 262 | self.$meth(&other) 263 | } 264 | } 265 | 266 | impl<'a> $tr<&'a Mpq> for Mpq { 267 | type Output = Mpq; 268 | #[inline] 269 | fn $meth(mut self, other: &Mpq) -> Mpq { 270 | self.$meth_assign(other); 271 | self 272 | } 273 | } 274 | 275 | impl<'a> $tr for &'a Mpq { 276 | type Output = Mpq; 277 | #[inline] 278 | fn $meth(self, mut other: Mpq) -> Mpq { 279 | unsafe { 280 | div_guard!($tr, other); 281 | $fun(&mut other.mpq, &self.mpq, &other.mpq); 282 | other 283 | } 284 | } 285 | } 286 | 287 | impl<'a, 'b> $tr<&'a Mpq> for &'b Mpq { 288 | type Output = Mpq; 289 | fn $meth(self, other: &Mpq) -> Mpq { 290 | unsafe { 291 | div_guard!($tr, *other); 292 | let mut res = Mpq::new(); 293 | $fun(&mut res.mpq, &self.mpq, &other.mpq); 294 | res 295 | } 296 | } 297 | } 298 | 299 | impl<'a> $tr_assign for Mpq { 300 | #[inline] 301 | fn $meth_assign(&mut self, other: Mpq) { 302 | self.$meth_assign(&other) 303 | } 304 | } 305 | 306 | impl<'a> $tr_assign<&'a Mpq> for Mpq { 307 | #[inline] 308 | fn $meth_assign(&mut self, other: &Mpq) { 309 | unsafe { 310 | div_guard!($tr, *other); 311 | $fun(&mut self.mpq, &self.mpq, &other.mpq) 312 | } 313 | } 314 | } 315 | } 316 | } 317 | 318 | impl_oper!(Add, add, AddAssign, add_assign, __gmpq_add); 319 | impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpq_sub); 320 | impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpq_mul); 321 | impl_oper!(Div, div, DivAssign, div_assign, __gmpq_div); 322 | 323 | impl<'b> Neg for &'b Mpq { 324 | type Output = Mpq; 325 | fn neg(self) -> Mpq { 326 | unsafe { 327 | let mut res = Mpq::new(); 328 | __gmpq_neg(&mut res.mpq, &self.mpq); 329 | res 330 | } 331 | } 332 | } 333 | 334 | impl Neg for Mpq { 335 | type Output = Mpq; 336 | #[inline] 337 | fn neg(mut self) -> Mpq { 338 | unsafe { 339 | __gmpq_neg(&mut self.mpq, &self.mpq); 340 | self 341 | } 342 | } 343 | } 344 | 345 | impl From for f64 { 346 | fn from(other: Mpq) -> f64 { 347 | f64::from(&other) 348 | } 349 | } 350 | 351 | impl<'a> From<&'a Mpq> for f64 { 352 | fn from(other: &Mpq) -> f64 { 353 | unsafe { 354 | __gmpq_get_d(&other.mpq) as f64 355 | } 356 | } 357 | } 358 | 359 | impl From for Mpq { 360 | fn from(other: Mpz) -> Mpq { 361 | Mpq::from(&other) 362 | } 363 | } 364 | 365 | impl<'a> From<&'a Mpz> for Mpq { 366 | fn from(other: &Mpz) -> Mpq { 367 | let mut res = Mpq::new(); 368 | res.set_z(&other); 369 | res 370 | } 371 | } 372 | 373 | impl From for Mpq { 374 | fn from(other: i64) -> Mpq { 375 | From::::from(From::::from(other)) 376 | } 377 | } 378 | 379 | impl From for Mpq { 380 | fn from(other: i32) -> Mpq { 381 | From::::from(From::::from(other)) 382 | } 383 | } 384 | 385 | impl From for Mpq { 386 | fn from(other: u64) -> Mpq { 387 | From::::from(From::::from(other)) 388 | } 389 | } 390 | 391 | impl From for Mpq { 392 | fn from(other: u32) -> Mpq { 393 | From::::from(From::::from(other)) 394 | } 395 | } 396 | 397 | impl FromStr for Mpq { 398 | type Err = ParseMpqError; 399 | fn from_str(s: &str) -> Result { 400 | Mpq::from_str_radix(s, 10) 401 | } 402 | } 403 | 404 | 405 | impl fmt::Debug for Mpq { 406 | /// Renders as `numer/denom`. If denom=1, renders as numer. 407 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 408 | fmt::Display::fmt(&self, f) 409 | } 410 | } 411 | 412 | impl fmt::Display for Mpq { 413 | /// Renders as `numer/denom`. If denom=1, renders as numer. 414 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 415 | let numer = self.get_num(); 416 | let denom = self.get_den(); 417 | 418 | if denom == From::::from(1) { 419 | write!(f, "{}", numer) 420 | } else { 421 | write!(f, "{}/{}", numer, denom) 422 | } 423 | } 424 | } 425 | 426 | impl Zero for Mpq { 427 | #[inline] 428 | fn zero() -> Mpq { 429 | Mpq::zero() 430 | } 431 | 432 | #[inline] 433 | fn is_zero(&self) -> bool { 434 | self.is_zero() 435 | } 436 | } 437 | 438 | impl One for Mpq { 439 | #[inline] 440 | fn one() -> Mpq { 441 | Mpq::one() 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /src/mpz.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_int, c_long, c_ulong, c_void, c_double, size_t}; 2 | use super::rand::gmp_randstate_t; 3 | use super::sign::Sign; 4 | use std::convert::From; 5 | use std::mem::{uninitialized,size_of}; 6 | use std::{fmt, hash}; 7 | use std::cmp::Ordering::{self, Greater, Less, Equal}; 8 | use std::str::FromStr; 9 | use std::error::Error; 10 | use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, BitXor, BitXorAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, Rem, RemAssign}; 11 | use std::ffi::CString; 12 | use std::{u32, i32}; 13 | use num_traits::{Zero, One}; 14 | 15 | use ffi::*; 16 | 17 | #[repr(C)] 18 | pub struct mpz_struct { 19 | _mp_alloc: c_int, 20 | _mp_size: c_int, 21 | _mp_d: *mut c_void 22 | } 23 | 24 | pub type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead. 25 | pub type mp_bitcnt_t = c_ulong; 26 | pub type mpz_srcptr = *const mpz_struct; 27 | pub type mpz_ptr = *mut mpz_struct; 28 | 29 | #[link(name = "gmp")] 30 | extern "C" { 31 | static __gmp_bits_per_limb: c_int; 32 | fn __gmpz_init(x: mpz_ptr); 33 | fn __gmpz_init2(x: mpz_ptr, n: mp_bitcnt_t); 34 | fn __gmpz_init_set(rop: mpz_ptr, op: mpz_srcptr); 35 | fn __gmpz_init_set_ui(rop: mpz_ptr, op: c_ulong); 36 | fn __gmpz_init_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; 37 | fn __gmpz_clear(x: mpz_ptr); 38 | fn __gmpz_realloc2(x: mpz_ptr, n: mp_bitcnt_t); 39 | fn __gmpz_set(rop: mpz_ptr, op: mpz_srcptr); 40 | fn __gmpz_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; 41 | fn __gmpz_get_str(s: *mut c_char, base: c_int, op: mpz_srcptr) -> *mut c_char; 42 | fn __gmpz_get_ui(op: mpz_srcptr) -> c_ulong; 43 | fn __gmpz_fits_ulong_p(op: mpz_srcptr) -> c_int; 44 | fn __gmpz_get_si(op: mpz_srcptr) -> c_ulong; 45 | fn __gmpz_get_d(op: mpz_srcptr) -> c_double; 46 | fn __gmpz_fits_slong_p(op: mpz_srcptr) -> c_long; 47 | fn __gmpz_sizeinbase(op: mpz_srcptr, base: c_int) -> size_t; 48 | fn __gmpz_cmp(op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; 49 | fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int; 50 | fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 51 | fn __gmpz_add_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); 52 | fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 53 | fn __gmpz_sub_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); 54 | fn __gmpz_ui_sub(rop: mpz_ptr, op1: c_ulong, op2: mpz_srcptr); 55 | fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 56 | fn __gmpz_mul_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); 57 | fn __gmpz_mul_si(rop: mpz_ptr, op1: mpz_srcptr, op2: c_long); 58 | fn __gmpz_mul_2exp(rop: mpz_ptr, op1: mpz_srcptr, op2: mp_bitcnt_t); 59 | fn __gmpz_neg(rop: mpz_ptr, op: mpz_srcptr); 60 | fn __gmpz_abs(rop: mpz_ptr, op: mpz_srcptr); 61 | fn __gmpz_tdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 62 | fn __gmpz_tdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 63 | fn __gmpz_tdiv_q_ui(q: mpz_ptr, n: mpz_srcptr, d: c_ulong); 64 | fn __gmpz_tdiv_r_ui(r: mpz_ptr, n: mpz_srcptr, d: c_ulong); 65 | fn __gmpz_fdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 66 | fn __gmpz_fdiv_q_2exp(q: mpz_ptr, n: mpz_srcptr, b: mp_bitcnt_t); 67 | fn __gmpz_mod(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); 68 | fn __gmpz_divisible_p(n: mpz_srcptr, d: mpz_srcptr) -> c_int; 69 | fn __gmpz_and(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 70 | fn __gmpz_ior(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 71 | fn __gmpz_xor(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 72 | fn __gmpz_com(rop: mpz_ptr, op: mpz_srcptr); 73 | fn __gmpz_popcount(op: mpz_srcptr) -> mp_bitcnt_t; 74 | fn __gmpz_pow_ui(rop: mpz_ptr, base: mpz_srcptr, exp: c_ulong); 75 | fn __gmpz_ui_pow_ui(rop: mpz_ptr, base: c_ulong, exp: c_ulong); 76 | fn __gmpz_powm(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr); 77 | fn __gmpz_powm_sec(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr); 78 | fn __gmpz_hamdist(op1: mpz_srcptr, op2: mpz_srcptr) -> mp_bitcnt_t; 79 | fn __gmpz_setbit(rop: mpz_ptr, bit_index: mp_bitcnt_t); 80 | fn __gmpz_clrbit(rop: mpz_ptr, bit_index: mp_bitcnt_t); 81 | fn __gmpz_combit(rop: mpz_ptr, bit_index: mp_bitcnt_t); 82 | fn __gmpz_tstbit(rop: mpz_srcptr, bit_index: mp_bitcnt_t) -> c_int; 83 | fn __gmpz_probab_prime_p(n: mpz_srcptr, reps: c_int) -> c_int; 84 | fn __gmpz_nextprime(rop: mpz_ptr, op: mpz_srcptr); 85 | fn __gmpz_gcd(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 86 | fn __gmpz_gcdext(g: mpz_ptr, s: mpz_ptr, t: mpz_ptr, a: mpz_srcptr, b: mpz_srcptr); 87 | fn __gmpz_lcm(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); 88 | fn __gmpz_invert(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; 89 | fn __gmpz_import(rop: mpz_ptr, count: size_t, order: c_int, size: size_t, 90 | endian: c_int, nails: size_t, op: *const c_void); 91 | fn __gmpz_export(rop: *mut c_void, countp: *mut size_t, order: c_int, size: size_t, 92 | endian: c_int, nails: size_t, op: mpz_srcptr); 93 | fn __gmpz_root(rop: mpz_ptr, op: mpz_srcptr, n: c_ulong) -> c_int; 94 | fn __gmpz_sqrt(rop: mpz_ptr, op: mpz_srcptr); 95 | fn __gmpz_millerrabin(n: mpz_srcptr, reps: c_int) -> c_int; 96 | fn __gmpz_urandomb(rop: mpz_ptr, state: gmp_randstate_t, n: mp_bitcnt_t); 97 | fn __gmpz_urandomm(rop: mpz_ptr, state: gmp_randstate_t, n: mpz_srcptr); 98 | } 99 | 100 | pub struct Mpz { 101 | mpz: mpz_struct, 102 | } 103 | 104 | unsafe impl Send for Mpz { } 105 | unsafe impl Sync for Mpz { } 106 | 107 | impl Drop for Mpz { 108 | fn drop(&mut self) { unsafe { __gmpz_clear(&mut self.mpz) } } 109 | } 110 | 111 | /// The result of running probab_prime 112 | #[derive(PartialEq)] 113 | pub enum ProbabPrimeResult { 114 | NotPrime, 115 | ProbablyPrime, 116 | Prime 117 | } 118 | 119 | impl Mpz { 120 | pub unsafe fn inner(&self) -> mpz_srcptr { 121 | &self.mpz 122 | } 123 | 124 | pub unsafe fn inner_mut(&mut self) -> mpz_ptr { 125 | &mut self.mpz 126 | } 127 | 128 | pub fn new() -> Mpz { 129 | unsafe { 130 | let mut mpz = uninitialized(); 131 | __gmpz_init(&mut mpz); 132 | Mpz { mpz: mpz } 133 | } 134 | } 135 | 136 | pub fn new_reserve(n: usize) -> Mpz { 137 | unsafe { 138 | let mut mpz = uninitialized(); 139 | __gmpz_init2(&mut mpz, n as c_ulong); 140 | Mpz { mpz: mpz } 141 | } 142 | } 143 | 144 | pub fn reserve(&mut self, n: usize) { 145 | if self.bit_length() < n { 146 | unsafe { __gmpz_realloc2(&mut self.mpz, n as c_ulong) } 147 | } 148 | } 149 | 150 | pub fn size_in_base(&self, base: u8) -> usize { 151 | unsafe { 152 | __gmpz_sizeinbase(&self.mpz, base as c_int) as usize 153 | } 154 | } 155 | 156 | // TODO: fail on an invalid base 157 | // FIXME: Unfortunately it isn't currently possible to use the fmt::RadixFmt 158 | // machinery for a custom type. 159 | pub fn to_str_radix(&self, base: u8) -> String { 160 | unsafe { 161 | // Extra two bytes are for possible minus sign and null terminator 162 | let len = __gmpz_sizeinbase(&self.mpz, base as c_int) as usize + 2; 163 | 164 | // Allocate and write into a raw *c_char of the correct length 165 | let mut vector: Vec = Vec::with_capacity(len); 166 | vector.set_len(len); 167 | 168 | __gmpz_get_str(vector.as_mut_ptr() as *mut _, base as c_int, &self.mpz); 169 | 170 | let mut first_nul = None; 171 | let mut index : usize = 0; 172 | for elem in &vector { 173 | if *elem == 0 { 174 | first_nul = Some(index); 175 | break; 176 | } 177 | index += 1; 178 | } 179 | let first_nul = first_nul.unwrap_or(len); 180 | 181 | vector.truncate(first_nul); 182 | match String::from_utf8(vector) { 183 | Ok(s) => s, 184 | Err(_) => panic!("GMP returned invalid UTF-8!") 185 | } 186 | } 187 | } 188 | 189 | pub fn from_str_radix(s: &str, base: u8) -> Result { 190 | let s = CString::new(s.to_string()).map_err(|_| ParseMpzError { _priv: () })?; 191 | unsafe { 192 | assert!(base == 0 || (base >= 2 && base <= 62)); 193 | let mut mpz = uninitialized(); 194 | let r = __gmpz_init_set_str(&mut mpz, s.as_ptr(), base as c_int); 195 | if r == 0 { 196 | Ok(Mpz { mpz: mpz }) 197 | } else { 198 | __gmpz_clear(&mut mpz); 199 | Err(ParseMpzError { _priv: () }) 200 | } 201 | } 202 | } 203 | 204 | pub fn set(&mut self, other: &Mpz) { 205 | unsafe { __gmpz_set(&mut self.mpz, &other.mpz) } 206 | } 207 | 208 | // TODO: too easy to forget to check this return value - rename? 209 | pub fn set_from_str_radix(&mut self, s: &str, base: u8) -> bool { 210 | assert!(base == 0 || (base >= 2 && base <= 62)); 211 | let s = CString::new(s.to_string()).unwrap(); 212 | unsafe { __gmpz_set_str(&mut self.mpz, s.as_ptr(), base as c_int) == 0 } 213 | } 214 | 215 | pub fn bit_length(&self) -> usize { 216 | unsafe { __gmpz_sizeinbase(&self.mpz, 2) as usize } 217 | } 218 | 219 | pub fn compl(&self) -> Mpz { 220 | unsafe { 221 | let mut res = Mpz::new(); 222 | __gmpz_com(&mut res.mpz, &self.mpz); 223 | res 224 | } 225 | } 226 | 227 | pub fn abs(&self) -> Mpz { 228 | unsafe { 229 | let mut res = Mpz::new(); 230 | __gmpz_abs(&mut res.mpz, &self.mpz); 231 | res 232 | } 233 | } 234 | 235 | pub fn div_floor(&self, other: &Mpz) -> Mpz { 236 | unsafe { 237 | if other.is_zero() { 238 | panic!("divide by zero") 239 | } 240 | 241 | let mut res = Mpz::new(); 242 | __gmpz_fdiv_q(&mut res.mpz, &self.mpz, &other.mpz); 243 | res 244 | } 245 | } 246 | 247 | pub fn mod_floor(&self, other: &Mpz) -> Mpz { 248 | unsafe { 249 | if other.is_zero() { 250 | panic!("divide by zero") 251 | } 252 | 253 | let mut res = Mpz::new(); 254 | __gmpz_fdiv_r(&mut res.mpz, &self.mpz, &other.mpz); 255 | res 256 | } 257 | } 258 | 259 | /// Determine whether n is prime. 260 | /// 261 | /// This function performs some trial divisions, then reps Miller-Rabin probabilistic primality tests. A higher reps value will reduce the chances of a non-prime being identified as “probably prime”. A composite number will be identified as a prime with a probability of less than 4^(-reps). Reasonable values of reps are between 15 and 50. 262 | pub fn probab_prime(&self, reps: i32) -> ProbabPrimeResult { 263 | match unsafe { 264 | __gmpz_probab_prime_p(&self.mpz, reps as c_int) as u8 265 | } { 266 | 2 => ProbabPrimeResult::Prime, 267 | 1 => ProbabPrimeResult::ProbablyPrime, 268 | 0 => ProbabPrimeResult::NotPrime, 269 | x => panic!("Undocumented return value {} from __gmpz_probab_prime_p", x), 270 | } 271 | } 272 | 273 | pub fn nextprime(&self) -> Mpz { 274 | unsafe { 275 | let mut res = Mpz::new(); 276 | __gmpz_nextprime(&mut res.mpz, &self.mpz); 277 | res 278 | } 279 | } 280 | 281 | pub fn gcd(&self, other: &Mpz) -> Mpz { 282 | unsafe { 283 | let mut res = Mpz::new(); 284 | __gmpz_gcd(&mut res.mpz, &self.mpz, &other.mpz); 285 | res 286 | } 287 | } 288 | 289 | /// Given (a, b), return (g, s, t) such that g = gcd(a, b) = s*a + t*b. 290 | pub fn gcdext(&self, other: &Mpz) -> (Mpz, Mpz, Mpz) { 291 | unsafe { 292 | let mut g = Mpz::new(); 293 | let mut s = Mpz::new(); 294 | let mut t = Mpz::new(); 295 | __gmpz_gcdext(&mut g.mpz, &mut s.mpz, &mut t.mpz, 296 | &self.mpz, &other.mpz); 297 | (g, s, t) 298 | } 299 | } 300 | 301 | pub fn lcm(&self, other: &Mpz) -> Mpz { 302 | unsafe { 303 | let mut res = Mpz::new(); 304 | __gmpz_lcm(&mut res.mpz, &self.mpz, &other.mpz); 305 | res 306 | } 307 | } 308 | 309 | pub fn is_multiple_of(&self, other: &Mpz) -> bool { 310 | unsafe { 311 | __gmpz_divisible_p(&self.mpz, &other.mpz) != 0 312 | } 313 | } 314 | 315 | #[inline] 316 | pub fn divides(&self, other: &Mpz) -> bool { 317 | other.is_multiple_of(self) 318 | } 319 | 320 | pub fn modulus(&self, modulo: &Mpz) -> Mpz { 321 | unsafe { 322 | if modulo.is_zero() { 323 | panic!("divide by zero") 324 | } 325 | 326 | let mut res = Mpz::new(); 327 | __gmpz_mod(&mut res.mpz, &self.mpz, &modulo.mpz); 328 | res 329 | } 330 | } 331 | 332 | // TODO: handle a zero modulo 333 | pub fn invert(&self, modulo: &Mpz) -> Option { 334 | unsafe { 335 | let mut res = Mpz::new(); 336 | if __gmpz_invert(&mut res.mpz, &self.mpz, &modulo.mpz) == 0 { 337 | None 338 | } else { 339 | Some(res) 340 | } 341 | } 342 | } 343 | 344 | pub fn popcount(&self) -> usize { 345 | unsafe { __gmpz_popcount(&self.mpz) as usize } 346 | } 347 | 348 | pub fn pow(&self, exp: u32) -> Mpz { 349 | unsafe { 350 | let mut res = Mpz::new(); 351 | __gmpz_pow_ui(&mut res.mpz, &self.mpz, exp as c_ulong); 352 | res 353 | } 354 | } 355 | 356 | pub fn powm(&self, exp: &Mpz, modulus: &Mpz) -> Mpz { 357 | unsafe { 358 | let mut res = Mpz::new(); 359 | __gmpz_powm(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz); 360 | res 361 | } 362 | } 363 | 364 | pub fn powm_sec(&self, exp: &Mpz, modulus: &Mpz) -> Mpz { 365 | unsafe { 366 | let mut res = Mpz::new(); 367 | __gmpz_powm_sec(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz); 368 | res 369 | } 370 | } 371 | 372 | pub fn ui_pow_ui(x: u32, y: u32) -> Mpz { 373 | unsafe { 374 | let mut res = Mpz::new(); 375 | __gmpz_ui_pow_ui(&mut res.mpz, x as c_ulong, y as c_ulong); 376 | res 377 | } 378 | } 379 | 380 | pub fn hamdist(&self, other: &Mpz) -> usize { 381 | unsafe { __gmpz_hamdist(&self.mpz, &other.mpz) as usize } 382 | } 383 | 384 | pub fn setbit(&mut self, bit_index: usize) { 385 | unsafe { __gmpz_setbit(&mut self.mpz, bit_index as c_ulong) } 386 | } 387 | 388 | pub fn clrbit(&mut self, bit_index: usize) { 389 | unsafe { __gmpz_clrbit(&mut self.mpz, bit_index as c_ulong) } 390 | } 391 | 392 | pub fn combit(&mut self, bit_index: usize) { 393 | unsafe { __gmpz_combit(&mut self.mpz, bit_index as c_ulong) } 394 | } 395 | 396 | pub fn tstbit(&self, bit_index: usize) -> bool { 397 | unsafe { __gmpz_tstbit(&self.mpz, bit_index as c_ulong) == 1 } 398 | } 399 | 400 | pub fn root(&self, n: u32) -> Mpz { 401 | assert!(self.mpz._mp_size >= 0); 402 | unsafe { 403 | let mut res = Mpz::new(); 404 | let _perfect_root 405 | = match __gmpz_root(&mut res.mpz, &self.mpz, n as c_ulong) { 406 | 0 => false, 407 | _ => true, 408 | }; 409 | // TODO: consider returning `_perfect_root` 410 | res 411 | } 412 | } 413 | 414 | pub fn sqrt(&self) -> Mpz { 415 | assert!(self.mpz._mp_size >= 0); 416 | unsafe { 417 | let mut res = Mpz::new(); 418 | __gmpz_sqrt(&mut res.mpz, &self.mpz); 419 | res 420 | } 421 | } 422 | 423 | pub fn millerrabin(&self, reps: i32) -> i32 { 424 | unsafe { 425 | __gmpz_millerrabin(&self.mpz, reps as c_int) 426 | } 427 | } 428 | 429 | pub fn sign(&self) -> Sign { 430 | let size = self.mpz._mp_size; 431 | if size == 0 { 432 | Sign::Zero 433 | } else if size > 0 { 434 | Sign::Positive 435 | } else { 436 | Sign::Negative 437 | } 438 | } 439 | 440 | pub fn one() -> Mpz { 441 | unsafe { 442 | let mut mpz = uninitialized(); 443 | __gmpz_init_set_ui(&mut mpz, 1); 444 | Mpz { mpz: mpz } 445 | } 446 | } 447 | 448 | pub fn zero() -> Mpz { Mpz::new() } 449 | 450 | pub fn is_zero(&self) -> bool { 451 | self.mpz._mp_size == 0 452 | } 453 | } 454 | 455 | #[derive(Debug)] 456 | pub struct ParseMpzError { 457 | _priv: () 458 | } 459 | 460 | impl fmt::Display for ParseMpzError { 461 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 462 | self.description().fmt(f) 463 | } 464 | } 465 | 466 | impl Error for ParseMpzError { 467 | fn description(&self) -> &'static str { 468 | "invalid integer" 469 | } 470 | 471 | fn cause(&self) -> Option<&'static Error> { 472 | None 473 | } 474 | } 475 | 476 | impl Clone for Mpz { 477 | fn clone(&self) -> Mpz { 478 | unsafe { 479 | let mut mpz = uninitialized(); 480 | __gmpz_init_set(&mut mpz, &self.mpz); 481 | Mpz { mpz: mpz } 482 | } 483 | } 484 | } 485 | 486 | impl Eq for Mpz { } 487 | 488 | impl PartialEq for Mpz { 489 | fn eq(&self, other: &Mpz) -> bool { 490 | unsafe { __gmpz_cmp(&self.mpz, &other.mpz) == 0 } 491 | } 492 | } 493 | 494 | impl Ord for Mpz { 495 | fn cmp(&self, other: &Mpz) -> Ordering { 496 | let cmp = unsafe { __gmpz_cmp(&self.mpz, &other.mpz) }; 497 | if cmp == 0 { 498 | Equal 499 | } else if cmp < 0 { 500 | Less 501 | } else { 502 | Greater 503 | } 504 | } 505 | } 506 | 507 | impl PartialOrd for Mpz { 508 | fn partial_cmp(&self, other: &Mpz) -> Option { 509 | Some(self.cmp(other)) 510 | } 511 | } 512 | 513 | // Implementation of operators 514 | 515 | // This macro inserts a guard against division by 0 for Div and Rem implementations 516 | macro_rules! div_guard { 517 | (Div, $is_zero: expr) => { 518 | if $is_zero { 519 | panic!("divide by zero") 520 | } 521 | }; 522 | (Rem, $is_zero: expr) => { 523 | if $is_zero { 524 | panic!("divide by zero") 525 | } 526 | }; 527 | ($tr: ident, $is_zero: expr) => {} 528 | } 529 | 530 | // On Windows c_long and c_ulong are only 32-bit - in order to implement operations for 531 | // 64-bit types we need some workarounds 532 | macro_rules! bit_guard { 533 | (u64, $what: ident, $e1: expr, $e2: expr) => ( 534 | if size_of::() == 8 || $what <= u32::MAX as u64 { 535 | $e1 536 | } 537 | else { 538 | $e2 539 | } 540 | ); 541 | 542 | (i64, $what: ident, $e1: expr, $e2: expr) => ( 543 | if size_of::() == 8 || $what <= i32::MAX as i64 { 544 | $e1 545 | } 546 | else { 547 | $e2 548 | } 549 | ); 550 | 551 | (u32, $what: ident, $e1: expr, $e2: expr) => ($e1); 552 | 553 | (i32, $what: ident, $e1: expr, $e2: expr) => ($e1); 554 | } 555 | 556 | macro_rules! impl_oper { 557 | ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { 558 | impl $tr for Mpz { 559 | type Output = Mpz; 560 | #[inline] 561 | fn $meth(self, other: Mpz) -> Mpz { 562 | self.$meth(&other) 563 | } 564 | } 565 | 566 | impl<'a> $tr<&'a Mpz> for Mpz { 567 | type Output = Mpz; 568 | #[inline] 569 | fn $meth(mut self, other: &Mpz) -> Mpz { 570 | self.$meth_assign(other); 571 | self 572 | } 573 | } 574 | 575 | impl<'a> $tr for &'a Mpz { 576 | type Output = Mpz; 577 | #[inline] 578 | fn $meth(self, mut other: Mpz) -> Mpz { 579 | unsafe { 580 | div_guard!($tr, other.is_zero()); 581 | $fun(&mut other.mpz, &self.mpz, &other.mpz); 582 | other 583 | } 584 | } 585 | } 586 | 587 | impl<'a, 'b> $tr<&'b Mpz> for &'a Mpz { 588 | type Output = Mpz; 589 | fn $meth(self, other: &Mpz) -> Mpz { 590 | unsafe { 591 | div_guard!($tr, other.is_zero()); 592 | let mut res = Mpz::new(); 593 | $fun(&mut res.mpz, &self.mpz, &other.mpz); 594 | res 595 | } 596 | } 597 | } 598 | 599 | impl $tr_assign for Mpz { 600 | #[inline] 601 | fn $meth_assign(&mut self, other: Mpz) { 602 | self.$meth_assign(&other) 603 | } 604 | } 605 | 606 | impl<'a> $tr_assign<&'a Mpz> for Mpz { 607 | #[inline] 608 | fn $meth_assign(&mut self, other: &Mpz) { 609 | unsafe { 610 | div_guard!($tr, other.is_zero()); 611 | $fun(&mut self.mpz, &self.mpz, &other.mpz); 612 | } 613 | } 614 | } 615 | }; 616 | 617 | (both $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { 618 | impl_oper!(normal $num, $cnum, $tr, $meth, $tr_assign, $meth_assign, $fun); 619 | 620 | impl $tr for $num { 621 | type Output = Mpz; 622 | #[inline] 623 | fn $meth(self, mut other: Mpz) -> Mpz { 624 | unsafe { 625 | bit_guard!($num, self, { 626 | $fun(&mut other.mpz, &other.mpz, self as $cnum); 627 | other 628 | }, other.$meth(Mpz::from(self))) 629 | } 630 | } 631 | } 632 | 633 | impl<'a> $tr<&'a Mpz> for $num { 634 | type Output = Mpz; 635 | fn $meth(self, other: &'a Mpz) -> Mpz { 636 | unsafe { 637 | bit_guard!($num, self, { 638 | let mut res = Mpz::new(); 639 | $fun(&mut res.mpz, &other.mpz, self as $cnum); 640 | res 641 | }, other.$meth(Mpz::from(self))) 642 | } 643 | } 644 | } 645 | }; 646 | 647 | (normal $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { 648 | impl $tr<$num> for Mpz { 649 | type Output = Mpz; 650 | #[inline] 651 | fn $meth(mut self, other: $num) -> Mpz { 652 | self.$meth_assign(other); 653 | self 654 | } 655 | } 656 | 657 | impl<'a> $tr<$num> for &'a Mpz { 658 | type Output = Mpz; 659 | fn $meth(self, other: $num) -> Mpz { 660 | unsafe { 661 | div_guard!($tr, other == 0); 662 | bit_guard!($num, other, { 663 | let mut res = Mpz::new(); 664 | $fun(&mut res.mpz, &self.mpz, other as $cnum); 665 | res 666 | }, self.$meth(Mpz::from(other))) 667 | } 668 | } 669 | } 670 | 671 | impl $tr_assign<$num> for Mpz { 672 | #[inline] 673 | fn $meth_assign(&mut self, other: $num) { 674 | unsafe { 675 | div_guard!($tr, other == 0); 676 | bit_guard!($num, other, 677 | $fun(&mut self.mpz, &self.mpz, other as $cnum), 678 | self.$meth_assign(Mpz::from(other))) 679 | } 680 | } 681 | } 682 | }; 683 | 684 | (reverse $num: ident, $cnum: ident, $tr: ident, $meth: ident, $fun: ident) => { 685 | impl $tr for $num { 686 | type Output = Mpz; 687 | #[inline] 688 | fn $meth(self, mut other: Mpz) -> Mpz { 689 | unsafe { 690 | bit_guard!($num, self, { 691 | $fun(&mut other.mpz, self as $cnum, &other.mpz); 692 | other 693 | }, Mpz::from(self).$meth(other)) 694 | } 695 | } 696 | } 697 | 698 | impl<'a> $tr<&'a Mpz> for $num { 699 | type Output = Mpz; 700 | fn $meth(self, other: &'a Mpz) -> Mpz { 701 | unsafe { 702 | bit_guard!($num, self, { 703 | let mut res = Mpz::new(); 704 | $fun(&mut res.mpz, self as $cnum, &other.mpz); 705 | res 706 | }, Mpz::from(self).$meth(other)) 707 | } 708 | } 709 | } 710 | }; 711 | 712 | } 713 | 714 | impl_oper!(Add, add, AddAssign, add_assign, __gmpz_add); 715 | impl_oper!(both u64, c_ulong, Add, add, AddAssign, add_assign, __gmpz_add_ui); 716 | 717 | impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpz_sub); 718 | impl_oper!(normal u64, c_ulong, Sub, sub, SubAssign, sub_assign, __gmpz_sub_ui); 719 | impl_oper!(reverse u64, c_ulong, Sub, sub, __gmpz_ui_sub); 720 | 721 | impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpz_mul); 722 | impl_oper!(both i64, c_long, Mul, mul, MulAssign, mul_assign, __gmpz_mul_si); 723 | impl_oper!(both u64, c_ulong, Mul, mul, MulAssign, mul_assign, __gmpz_mul_ui); 724 | 725 | impl_oper!(Div, div, DivAssign, div_assign, __gmpz_tdiv_q); 726 | impl_oper!(normal u64, c_ulong, Div, div, DivAssign, div_assign, __gmpz_tdiv_q_ui); 727 | 728 | impl_oper!(Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r); 729 | impl_oper!(normal u64, c_ulong, Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r_ui); 730 | 731 | impl<'b> Neg for &'b Mpz { 732 | type Output = Mpz; 733 | fn neg(self) -> Mpz { 734 | unsafe { 735 | let mut res = Mpz::new(); 736 | __gmpz_neg(&mut res.mpz, &self.mpz); 737 | res 738 | } 739 | } 740 | } 741 | 742 | impl Neg for Mpz { 743 | type Output = Mpz; 744 | #[inline] 745 | fn neg(mut self) -> Mpz { 746 | unsafe { 747 | __gmpz_neg(&mut self.mpz, &self.mpz); 748 | self 749 | } 750 | } 751 | } 752 | 753 | impl<'b> Not for &'b Mpz { 754 | type Output = Mpz; 755 | fn not(self) -> Mpz { 756 | unsafe { 757 | let mut res = Mpz::new(); 758 | __gmpz_com(&mut res.mpz, &self.mpz); 759 | res 760 | } 761 | } 762 | } 763 | 764 | impl Not for Mpz { 765 | type Output = Mpz; 766 | #[inline] 767 | fn not(mut self) -> Mpz { 768 | unsafe { 769 | __gmpz_com(&mut self.mpz, &self.mpz); 770 | self 771 | } 772 | } 773 | } 774 | 775 | // Similarly to mpz_export, this does not preserve the sign of the input. 776 | impl<'b> From<&'b Mpz> for Vec { 777 | fn from(other: &Mpz) -> Vec { 778 | unsafe { 779 | let bit_size = size_of::() * 8; 780 | let size = (__gmpz_sizeinbase(&other.mpz, 2) + bit_size - 1) / bit_size; 781 | let mut result: Vec = vec!(0; size); 782 | __gmpz_export(result.as_mut_ptr() as *mut c_void, 0 as *mut size_t, 1, size_of::() as size_t, 0, 0, &other.mpz); 783 | result 784 | } 785 | } 786 | } 787 | 788 | impl<'b> From<&'b Mpz> for Option { 789 | fn from(other: &Mpz) -> Option { 790 | unsafe { 791 | let negative = other.mpz._mp_size < 0; 792 | let mut to_export = Mpz::new(); 793 | 794 | if negative { 795 | __gmpz_com(&mut to_export.mpz, &other.mpz); 796 | } else { 797 | __gmpz_set(&mut to_export.mpz, &other.mpz); 798 | } 799 | 800 | if __gmpz_sizeinbase(&to_export.mpz, 2) <= 63 { 801 | let mut result : i64 = 0; 802 | __gmpz_export(&mut result as *mut i64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &to_export.mpz); 803 | if negative { 804 | Some(result ^ -1i64) 805 | } else { 806 | Some(result) 807 | } 808 | } else { 809 | return None; 810 | } 811 | } 812 | } 813 | } 814 | 815 | impl<'b> From<&'b Mpz> for Option { 816 | fn from(other: &Mpz) -> Option { 817 | unsafe { 818 | if __gmpz_sizeinbase(&other.mpz, 2) <= 64 && other.mpz._mp_size >= 0 { 819 | let mut result : u64 = 0; 820 | __gmpz_export(&mut result as *mut u64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &other.mpz); 821 | Some(result) 822 | } else { 823 | None 824 | } 825 | } 826 | } 827 | } 828 | 829 | impl<'a> From<&'a Mpz> for f64 { 830 | fn from(other: &Mpz) -> f64 { 831 | unsafe { 832 | __gmpz_get_d(&other.mpz) as f64 833 | } 834 | } 835 | } 836 | 837 | impl<'a> From<&'a [u8]> for Mpz { 838 | fn from(other: &'a [u8]) -> Mpz { 839 | unsafe { 840 | let mut res = Mpz::new(); 841 | __gmpz_import(&mut res.mpz, other.len(), 1, size_of::() as size_t, 842 | 0, 0, other.as_ptr() as *const c_void); 843 | res 844 | } 845 | } 846 | } 847 | 848 | impl From for Mpz { 849 | fn from(other: u64) -> Mpz { 850 | unsafe { 851 | let mut res = Mpz::new(); 852 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 853 | &other as *const u64 as *const c_void); 854 | res 855 | } 856 | } 857 | } 858 | 859 | impl From for Mpz { 860 | fn from(other: u32) -> Mpz { 861 | unsafe { 862 | let mut res = Mpz::new(); 863 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 864 | &other as *const u32 as *const c_void); 865 | res 866 | } 867 | } 868 | } 869 | 870 | impl From for Mpz { 871 | fn from(other: i64) -> Mpz { 872 | unsafe { 873 | let mut res = Mpz::new(); 874 | 875 | if other.is_negative() { 876 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 877 | &(other ^ -1i64) as *const i64 as *const c_void); 878 | __gmpz_com(&mut res.mpz, &res.mpz); 879 | } else { 880 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 881 | &other as *const i64 as *const c_void); 882 | } 883 | res 884 | } 885 | } 886 | } 887 | 888 | impl From for Mpz { 889 | fn from(other: i32) -> Mpz { 890 | unsafe { 891 | let mut res = Mpz::new(); 892 | 893 | if other.is_negative() { 894 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 895 | &(other ^ -1i32) as *const i32 as *const c_void); 896 | __gmpz_com(&mut res.mpz, &res.mpz); 897 | } else { 898 | __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, 899 | &other as *const i32 as *const c_void); 900 | } 901 | res 902 | } 903 | } 904 | } 905 | 906 | impl_oper!(BitAnd, bitand, BitAndAssign, bitand_assign, __gmpz_and); 907 | impl_oper!(BitOr, bitor, BitOrAssign, bitor_assign, __gmpz_ior); 908 | impl_oper!(BitXor, bitxor, BitXorAssign, bitxor_assign, __gmpz_xor); 909 | 910 | impl<'b> Shl for &'b Mpz { 911 | type Output = Mpz; 912 | fn shl(self, other: usize) -> Mpz { 913 | unsafe { 914 | let mut res = Mpz::new(); 915 | __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong); 916 | res 917 | } 918 | } 919 | } 920 | 921 | impl<'b> Shr for &'b Mpz { 922 | type Output = Mpz; 923 | fn shr(self, other: usize) -> Mpz { 924 | unsafe { 925 | let mut res = Mpz::new(); 926 | __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong); 927 | res 928 | } 929 | } 930 | } 931 | 932 | impl Shl for Mpz { 933 | type Output = Mpz; 934 | fn shl(self, other: usize) -> Mpz { 935 | unsafe { 936 | let mut res = Mpz::new(); 937 | __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong); 938 | res 939 | } 940 | } 941 | } 942 | 943 | impl Shr for Mpz { 944 | type Output = Mpz; 945 | fn shr(self, other: usize) -> Mpz { 946 | unsafe { 947 | let mut res = Mpz::new(); 948 | __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong); 949 | res 950 | } 951 | } 952 | } 953 | 954 | impl ShlAssign for Mpz { 955 | fn shl_assign(&mut self, other: usize) { 956 | unsafe { 957 | __gmpz_mul_2exp(&mut self.mpz, &self.mpz, other as c_ulong); 958 | } 959 | } 960 | } 961 | 962 | impl ShrAssign for Mpz { 963 | fn shr_assign(&mut self, other: usize) { 964 | unsafe { 965 | __gmpz_fdiv_q_2exp(&mut self.mpz, &self.mpz, other as c_ulong); 966 | } 967 | } 968 | } 969 | 970 | impl FromStr for Mpz { 971 | type Err = ParseMpzError; 972 | fn from_str(s: &str) -> Result { 973 | Mpz::from_str_radix(s, 10) 974 | } 975 | } 976 | 977 | impl fmt::Display for Mpz { 978 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 979 | write!(f, "{}", self.to_str_radix(10)) 980 | } 981 | } 982 | 983 | impl fmt::Debug for Mpz { 984 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 985 | write!(f, "{}", self.to_str_radix(10)) 986 | } 987 | } 988 | 989 | impl hash::Hash for Mpz { 990 | fn hash(&self, state: &mut S) { 991 | unsafe { 992 | for i in 0..self.mpz._mp_size.abs() { 993 | let limb = self.mpz._mp_d as *const mp_limb_t; 994 | let limb = *(limb.offset(i as isize)); 995 | limb.hash(state); 996 | } 997 | } 998 | } 999 | } 1000 | 1001 | impl Zero for Mpz { 1002 | #[inline] 1003 | fn zero() -> Mpz { 1004 | Mpz::zero() 1005 | } 1006 | 1007 | #[inline] 1008 | fn is_zero(&self) -> bool { 1009 | self.is_zero() 1010 | } 1011 | } 1012 | 1013 | impl One for Mpz { 1014 | #[inline] 1015 | fn one() -> Mpz { 1016 | Mpz::one() 1017 | } 1018 | } 1019 | 1020 | -------------------------------------------------------------------------------- /src/rand.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_int, c_ulong, c_void}; 2 | use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr, mp_bitcnt_t}; 3 | use std::mem::uninitialized; 4 | 5 | #[repr(C)] 6 | pub struct gmp_randstate_struct { 7 | _mp_seed: mpz_struct, 8 | _mp_alg: c_int, 9 | _mp_algdata: *const c_void 10 | } 11 | 12 | pub type gmp_randstate_t = *mut gmp_randstate_struct; 13 | 14 | #[link(name = "gmp")] 15 | extern "C" { 16 | fn __gmp_randinit_default(state: gmp_randstate_t); 17 | fn __gmp_randinit_mt(state: gmp_randstate_t); 18 | fn __gmp_randinit_lc_2exp(state: gmp_randstate_t, a: mpz_srcptr, c: c_ulong, m2exp: mp_bitcnt_t); 19 | fn __gmp_randinit_lc_2exp_size(state: gmp_randstate_t, size: mp_bitcnt_t); 20 | fn __gmp_randinit_set(state: gmp_randstate_t, op: *const gmp_randstate_struct); 21 | fn __gmp_randclear(state: gmp_randstate_t); 22 | fn __gmp_randseed(state: gmp_randstate_t, seed: mpz_srcptr); 23 | fn __gmp_randseed_ui(state: gmp_randstate_t, seed: c_ulong); 24 | fn __gmpz_urandomb(rop: mpz_ptr, state: gmp_randstate_t, n: mp_bitcnt_t); 25 | fn __gmpz_urandomm(rop: mpz_ptr, state: gmp_randstate_t, n: mpz_srcptr); 26 | } 27 | 28 | pub struct RandState { 29 | state: gmp_randstate_struct, 30 | } 31 | 32 | unsafe impl Send for RandState { } 33 | unsafe impl Sync for RandState { } 34 | 35 | impl Drop for RandState { 36 | fn drop(&mut self) { 37 | unsafe { __gmp_randclear(&mut self.state) } 38 | } 39 | } 40 | 41 | impl RandState { 42 | pub fn new() -> RandState { 43 | unsafe { 44 | let mut state: gmp_randstate_struct = uninitialized(); 45 | __gmp_randinit_default(&mut state); 46 | RandState { state: state } 47 | } 48 | } 49 | 50 | pub fn new_mt() -> RandState { 51 | unsafe { 52 | let mut state: gmp_randstate_struct = uninitialized(); 53 | __gmp_randinit_mt(&mut state); 54 | RandState { state: state } 55 | } 56 | } 57 | 58 | pub fn new_lc_2exp(a: Mpz, c: u64, m2exp: u64) -> RandState { 59 | unsafe { 60 | let mut state: gmp_randstate_struct = uninitialized(); 61 | __gmp_randinit_lc_2exp(&mut state, a.inner(), c as c_ulong, m2exp as c_ulong); 62 | RandState { state: state } 63 | } 64 | } 65 | 66 | pub fn new_lc_2exp_size(size: u64) -> RandState { 67 | unsafe { 68 | let mut state: gmp_randstate_struct = uninitialized(); 69 | __gmp_randinit_lc_2exp_size(&mut state, size as c_ulong); 70 | RandState { state: state } 71 | } 72 | } 73 | 74 | pub fn seed(&mut self, seed: Mpz) { 75 | unsafe { __gmp_randseed(&mut self.state, seed.inner()) } 76 | } 77 | 78 | pub fn seed_ui(&mut self, seed: u64) { 79 | unsafe { __gmp_randseed_ui(&mut self.state, seed as c_ulong) } 80 | } 81 | 82 | /// Generate a uniform random integer in the range 0 to n-1, inclusive 83 | pub fn urandom(&mut self, n: &Mpz) -> Mpz { 84 | unsafe { 85 | let mut res = Mpz::new(); 86 | __gmpz_urandomm(res.inner_mut(), &mut self.state, n.inner()); 87 | res 88 | } 89 | } 90 | 91 | /// Generate a uniformly distributed random integer in the range 0 to 2^n−1, inclusive. 92 | pub fn urandom_2exp(&mut self, n: u64) -> Mpz { 93 | unsafe { 94 | let mut res = Mpz::new(); 95 | __gmpz_urandomb(res.inner_mut(), &mut self.state, n as c_ulong); 96 | res 97 | } 98 | } 99 | } 100 | 101 | impl Clone for RandState { 102 | fn clone(&self) -> RandState { 103 | unsafe { 104 | let mut state: gmp_randstate_struct = uninitialized(); 105 | __gmp_randinit_set(&mut state, &self.state); 106 | RandState { state: state } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/sign.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)] 2 | pub enum Sign { 3 | Negative, 4 | Zero, 5 | Positive, 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test.rs: -------------------------------------------------------------------------------- 1 | use super::mpz::mp_limb_t; 2 | use std; 3 | use libc::c_int; 4 | 5 | #[link(name = "gmp")] 6 | extern "C" { 7 | static __gmp_bits_per_limb: c_int; 8 | } 9 | 10 | #[test] 11 | fn test_limb_size() { 12 | // We are assuming that the limb size is the same as the pointer size. 13 | assert_eq!(std::mem::size_of::() * 8, 14 | unsafe { __gmp_bits_per_limb as usize }); 15 | } 16 | 17 | mod mpz { 18 | use super::super::mpz::Mpz; 19 | use super::super::mpz::ProbabPrimeResult; 20 | use super::super::sign::Sign; 21 | use std::str::FromStr; 22 | use std::convert::{From, Into}; 23 | use std::{i64, u64}; 24 | 25 | use std::hash::{Hash, Hasher}; 26 | use std::collections::hash_map::DefaultHasher; 27 | 28 | #[test] 29 | fn test_set() { 30 | let mut x: Mpz = From::::from(1000); 31 | let y: Mpz = From::::from(5000); 32 | assert!(x != y); 33 | x.set(&y); 34 | assert!(x == y); 35 | } 36 | 37 | #[test] 38 | fn test_set_from_str_radix() { 39 | let mut x: Mpz = From::::from(1000); 40 | let y: Mpz = From::::from(5000); 41 | assert!(x != y); 42 | assert!(x.set_from_str_radix("5000", 10)); 43 | assert!(x == y); 44 | assert!(!x.set_from_str_radix("aaaa", 2)); 45 | } 46 | 47 | #[test] 48 | #[should_panic] 49 | fn test_from_str_radix_lower_bound() { 50 | let _ = Mpz::from_str_radix("", 1); 51 | } 52 | 53 | #[test] 54 | #[should_panic] 55 | fn test_from_str_radix_upper_bound() { 56 | let _ = Mpz::from_str_radix("", 63); 57 | } 58 | 59 | #[test] 60 | #[should_panic] 61 | fn test_set_from_str_radix_lower_bound() { 62 | let mut x = Mpz::new(); 63 | x.set_from_str_radix("", 1); 64 | } 65 | 66 | #[test] 67 | #[should_panic] 68 | fn test_set_from_str_radix_upper_bound() { 69 | let mut x = Mpz::new(); 70 | x.set_from_str_radix("", 63); 71 | } 72 | 73 | #[test] 74 | fn test_eq() { 75 | let x: Mpz = From::::from(4242142195); 76 | let y: Mpz = From::::from(4242142195); 77 | let z: Mpz = From::::from(4242142196); 78 | 79 | assert!(x == y); 80 | assert!(x != z); 81 | assert!(y != z); 82 | } 83 | 84 | #[test] 85 | fn test_ord() { 86 | let x: Mpz = FromStr::from_str("40000000000000000000000").unwrap(); 87 | let y: Mpz = FromStr::from_str("45000000000000000000000").unwrap(); 88 | let z: Mpz = FromStr::from_str("50000000000000000000000").unwrap(); 89 | 90 | assert!(x < y && x < z && y < z); 91 | assert!(x <= x && x <= y && x <= z && y <= z); 92 | assert!(z > y && z > x && y > x); 93 | assert!(z >= z && z >= y && z >= x && y >= x); 94 | } 95 | 96 | #[test] 97 | #[should_panic] 98 | fn test_div_zero() { 99 | let x: Mpz = From::::from(1); 100 | let y = Mpz::new(); 101 | x / y; 102 | } 103 | 104 | #[test] 105 | #[should_panic] 106 | fn test_rem_zero() { 107 | let x: Mpz = From::::from(1); 108 | let y = Mpz::new(); 109 | x % y; 110 | } 111 | 112 | #[test] 113 | fn test_div_round() { 114 | let x: Mpz = From::::from(2); 115 | let y: Mpz = From::::from(3); 116 | assert!((&x / &y).to_string() == (2i32 / 3).to_string()); 117 | assert!((&x / -&y).to_string() == (2i32 / -3).to_string()); 118 | } 119 | 120 | #[test] 121 | fn test_rem() { 122 | let x: Mpz = From::::from(20); 123 | let y: Mpz = From::::from(3); 124 | assert!((&x % &y).to_string() == (20i32 % 3).to_string()); 125 | assert!((&x % 3).to_string() == (20i32 % 3).to_string()); 126 | assert!((&x % -&y).to_string() == (20i32 % -3).to_string()); 127 | assert!((-&x % &y).to_string() == (-20i32 % 3).to_string()); 128 | } 129 | 130 | #[test] 131 | fn test_add() { 132 | let x: Mpz = From::::from(2); 133 | let y: Mpz = From::::from(3); 134 | let str5 = 5i32.to_string(); 135 | assert!((&x + &y).to_string() == str5); 136 | assert!((&x + 3).to_string() == str5); 137 | assert!((&y + 2).to_string() == str5); 138 | } 139 | 140 | #[test] 141 | fn test_sub() { 142 | let x: Mpz = From::::from(2); 143 | let y: Mpz = From::::from(3); 144 | assert!((&x - &y).to_string() == (-1i32).to_string()); 145 | assert!((&y - &x).to_string() == 1i32.to_string()); 146 | assert!((&y - 8).to_string() == (-5i32).to_string()); 147 | } 148 | 149 | #[test] 150 | fn test_mul() { 151 | let x: Mpz = From::::from(2); 152 | let y: Mpz = From::::from(3); 153 | assert!((&x * &y).to_string() == 6i32.to_string()); 154 | assert!((&x * 3i64).to_string() == 6i32.to_string()); 155 | assert!((&y * -5i64).to_string() == (-15i32).to_string()); 156 | // check with values not fitting in 32 bits 157 | assert!((&x * 5000000000i64).to_string() == 10000000000i64.to_string()); 158 | } 159 | 160 | #[test] 161 | fn test_to_str_radix() { 162 | let x: Mpz = From::::from(255); 163 | assert!(x.to_str_radix(16) == "ff".to_string()); 164 | } 165 | 166 | #[test] 167 | fn test_to_string() { 168 | let x: Mpz = FromStr::from_str("1234567890").unwrap(); 169 | assert!(x.to_string() == "1234567890".to_string()); 170 | } 171 | 172 | #[test] 173 | fn test_invalid_str() { 174 | let x: Result = FromStr::from_str("foobar"); 175 | assert!(x.is_err()); 176 | } 177 | 178 | #[test] 179 | fn test_clone() { 180 | let a: Mpz = From::::from(100); 181 | let b = a.clone(); 182 | let aplusb: Mpz = From::::from(200); 183 | assert!(b == a); 184 | assert!(a + b == aplusb); 185 | } 186 | 187 | #[test] 188 | fn test_from_int() { 189 | let x: Mpz = From::::from(150); 190 | assert!(x.to_string() == "150".to_string()); 191 | assert!(x == FromStr::from_str("150").unwrap()); 192 | } 193 | 194 | #[test] 195 | fn test_from_slice_u8() { 196 | let v: Vec = vec!(255, 255); 197 | let x: Mpz = From::from(&v[..]); 198 | assert!(x.to_string() == "65535".to_string()); 199 | } 200 | 201 | #[test] 202 | fn test_abs() { 203 | let x: Mpz = From::::from(1000); 204 | let y: Mpz = From::::from(-1000); 205 | assert!(-&x == y); 206 | assert!(x == -&y); 207 | assert!(x == y.abs()); 208 | assert!(x.abs() == y.abs()); 209 | } 210 | 211 | #[test] 212 | fn test_div_floor() { 213 | let two: Mpz = From::::from(2); 214 | let eight: Mpz = From::::from(8); 215 | let minuseight: Mpz = From::::from(-8); 216 | let three: Mpz = From::::from(3); 217 | let minusthree: Mpz = From::::from(-3); 218 | assert_eq!(eight.div_floor(&three), two); 219 | assert_eq!(eight.div_floor(&minusthree), minusthree); 220 | assert_eq!(minuseight.div_floor(&three), minusthree); 221 | assert_eq!(minuseight.div_floor(&minusthree), two); 222 | } 223 | 224 | #[test] 225 | fn test_mod_floor() { 226 | let one: Mpz = From::::from(1); 227 | let minusone: Mpz = From::::from(-1); 228 | let two: Mpz = From::::from(2); 229 | let minustwo: Mpz = From::::from(-2); 230 | let three: Mpz = From::::from(3); 231 | let minusthree: Mpz = From::::from(-3); 232 | let eight: Mpz = From::::from(8); 233 | let minuseight: Mpz = From::::from(-8); 234 | assert_eq!(eight.mod_floor(&three), two); 235 | assert_eq!(eight.mod_floor(&minusthree), minusone); 236 | assert_eq!(minuseight.mod_floor(&three), one); 237 | assert_eq!(minuseight.mod_floor(&minusthree), minustwo); 238 | } 239 | 240 | #[test] 241 | fn test_bitand() { 242 | let a = 0b1001_0111; 243 | let b = 0b1100_0100; 244 | let mpza: Mpz = From::::from(a); 245 | let mpzb: Mpz = From::::from(b); 246 | let mpzres: Mpz = From::::from(a & b); 247 | assert!(mpza & mpzb == mpzres); 248 | } 249 | 250 | #[test] 251 | fn test_bitor() { 252 | let a = 0b1001_0111; 253 | let b = 0b1100_0100; 254 | let mpza: Mpz = From::::from(a); 255 | let mpzb: Mpz = From::::from(b); 256 | let mpzres: Mpz = From::::from(a | b); 257 | assert!(mpza | mpzb == mpzres); 258 | } 259 | 260 | #[test] 261 | fn test_bitxor() { 262 | let a = 0b1001_0111; 263 | let b = 0b1100_0100; 264 | let mpza: Mpz = From::::from(a); 265 | let mpzb: Mpz = From::::from(b); 266 | let mpzres: Mpz = From::::from(a ^ b); 267 | assert!(mpza ^ mpzb == mpzres); 268 | } 269 | 270 | #[test] 271 | fn test_shifts() { 272 | let i = 227; 273 | let j: Mpz = From::::from(i); 274 | assert!((i << 4).to_string() == (&j << 4).to_string()); 275 | assert!((-i << 4).to_string() == (-&j << 4).to_string()); 276 | assert!((i >> 4).to_string() == (&j >> 4).to_string()); 277 | assert!((-i >> 4).to_string() == (-&j >> 4).to_string()); 278 | } 279 | 280 | #[test] 281 | fn test_compl() { 282 | let a: Mpz = From::::from(13); 283 | let b: Mpz = From::::from(-442); 284 | assert!(a.compl().to_string() == (!13i32).to_string()); 285 | assert!(b.compl().to_string() == (!-442i32).to_string()); 286 | } 287 | 288 | #[test] 289 | fn test_pow() { 290 | let a: Mpz = From::::from(2); 291 | let b: Mpz = From::::from(8); 292 | assert!(a.pow(3) == b); 293 | assert!(Mpz::ui_pow_ui(2, 3) == b); 294 | } 295 | 296 | #[test] 297 | fn test_powm() { 298 | let a: Mpz = From::::from(13); 299 | let b: Mpz = From::::from(7); 300 | let p: Mpz = From::::from(19); 301 | let c: Mpz = From::::from(10); 302 | assert!(a.powm(&b, &p) == c); 303 | } 304 | 305 | #[test] 306 | fn test_powm_sec() { 307 | let a: Mpz = From::::from(13); 308 | let b: Mpz = From::::from(7); 309 | let p: Mpz = From::::from(19); 310 | let c: Mpz = From::::from(10); 311 | assert!(a.powm_sec(&b, &p) == c); 312 | } 313 | 314 | #[test] 315 | fn test_popcount() { 316 | Mpz::from_str_radix("1010010011", 2).unwrap().popcount() == 5; 317 | } 318 | 319 | #[test] 320 | fn test_hamdist() { 321 | let a: Mpz = From::::from(0b1011_0001); 322 | let b: Mpz = From::::from(0b0010_1011); 323 | assert!(a.hamdist(&b) == 4); 324 | } 325 | 326 | #[test] 327 | fn test_bit_length() { 328 | let a: Mpz = From::::from(0b1011_0000_0001_0000); 329 | let b: Mpz = From::::from(0b101); 330 | assert!(a.bit_length() == 16); 331 | assert!(b.bit_length() == 3); 332 | } 333 | 334 | #[test] 335 | fn test_probab_prime() { 336 | let prime: Mpz = From::::from(2); 337 | assert!(prime.probab_prime(15) == ProbabPrimeResult::Prime); 338 | 339 | let not_prime: Mpz = From::::from(4); 340 | assert!(not_prime.probab_prime(15) == ProbabPrimeResult::NotPrime); 341 | } 342 | 343 | #[test] 344 | fn test_nextprime() { 345 | let a: Mpz = From::::from(123456); 346 | let b: Mpz = From::::from(123457); 347 | assert!(a.nextprime() == b); 348 | } 349 | 350 | #[test] 351 | fn test_gcd() { 352 | let zero: Mpz = From::::from(0); 353 | let three: Mpz = From::::from(3); 354 | let six: Mpz = From::::from(6); 355 | let eighteen: Mpz = From::::from(18); 356 | let twentyfour: Mpz = From::::from(24); 357 | assert!(zero.gcd(&zero) == zero); 358 | assert!(three.gcd(&six) == three); 359 | assert!(eighteen.gcd(&twentyfour) == six); 360 | } 361 | 362 | #[test] 363 | fn test_gcdext() { 364 | let six: Mpz = From::::from(6); 365 | let eighteen: Mpz = From::::from(18); 366 | let twentyfour: Mpz = From::::from(24); 367 | let (g, s, t) = eighteen.gcdext(&twentyfour); 368 | assert!(g == six); 369 | assert!(g == s*eighteen + t*twentyfour); 370 | } 371 | 372 | #[test] 373 | fn test_lcm() { 374 | let zero: Mpz = From::::from(0); 375 | let three: Mpz = From::::from(3); 376 | let five: Mpz = From::::from(5); 377 | let six: Mpz = From::::from(6); 378 | let eighteen: Mpz = From::::from(18); 379 | let twentyfour: Mpz = From::::from(24); 380 | let seventytwo: Mpz = From::::from(72); 381 | assert!(zero.lcm(&five) == zero); 382 | assert!(five.lcm(&zero) == zero); 383 | assert!(three.lcm(&six) == six); 384 | assert!(eighteen.lcm(&twentyfour) == seventytwo); 385 | } 386 | 387 | #[test] 388 | fn test_is_multiple_of() { 389 | let two: Mpz = From::::from(2); 390 | let three: Mpz = From::::from(3); 391 | let six: Mpz = From::::from(6); 392 | assert!(six.is_multiple_of(&two)); 393 | assert!(six.is_multiple_of(&three)); 394 | assert!(!three.is_multiple_of(&two)); 395 | } 396 | 397 | #[test] 398 | fn test_modulus() { 399 | let minusone: Mpz = From::::from(-1); 400 | let two: Mpz = From::::from(2); 401 | let three: Mpz = From::::from(3); 402 | assert_eq!(two.modulus(&three), two); 403 | assert_eq!(minusone.modulus(&three), two); 404 | } 405 | 406 | #[test] 407 | fn test_invert() { 408 | let two: Mpz = From::::from(2); 409 | let three: Mpz = From::::from(3); 410 | let four: Mpz = From::::from(4); 411 | let five: Mpz = From::::from(5); 412 | let eleven: Mpz = From::::from(11); 413 | assert!(three.invert(&eleven) == Some(four.clone())); 414 | assert!(four.invert(&eleven) == Some(three.clone())); 415 | assert!(two.invert(&five) == Some(three.clone())); 416 | assert!(three.invert(&five) == Some(two.clone())); 417 | assert!(two.invert(&four).is_none()); 418 | } 419 | 420 | #[test] 421 | fn test_one() { 422 | let onea: Mpz = From::::from(1); 423 | let oneb: Mpz = From::::from(1); 424 | assert!(onea == oneb); 425 | } 426 | 427 | #[test] 428 | fn test_bit_fiddling() { 429 | let mut xs: Mpz = From::::from(0b1010_1000_0010_0011); 430 | assert!(xs.bit_length() == 16); 431 | let mut ys = [true, false, true, false, 432 | true, false, false, false, 433 | false, false, true, false, 434 | false, false, true, true]; 435 | ys.reverse(); 436 | for i in 0..xs.bit_length() { 437 | assert!(xs.tstbit(i) == ys[i]); 438 | } 439 | xs.setbit(0); 440 | ys[0] = true; 441 | xs.setbit(3); 442 | ys[3] = true; 443 | xs.clrbit(1); 444 | ys[1] = false; 445 | xs.clrbit(5); 446 | ys[5] = false; 447 | xs.combit(14); 448 | ys[14] = !ys[14]; 449 | xs.combit(15); 450 | ys[15] = !ys[15]; 451 | for i in 0..xs.bit_length() { 452 | assert!(xs.tstbit(i) == ys[i]); 453 | } 454 | } 455 | 456 | #[test] 457 | fn test_root() { 458 | let x: Mpz = From::::from(123456); 459 | let y: Mpz = From::::from(49); 460 | assert!(x.root(3) == y); 461 | } 462 | 463 | #[test] 464 | fn test_sqrt() { 465 | let x: Mpz = From::::from(567); 466 | let y: Mpz = From::::from(23); 467 | assert!(x.sqrt() == y); 468 | } 469 | 470 | #[test] 471 | fn test_hash_short() { 472 | let zero: Mpz = From::::from(0); 473 | let one: Mpz = From::::from(1); 474 | let two = &one + &one; 475 | 476 | let hash = |x : &Mpz| { 477 | let mut hasher = DefaultHasher::new(); 478 | x.hash(&mut hasher); 479 | hasher.finish() 480 | }; 481 | 482 | assert!(hash(&zero) != hash(&one)); 483 | assert_eq!(hash(&one), hash(&(&two - &one))); 484 | } 485 | 486 | #[test] 487 | fn test_hash_long() { 488 | let a = Mpz::from_str_radix("348917329847193287498312749187234192387", 10) 489 | .unwrap(); 490 | let b = Mpz::from_str_radix("348917329847193287498312749187234192386", 10) 491 | .unwrap(); 492 | let one: Mpz = From::::from(1); 493 | 494 | let hash = |x : &Mpz| { 495 | let mut hasher = DefaultHasher::new(); 496 | x.hash(&mut hasher); 497 | hasher.finish() 498 | }; 499 | 500 | assert!(hash(&a) != hash(&b)); 501 | assert_eq!(hash(&a), hash(&(&b + &one))); 502 | assert_eq!(hash(&(&a - &a)), hash(&(&one - &one))); 503 | } 504 | 505 | #[test] 506 | fn test_to_vec_u8() { 507 | let minus_five: Mpz = From::::from(-5); 508 | let minus_one: Mpz = From::::from(-1); 509 | let zero: Mpz = From::::from(0); 510 | let one: Mpz = From::::from(1); 511 | let five: Mpz = From::::from(5); 512 | let xffff: Mpz = From::::from(65535); 513 | let max_u64: Mpz = From::::from(u64::MAX); 514 | 515 | assert_eq!(Into::>::into(&minus_five), vec!(5u8)); 516 | assert_eq!(Into::>::into(&minus_one), vec!(1u8)); 517 | assert_eq!(Into::>::into(&zero), vec!(0u8)); 518 | assert_eq!(Into::>::into(&one), vec!(1u8)); 519 | assert_eq!(Into::>::into(&five), vec!(5u8)); 520 | assert_eq!(Into::>::into(&xffff), vec!(255u8, 255u8)); 521 | assert_eq!(Into::>::into(&max_u64), vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8)); 522 | } 523 | 524 | #[test] 525 | fn test_to_u64() { 526 | let minus_five: Mpz = From::::from(-5); 527 | let minus_one: Mpz = From::::from(-1); 528 | let zero: Mpz = From::::from(0); 529 | let one: Mpz = From::::from(1); 530 | let five: Mpz = From::::from(5); 531 | let max_u64: Mpz = From::::from(u64::MAX); 532 | 533 | assert_eq!(Into::>::into(&minus_five), None); 534 | assert_eq!(Into::>::into(&minus_one), None); 535 | assert_eq!(Into::>::into(&zero), Some(0u64)); 536 | assert_eq!(Into::>::into(&one), Some(1u64)); 537 | assert_eq!(Into::>::into(&five), Some(5u64)); 538 | assert_eq!(Into::>::into(&max_u64), Some(u64::MAX)); 539 | assert_eq!(Into::>::into(&(&max_u64 + &one)), None); 540 | } 541 | 542 | #[test] 543 | fn test_to_i64() { 544 | let min_i64: Mpz = From::::from(i64::MIN); 545 | let minus_five: Mpz = From::::from(-5); 546 | let minus_one: Mpz = From::::from(-1); 547 | let zero: Mpz = From::::from(0); 548 | let one: Mpz = From::::from(1); 549 | let five: Mpz = From::::from(5); 550 | let max_i64: Mpz = From::::from(i64::MAX); 551 | 552 | assert_eq!(Into::>::into(&(&min_i64 - &one)), None); 553 | assert_eq!(Into::>::into(&min_i64), Some(i64::MIN)); 554 | assert_eq!(Into::>::into(&minus_five), Some(-5i64)); 555 | assert_eq!(Into::>::into(&minus_one), Some(-1i64)); 556 | assert_eq!(Into::>::into(&zero), Some(0i64)); 557 | assert_eq!(Into::>::into(&one), Some(1i64)); 558 | assert_eq!(Into::>::into(&five), Some(5i64)); 559 | assert_eq!(Into::>::into(&max_i64), Some(i64::MAX)); 560 | assert_eq!(Into::>::into(&(&max_i64 + &one)), None); 561 | } 562 | 563 | #[test] 564 | fn test_sign() { 565 | let zero: Mpz = From::::from(0); 566 | let five: Mpz = From::::from(5); 567 | let minus_five: Mpz = From::::from(-5); 568 | 569 | assert_eq!(zero.sign(), Sign::Zero); 570 | assert_eq!(five.sign(), Sign::Positive); 571 | assert_eq!(minus_five.sign(), Sign::Negative); 572 | } 573 | } 574 | 575 | mod rand { 576 | use std::convert::From; 577 | use super::super::mpz::Mpz; 578 | use super::super::rand::RandState; 579 | 580 | #[test] 581 | fn test_randstate() { 582 | let mut state = RandState::new(); 583 | state.seed_ui(42); 584 | for _ in 1u32..1000 { 585 | for x in 1i64..10 { 586 | let upper: Mpz = From::::from(x); 587 | assert!(state.urandom(&upper) < upper); 588 | } 589 | } 590 | } 591 | } 592 | 593 | mod mpq { 594 | use std::convert::From; 595 | use std::u64; 596 | use super::super::mpq::Mpq; 597 | use super::super::mpz::Mpz; 598 | use super::super::sign::Sign; 599 | 600 | #[test] 601 | fn test_one() { 602 | let onea: Mpq = From::::from(1); 603 | let oneb: Mpq = From::::from(1); 604 | assert!(onea == oneb); 605 | } 606 | 607 | #[test] 608 | #[should_panic] 609 | fn test_div_zero() { 610 | let x: Mpq = From::::from(1); 611 | let y = Mpq::new(); 612 | x / y; 613 | } 614 | 615 | #[test] 616 | #[should_panic] 617 | fn test_invert_zero() { 618 | Mpq::new().invert(); 619 | } 620 | 621 | #[test] 622 | fn test_fmt() { 623 | let fourty: Mpq = From::::from(40); 624 | let six: Mpq = From::::from(6); 625 | let fourty_sixths = &fourty / &six; 626 | 627 | assert_eq!(format!("{:?}", fourty), "40"); 628 | assert_eq!(format!("{:?}", -&fourty), "-40"); 629 | assert_eq!(format!("{:?}", fourty_sixths), "20/3"); 630 | assert_eq!(format!("{:?}", -&fourty_sixths), "-20/3"); 631 | } 632 | 633 | #[test] 634 | fn test_floor() { 635 | let half = Mpq::ratio(&Mpz::from(1), &Mpz::from(2)); 636 | assert_eq!(half.floor(), Mpz::from(0)); 637 | 638 | let big = Mpz::from(u64::MAX) * Mpz::from(u64::MAX); 639 | let slightly_more_than_one = Mpq::ratio(&(&big + Mpz::from(1)), &big); 640 | assert_eq!(slightly_more_than_one.floor(), Mpz::from(1)); 641 | 642 | let minus_half = -half; 643 | assert_eq!(minus_half.floor(), Mpz::from(-1)); 644 | } 645 | 646 | #[test] 647 | fn test_ceil() { 648 | let half = Mpq::ratio(&Mpz::from(1), &Mpz::from(2)); 649 | assert_eq!(half.ceil(), Mpz::from(1)); 650 | 651 | let minus_half = -half; 652 | assert_eq!(minus_half.ceil(), Mpz::from(0)); 653 | } 654 | 655 | #[test] 656 | fn test_sign() { 657 | let zero: Mpq = From::::from(0); 658 | let five: Mpq = From::::from(5); 659 | let minus_five: Mpq = From::::from(-5); 660 | 661 | assert_eq!(zero.sign(), Sign::Zero); 662 | assert_eq!(five.sign(), Sign::Positive); 663 | assert_eq!(minus_five.sign(), Sign::Negative); 664 | } 665 | 666 | #[test] 667 | fn test_ratio() { 668 | let zero: Mpz = From::::from(0); 669 | let one: Mpz = From::::from(1); 670 | let minus_one = -&one; 671 | let two = &one + &one; 672 | let four = &two + &two; 673 | 674 | assert_eq!(Mpq::ratio(&one, &minus_one), Mpq::ratio(&minus_one, &one)); 675 | assert_eq!(Mpq::ratio(&zero, &one), Mpq::ratio(&zero, &minus_one)); 676 | assert_eq!(Mpq::ratio(&zero, &one), Mpq::ratio(&zero, &two)); 677 | assert_eq!(Mpq::ratio(&two, &four), Mpq::ratio(&one, &two)); 678 | } 679 | 680 | #[test] 681 | fn test_from_str_radix() { 682 | let zero: Mpz = From::::from(0); 683 | let one: Mpz = From::::from(1); 684 | let minus_one = -&one; 685 | let two = &one + &one; 686 | 687 | assert_eq!(Mpq::from_str_radix("1/-1", 10).unwrap(), Mpq::ratio(&minus_one, &one)); 688 | assert_eq!(Mpq::from_str_radix("0/2", 10).unwrap(), Mpq::ratio(&zero, &one)); 689 | assert_eq!(Mpq::from_str_radix("2/4", 10).unwrap(), Mpq::ratio(&one, &two)); 690 | } 691 | } 692 | 693 | mod mpf { 694 | use super::super::mpf::Mpf; 695 | use super::super::sign::Sign; 696 | 697 | #[test] 698 | #[should_panic] 699 | fn test_div_zero() { 700 | let x = Mpf::new(0); 701 | &x / &x; 702 | } 703 | 704 | #[test] 705 | fn test_sign() { 706 | let zero = Mpf::zero(); 707 | let mut five = Mpf::zero(); 708 | Mpf::set_from_si(&mut five, 5); 709 | let mut minus_five = Mpf::zero(); 710 | Mpf::set_from_si(&mut minus_five, -5); 711 | 712 | assert_eq!(zero.sign(), Sign::Zero); 713 | assert_eq!(five.sign(), Sign::Positive); 714 | assert_eq!(minus_five.sign(), Sign::Negative); 715 | } 716 | } 717 | --------------------------------------------------------------------------------