Make ready for publication

This commit is contained in:
Demi M. Obenour 2019-01-10 12:31:40 -05:00
parent 7fd43b8b79
commit 1016cb998a
16 changed files with 3019 additions and 1 deletions

View File

@ -8,3 +8,6 @@ following NOTICE file:
This product includes software developed at
Chia Network Inc (https://www.chia.net/).
This project contains code from rust-gmp, located at
https://github.com/fizyk20/rust-gmp and licensed under the MIT license.

View File

@ -22,7 +22,7 @@ edition = "2018"
[dependencies]
num-traits = "0.2"
rust-gmp = { git = "https://github.com/poanetwork/rust-gmp" }
rust-gmp = { path = "../rust-gmp" }
libc = "0.2"
[dev-dependencies]

3
rust-gmp/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target/
Cargo.lock
*.swp

4
rust-gmp/.travis.yml Normal file
View File

@ -0,0 +1,4 @@
before_install:
- sudo apt-get update -qq
- sudo apt-get install -y libgmp3-dev
language: rust

16
rust-gmp/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "rust-gmp"
version = "0.5.0"
authors = [ "thestinger <danielmicay@gmail.com>", "Bartłomiej Kamiński <fizyk20@gmail.com>" ]
description = "Rust bindings for GMP"
repository = "https://github.com/fizyk20/rust-gmp"
documentation = "https://docs.rs/rust-gmp"
license = "MIT"
keywords = [ "gmp", "multi", "precision", "arithmetic", "bignum" ]
[lib]
name = "gmp"
[dependencies]
libc = "~0.2"
num-traits = "0.1"

20
rust-gmp/LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright © 2014 Daniel Micay
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

22
rust-gmp/README.md Normal file
View File

@ -0,0 +1,22 @@
[![Build Status](https://travis-ci.org/fizyk20/rust-gmp.svg?branch=master)](https://travis-ci.org/fizyk20/rust-gmp)
[Documentation](https://docs.rs/rust-gmp)
The following functions are intentionally left out of the bindings:
* `gmp_randinit` (not thread-safe, obsolete)
* `mpz_random` (not thread-safe, obsolete)
* `mpz_random2` (not thread-safe, obsolete)
* `mpf_set_default_prec` (not thread-safe)
* `mpf_get_default_prec` (not thread-safe)
* `mpf_init` (not thread-safe)
* `mpf_inits` (not thread-safe, va_list wrapper)
* `mpf_clears` (va_list wrapper)
* `mpf_swap` (no better than rust's swap)
* `mpf_set_prec_raw` (could be exposed with an `unsafe` function if needed)
* `mpz_inits` (va_list wrapper)
* `mpz_clears` (va_list wrapper)
* `mpz_swap` (no better than rust's swap)
* `mpq_inits` (va_list wrapper)
* `mpq_clears` (va_list wrapper)
* `mpq_swap` (no better than rust's swap)

253
rust-gmp/main.patch Normal file
View File

@ -0,0 +1,253 @@
diff --git a/src/mpz.rs b/src/mpz.rs
index 6226744..87f9895 100644
--- a/src/mpz.rs
+++ b/src/mpz.rs
@@ -1,4 +1,4 @@
-use libc::{c_char, c_int, c_long, c_ulong, c_void, c_double, size_t};
+use libc::{c_char, c_int, c_long, c_ulong, c_void, c_double, size_t, strnlen};
use super::rand::gmp_randstate_t;
use super::sign::Sign;
use std::convert::From;
@@ -9,7 +9,7 @@ use std::str::FromStr;
use std::error::Error;
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};
use std::ffi::CString;
-use std::{u32, i32};
+use std::{u32, i32, usize};
use num_traits::{Zero, One};
use ffi::*;
@@ -97,6 +97,7 @@ extern "C" {
fn __gmpz_urandomm(rop: mpz_ptr, state: gmp_randstate_t, n: mpz_srcptr);
}
+#[repr(transparent)]
pub struct Mpz {
mpz: mpz_struct,
}
@@ -117,14 +118,17 @@ pub enum ProbabPrimeResult {
}
impl Mpz {
+ #[inline]
pub unsafe fn inner(&self) -> mpz_srcptr {
&self.mpz
}
+ #[inline]
pub unsafe fn inner_mut(&mut self) -> mpz_ptr {
&mut self.mpz
}
+ #[inline]
pub fn new() -> Mpz {
unsafe {
let mut mpz = uninitialized();
@@ -133,6 +137,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn new_reserve(n: usize) -> Mpz {
unsafe {
let mut mpz = uninitialized();
@@ -141,12 +146,14 @@ impl Mpz {
}
}
+ #[inline]
pub fn reserve(&mut self, n: usize) {
if self.bit_length() < n {
unsafe { __gmpz_realloc2(&mut self.mpz, n as c_ulong) }
}
}
+ #[inline]
pub fn size_in_base(&self, base: u8) -> usize {
unsafe {
__gmpz_sizeinbase(&self.mpz, base as c_int) as usize
@@ -158,31 +165,22 @@ impl Mpz {
// machinery for a custom type.
pub fn to_str_radix(&self, base: u8) -> String {
unsafe {
+ assert!(base >= 2 && base <= 36, "invalid base");
// Extra two bytes are for possible minus sign and null terminator
- let len = __gmpz_sizeinbase(&self.mpz, base as c_int) as usize + 2;
+ let len = {
+ let len = __gmpz_sizeinbase(&self.mpz, base as c_int) as usize;
+ assert!(usize::MAX - len >= 2, "capacity overflow");
+ len + 2
+ };
// Allocate and write into a raw *c_char of the correct length
let mut vector: Vec<u8> = Vec::with_capacity(len);
- vector.set_len(len);
-
__gmpz_get_str(vector.as_mut_ptr() as *mut _, base as c_int, &self.mpz);
-
- let mut first_nul = None;
- let mut index : usize = 0;
- for elem in &vector {
- if *elem == 0 {
- first_nul = Some(index);
- break;
- }
- index += 1;
- }
- let first_nul = first_nul.unwrap_or(len);
-
- vector.truncate(first_nul);
- match String::from_utf8(vector) {
- Ok(s) => s,
- Err(_) => panic!("GMP returned invalid UTF-8!")
- }
+ let string_len = strnlen(vector.as_ptr() as *const _, len);
+ assert!(string_len < len);
+ vector.set_len(string_len);
+ // FIXME is this actually a problem?
+ String::from_utf8(vector).expect("GMP returned invalid UTF-8!")
}
}
@@ -201,6 +199,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn set(&mut self, other: &Mpz) {
unsafe { __gmpz_set(&mut self.mpz, &other.mpz) }
}
@@ -212,10 +211,12 @@ impl Mpz {
unsafe { __gmpz_set_str(&mut self.mpz, s.as_ptr(), base as c_int) == 0 }
}
+ #[inline]
pub fn bit_length(&self) -> usize {
unsafe { __gmpz_sizeinbase(&self.mpz, 2) as usize }
}
+ #[inline]
pub fn compl(&self) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -224,6 +225,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn abs(&self) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -232,6 +234,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn div_floor(&self, other: &Mpz) -> Mpz {
unsafe {
if other.is_zero() {
@@ -244,6 +247,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn mod_floor(&self, other: &Mpz) -> Mpz {
unsafe {
if other.is_zero() {
@@ -270,6 +274,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn nextprime(&self) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -278,6 +283,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn gcd(&self, other: &Mpz) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -298,6 +304,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn lcm(&self, other: &Mpz) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -306,6 +313,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn is_multiple_of(&self, other: &Mpz) -> bool {
unsafe {
__gmpz_divisible_p(&self.mpz, &other.mpz) != 0
@@ -341,10 +349,12 @@ impl Mpz {
}
}
+ #[inline]
pub fn popcount(&self) -> usize {
unsafe { __gmpz_popcount(&self.mpz) as usize }
}
+ #[inline]
pub fn pow(&self, exp: u32) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -353,6 +363,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn powm(&self, exp: &Mpz, modulus: &Mpz) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -361,6 +372,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn powm_sec(&self, exp: &Mpz, modulus: &Mpz) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -369,6 +381,7 @@ impl Mpz {
}
}
+ #[inline]
pub fn ui_pow_ui(x: u32, y: u32) -> Mpz {
unsafe {
let mut res = Mpz::new();
@@ -377,22 +390,27 @@ impl Mpz {
}
}
+ #[inline]
pub fn hamdist(&self, other: &Mpz) -> usize {
unsafe { __gmpz_hamdist(&self.mpz, &other.mpz) as usize }
}
+ #[inline]
pub fn setbit(&mut self, bit_index: usize) {
unsafe { __gmpz_setbit(&mut self.mpz, bit_index as c_ulong) }
}
+ #[inline]
pub fn clrbit(&mut self, bit_index: usize) {
unsafe { __gmpz_clrbit(&mut self.mpz, bit_index as c_ulong) }
}
+ #[inline]
pub fn combit(&mut self, bit_index: usize) {
unsafe { __gmpz_combit(&mut self.mpz, bit_index as c_ulong) }
}
+ #[inline]
pub fn tstbit(&self, bit_index: usize) -> bool {
unsafe { __gmpz_tstbit(&self.mpz, bit_index as c_ulong) == 1 }
}

7
rust-gmp/src/ffi.rs Normal file
View File

@ -0,0 +1,7 @@
use mpz::*;
#[link(name = "gmp")]
extern "C" {
pub fn __gmpz_fdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
pub fn __gmpz_cdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
}

17
rust-gmp/src/lib.rs Normal file
View File

@ -0,0 +1,17 @@
#![crate_name = "gmp"]
#![warn(deprecated)]
#![allow(non_camel_case_types)]
extern crate libc;
extern crate num_traits;
mod ffi;
pub mod mpz;
pub mod mpq;
pub mod mpf;
pub mod rand;
pub mod sign;
#[cfg(test)]
mod test;

353
rust-gmp/src/mpf.rs Normal file
View File

@ -0,0 +1,353 @@
use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char, free};
use std;
use std::mem::uninitialized;
use std::cmp;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
use std::ffi::CString;
use std::string::String;
use super::mpz::mp_bitcnt_t;
use super::mpz::{Mpz, mpz_srcptr};
use super::mpq::{Mpq, mpq_srcptr};
use super::sign::Sign;
use num_traits::{Zero, One};
type mp_exp_t = c_long;
#[repr(C)]
pub struct mpf_struct {
_mp_prec: c_int,
_mp_size: c_int,
_mp_exp: mp_exp_t,
_mp_d: *mut c_void
}
pub type mpf_srcptr = *const mpf_struct;
pub type mpf_ptr = *mut mpf_struct;
#[link(name = "gmp")]
extern "C" {
fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
fn __gmpf_init_set(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_clear(x: mpf_ptr);
fn __gmpf_get_prec(op: mpf_srcptr) -> mp_bitcnt_t;
fn __gmpf_set_prec(rop: mpf_ptr, prec: mp_bitcnt_t);
fn __gmpf_set(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_set_z(rop: mpf_ptr, op: mpz_srcptr);
fn __gmpf_set_q(rop: mpf_ptr, op: mpq_srcptr);
fn __gmpf_set_str(rop: mpf_ptr, str: *const c_char, base: c_int);
fn __gmpf_set_si(rop: mpf_ptr, op: c_long);
fn __gmpf_get_str(str: *const c_char, expptr: *const mp_exp_t, base: i32, n_digits: i32, op: mpf_ptr) -> *mut c_char;
fn __gmpf_cmp(op1: mpf_srcptr, op2: mpf_srcptr) -> c_int;
fn __gmpf_cmp_d(op1: mpf_srcptr, op2: c_double) -> c_int;
fn __gmpf_cmp_ui(op1: mpf_srcptr, op2: c_ulong) -> c_int;
fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int;
fn __gmpf_reldiff(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
fn __gmpf_add(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
fn __gmpf_sub(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
fn __gmpf_mul(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
fn __gmpf_div(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
fn __gmpf_neg(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_abs(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_ceil(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_floor(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_trunc(rop: mpf_ptr, op: mpf_srcptr);
fn __gmpf_sqrt(rop: mpf_ptr, op: mpf_srcptr);
}
pub struct Mpf {
mpf: mpf_struct,
}
unsafe impl Send for Mpf { }
unsafe impl Sync for Mpf { }
impl Drop for Mpf {
fn drop(&mut self) { unsafe { __gmpf_clear(&mut self.mpf) } }
}
impl Mpf {
pub unsafe fn inner(&self) -> mpf_srcptr {
&self.mpf
}
pub unsafe fn inner_mut(&mut self) -> mpf_ptr {
&mut self.mpf
}
pub fn zero() -> Mpf { Mpf::new(32) }
pub fn new(precision: usize) -> Mpf {
unsafe {
let mut mpf = uninitialized();
__gmpf_init2(&mut mpf, precision as c_ulong);
Mpf { mpf: mpf }
}
}
pub fn set(&mut self, other: &Mpf) {
unsafe { __gmpf_set(&mut self.mpf, &other.mpf) }
}
pub fn set_z(&mut self, other: &Mpz) {
unsafe { __gmpf_set_z(&mut self.mpf, other.inner()) }
}
pub fn set_q(&mut self, other: &Mpq) {
unsafe { __gmpf_set_q(&mut self.mpf, other.inner()) }
}
pub fn get_prec(&self) -> usize {
unsafe { __gmpf_get_prec(&self.mpf) as usize }
}
pub fn set_prec(&mut self, precision: usize) {
unsafe { __gmpf_set_prec(&mut self.mpf, precision as c_ulong) }
}
pub fn set_from_str(&mut self, string: &str, base: i32){
let c_str = CString::new(string).unwrap();
unsafe {
__gmpf_set_str(&mut self.mpf, c_str.as_ptr(), base as c_int);
}
}
pub fn set_from_si(&mut self, int: i64){
unsafe{
__gmpf_set_si(&mut self.mpf,int as c_long);
}
}
pub fn get_str(&mut self, n_digits: i32, base: i32, exp: &mut c_long) -> String{
let out;
unsafe{
out = CString::from_raw(__gmpf_get_str(std::ptr::null(), exp, base, n_digits, &mut self.mpf));
}
let r = out.to_str().unwrap().to_string();
// Free the pointer returned to us, as r already took a copy of the data inside of it
// Stops memory leaking
unsafe { free(out.into_raw() as _) };
r
}
pub fn abs(&self) -> Mpf {
unsafe {
let mut res = Mpf::new(self.get_prec());
__gmpf_abs(&mut res.mpf, &self.mpf);
res
}
}
pub fn ceil(&self) -> Mpf {
unsafe {
let mut res = Mpf::new(self.get_prec());
__gmpf_ceil(&mut res.mpf, &self.mpf);
res
}
}
pub fn floor(&self) -> Mpf {
unsafe {
let mut res = Mpf::new(self.get_prec());
__gmpf_floor(&mut res.mpf, &self.mpf);
res
}
}
pub fn trunc(&self) -> Mpf {
unsafe {
let mut res = Mpf::new(self.get_prec());
__gmpf_trunc(&mut res.mpf, &self.mpf);
res
}
}
pub fn reldiff(&self, other: &Mpf) -> Mpf {
unsafe {
let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
__gmpf_reldiff(&mut res.mpf, &self.mpf, &other.mpf);
res
}
}
pub fn sqrt(self) -> Mpf {
let mut retval:Mpf;
unsafe {
retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize);
retval.set_from_si(0);
if __gmpf_cmp_si(&self.mpf, 0) > 0 {
__gmpf_sqrt(&mut retval.mpf, &self.mpf);
} else {
panic!("Square root of negative/zero");
}
}
retval
}
pub fn sign(&self) -> Sign {
let size = self.mpf._mp_size;
if size == 0 {
Sign::Zero
} else if size > 0 {
Sign::Positive
} else {
Sign::Negative
}
}
}
impl Clone for Mpf {
fn clone(&self) -> Mpf {
unsafe {
let mut mpf = uninitialized();
__gmpf_init_set(&mut mpf, &self.mpf);
Mpf { mpf: mpf }
}
}
}
impl Eq for Mpf { }
impl PartialEq for Mpf {
fn eq(&self, other: &Mpf) -> bool {
unsafe { __gmpf_cmp(&self.mpf, &other.mpf) == 0 }
}
}
impl Ord for Mpf {
fn cmp(&self, other: &Mpf) -> Ordering {
let cmp = unsafe { __gmpf_cmp(&self.mpf, &other.mpf) };
if cmp == 0 {
Equal
} else if cmp > 0 {
Greater
} else {
Less
}
}
}
impl PartialOrd for Mpf {
fn partial_cmp(&self, other: &Mpf) -> Option<Ordering> {
Some(self.cmp(other))
}
}
macro_rules! div_guard {
(Div, $is_zero: expr) => {
if $is_zero {
panic!("divide by zero")
}
};
($tr: ident, $what: expr) => {}
}
macro_rules! impl_oper {
($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
impl<'a> $tr<Mpf> for &'a Mpf {
type Output = Mpf;
#[inline]
fn $meth(self, other: Mpf) -> Mpf {
self.$meth(&other)
}
}
impl<'a> $tr<&'a Mpf> for Mpf {
type Output = Mpf;
#[inline]
fn $meth(mut self, other: &Mpf) -> Mpf {
self.$meth_assign(other);
self
}
}
impl $tr<Mpf> for Mpf {
type Output = Mpf;
#[inline]
fn $meth(self, other: Mpf) -> Mpf {
self.$meth(&other)
}
}
impl<'a, 'b> $tr<&'a Mpf> for &'b Mpf {
type Output = Mpf;
fn $meth(self, other: &Mpf) -> Mpf {
unsafe {
div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
$fun(&mut res.mpf, &self.mpf, &other.mpf);
res
}
}
}
impl<'a> $tr_assign<Mpf> for Mpf {
#[inline]
fn $meth_assign(&mut self, other: Mpf) {
self.$meth_assign(&other)
}
}
impl<'a> $tr_assign<&'a Mpf> for Mpf {
#[inline]
fn $meth_assign(&mut self, other: &Mpf) {
unsafe {
div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
$fun(&mut self.mpf, &self.mpf, &other.mpf)
}
}
}
}
}
impl_oper!(Add, add, AddAssign, add_assign, __gmpf_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpf_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpf_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpf_div);
impl<'b> Neg for &'b Mpf {
type Output = Mpf;
fn neg(self) -> Mpf {
unsafe {
let mut res = Mpf::new(self.get_prec());
__gmpf_neg(&mut res.mpf, &self.mpf);
res
}
}
}
impl Neg for Mpf {
type Output = Mpf;
#[inline]
fn neg(mut self) -> Mpf {
unsafe {
__gmpf_neg(&mut self.mpf, &self.mpf);
self
}
}
}
impl Zero for Mpf {
#[inline]
fn zero() -> Mpf {
Mpf::zero()
}
#[inline]
fn is_zero(&self) -> bool {
unsafe {
__gmpf_cmp_ui(&self.mpf, 0) == 0
}
}
}
impl One for Mpf {
#[inline]
fn one() -> Mpf {
let mut res = Mpf::new(32);
res.set_from_si(1);
res
}
}

443
rust-gmp/src/mpq.rs Normal file
View File

@ -0,0 +1,443 @@
use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr};
use super::mpf::{Mpf, mpf_srcptr};
use super::sign::Sign;
use ffi::*;
use libc::{c_char, c_double, c_int, c_ulong};
use std::ffi::CString;
use std::str::FromStr;
use std::error::Error;
use std::convert::From;
use std::mem::uninitialized;
use std::fmt;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
use num_traits::{Zero, One};
#[repr(C)]
pub struct mpq_struct {
_mp_num: mpz_struct,
_mp_den: mpz_struct
}
pub type mpq_srcptr = *const mpq_struct;
pub type mpq_ptr = *mut mpq_struct;
#[link(name = "gmp")]
extern "C" {
fn __gmpq_init(x: mpq_ptr);
fn __gmpq_clear(x: mpq_ptr);
fn __gmpq_set(rop: mpq_ptr, op: mpq_srcptr);
fn __gmpq_set_z(rop: mpq_ptr, op: mpz_srcptr);
fn __gmpq_set_ui(rop: mpq_ptr, op1: c_ulong, op2: c_ulong);
fn __gmpq_set_d(rop: mpq_ptr, op: c_double);
fn __gmpq_set_f(rop: mpq_ptr, op: mpf_srcptr);
fn __gmpq_cmp(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
fn __gmpq_cmp_ui(op1: mpq_srcptr, num2: c_ulong, den2: c_ulong) -> c_int;
fn __gmpq_equal(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
fn __gmpq_add(sum: mpq_ptr, addend1: mpq_srcptr, addend2: mpq_srcptr);
fn __gmpq_sub(difference: mpq_ptr, minuend: mpq_srcptr, subtrahend: mpq_srcptr);
fn __gmpq_mul(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
fn __gmpq_div(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
fn __gmpq_neg(negated_operand: mpq_ptr, operand: mpq_srcptr);
fn __gmpq_abs(rop: mpq_ptr, op: mpq_srcptr);
fn __gmpq_inv(inverted_number: mpq_ptr, number: mpq_srcptr);
fn __gmpq_get_num(numerator: mpz_ptr, rational: mpq_srcptr);
fn __gmpq_get_den(denominator: mpz_ptr, rational: mpq_srcptr);
fn __gmpq_set_num(rational: mpq_ptr, numerator: mpz_srcptr);
fn __gmpq_set_den(rational: mpq_ptr, denominator: mpz_srcptr);
fn __gmpq_canonicalize(rational: mpq_ptr);
fn __gmpq_get_d(rational: mpq_srcptr) -> c_double;
fn __gmpq_set_str(rop: mpq_ptr, str: *const c_char, base: c_int) -> c_int;
}
pub struct Mpq {
mpq: mpq_struct,
}
unsafe impl Send for Mpq { }
unsafe impl Sync for Mpq { }
impl Drop for Mpq {
fn drop(&mut self) { unsafe { __gmpq_clear(&mut self.mpq) } }
}
impl Mpq {
pub unsafe fn inner(&self) -> mpq_srcptr {
&self.mpq
}
pub unsafe fn inner_mut(&mut self) -> mpq_ptr {
&mut self.mpq
}
pub fn new() -> Mpq {
unsafe {
let mut mpq = uninitialized();
__gmpq_init(&mut mpq);
Mpq { mpq: mpq }
}
}
pub fn ratio(num: &Mpz, den: &Mpz) -> Mpq {
unsafe {
let mut res = Mpq::new();
__gmpq_set_num(&mut res.mpq, num.inner());
__gmpq_set_den(&mut res.mpq, den.inner());
// Not canonicalizing is unsafe
__gmpq_canonicalize(&mut res.mpq);
res
}
}
pub fn from_str_radix(s: &str, base: u8) -> Result<Mpq, ParseMpqError> {
let s = CString::new(s).map_err(|_| ParseMpqError { _priv: () })?;
let mut res = Mpq::new();
unsafe {
assert!(base == 0 || (base >= 2 && base <= 62));
let r = __gmpq_set_str(&mut res.mpq, s.as_ptr(), base as c_int);
if r == 0 {
// Not canonicalizing is unsafe
__gmpq_canonicalize(&mut res.mpq);
Ok(res)
} else {
Err(ParseMpqError { _priv: () })
}
}
}
pub fn set(&mut self, other: &Mpq) {
unsafe { __gmpq_set(&mut self.mpq, &other.mpq) }
}
pub fn set_z(&mut self, other: &Mpz) {
unsafe { __gmpq_set_z(&mut self.mpq, other.inner()) }
}
pub fn set_d(&mut self, other: f64) {
unsafe { __gmpq_set_d(&mut self.mpq, other) }
}
pub fn set_f(&mut self, other: &Mpf) {
unsafe { __gmpq_set_f(&mut self.mpq, other.inner()) }
}
pub fn get_num(&self) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpq_get_num(res.inner_mut(), &self.mpq);
res
}
}
pub fn get_den(&self) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpq_get_den(res.inner_mut(), &self.mpq);
res
}
}
pub fn abs(&self) -> Mpq {
unsafe {
let mut res = Mpq::new();
__gmpq_abs(&mut res.mpq, &self.mpq);
res
}
}
pub fn invert(&self) -> Mpq {
unsafe {
if self.is_zero() {
panic!("divide by zero")
}
let mut res = Mpq::new();
__gmpq_inv(&mut res.mpq, &self.mpq);
res
}
}
pub fn floor(&self) -> Mpz {
let mut res = Mpz::new();
unsafe {
__gmpz_fdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
}
res
}
pub fn ceil(&self) -> Mpz {
let mut res = Mpz::new();
unsafe {
__gmpz_cdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
}
res
}
pub fn sign(&self) -> Sign {
self.get_num().sign()
}
pub fn one() -> Mpq {
let mut res = Mpq::new();
unsafe { __gmpq_set_ui(&mut res.mpq, 1, 1) }
res
}
pub fn zero() -> Mpq { Mpq::new() }
pub fn is_zero(&self) -> bool {
unsafe { __gmpq_cmp_ui(&self.mpq, 0, 1) == 0 }
}
}
#[derive(Debug)]
pub struct ParseMpqError {
_priv: ()
}
impl fmt::Display for ParseMpqError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl Error for ParseMpqError {
fn description(&self) -> &'static str {
"invalid rational number"
}
fn cause(&self) -> Option<&'static Error> {
None
}
}
impl Clone for Mpq {
fn clone(&self) -> Mpq {
let mut res = Mpq::new();
res.set(self);
res
}
}
impl Eq for Mpq { }
impl PartialEq for Mpq {
fn eq(&self, other: &Mpq) -> bool {
unsafe { __gmpq_equal(&self.mpq, &other.mpq) != 0 }
}
}
impl Ord for Mpq {
fn cmp(&self, other: &Mpq) -> Ordering {
let cmp = unsafe { __gmpq_cmp(&self.mpq, &other.mpq) };
if cmp == 0 {
Equal
} else if cmp < 0 {
Less
} else {
Greater
}
}
}
impl PartialOrd for Mpq {
fn partial_cmp(&self, other: &Mpq) -> Option<Ordering> {
Some(self.cmp(other))
}
}
macro_rules! div_guard {
(Div, $what: expr) => {
if $what.is_zero() {
panic!("divide by zero")
}
};
($tr: ident, $what: expr) => {}
}
macro_rules! impl_oper {
($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
impl $tr<Mpq> for Mpq {
type Output = Mpq;
#[inline]
fn $meth(self, other: Mpq) -> Mpq {
self.$meth(&other)
}
}
impl<'a> $tr<&'a Mpq> for Mpq {
type Output = Mpq;
#[inline]
fn $meth(mut self, other: &Mpq) -> Mpq {
self.$meth_assign(other);
self
}
}
impl<'a> $tr<Mpq> for &'a Mpq {
type Output = Mpq;
#[inline]
fn $meth(self, mut other: Mpq) -> Mpq {
unsafe {
div_guard!($tr, other);
$fun(&mut other.mpq, &self.mpq, &other.mpq);
other
}
}
}
impl<'a, 'b> $tr<&'a Mpq> for &'b Mpq {
type Output = Mpq;
fn $meth(self, other: &Mpq) -> Mpq {
unsafe {
div_guard!($tr, *other);
let mut res = Mpq::new();
$fun(&mut res.mpq, &self.mpq, &other.mpq);
res
}
}
}
impl<'a> $tr_assign<Mpq> for Mpq {
#[inline]
fn $meth_assign(&mut self, other: Mpq) {
self.$meth_assign(&other)
}
}
impl<'a> $tr_assign<&'a Mpq> for Mpq {
#[inline]
fn $meth_assign(&mut self, other: &Mpq) {
unsafe {
div_guard!($tr, *other);
$fun(&mut self.mpq, &self.mpq, &other.mpq)
}
}
}
}
}
impl_oper!(Add, add, AddAssign, add_assign, __gmpq_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpq_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpq_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpq_div);
impl<'b> Neg for &'b Mpq {
type Output = Mpq;
fn neg(self) -> Mpq {
unsafe {
let mut res = Mpq::new();
__gmpq_neg(&mut res.mpq, &self.mpq);
res
}
}
}
impl Neg for Mpq {
type Output = Mpq;
#[inline]
fn neg(mut self) -> Mpq {
unsafe {
__gmpq_neg(&mut self.mpq, &self.mpq);
self
}
}
}
impl From<Mpq> for f64 {
fn from(other: Mpq) -> f64 {
f64::from(&other)
}
}
impl<'a> From<&'a Mpq> for f64 {
fn from(other: &Mpq) -> f64 {
unsafe {
__gmpq_get_d(&other.mpq) as f64
}
}
}
impl From<Mpz> for Mpq {
fn from(other: Mpz) -> Mpq {
Mpq::from(&other)
}
}
impl<'a> From<&'a Mpz> for Mpq {
fn from(other: &Mpz) -> Mpq {
let mut res = Mpq::new();
res.set_z(&other);
res
}
}
impl From<i64> for Mpq {
fn from(other: i64) -> Mpq {
From::<Mpz>::from(From::<i64>::from(other))
}
}
impl From<i32> for Mpq {
fn from(other: i32) -> Mpq {
From::<Mpz>::from(From::<i32>::from(other))
}
}
impl From<u64> for Mpq {
fn from(other: u64) -> Mpq {
From::<Mpz>::from(From::<u64>::from(other))
}
}
impl From<u32> for Mpq {
fn from(other: u32) -> Mpq {
From::<Mpz>::from(From::<u32>::from(other))
}
}
impl FromStr for Mpq {
type Err = ParseMpqError;
fn from_str(s: &str) -> Result<Mpq, ParseMpqError> {
Mpq::from_str_radix(s, 10)
}
}
impl fmt::Debug for Mpq {
/// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self, f)
}
}
impl fmt::Display for Mpq {
/// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let numer = self.get_num();
let denom = self.get_den();
if denom == From::<i64>::from(1) {
write!(f, "{}", numer)
} else {
write!(f, "{}/{}", numer, denom)
}
}
}
impl Zero for Mpq {
#[inline]
fn zero() -> Mpq {
Mpq::zero()
}
#[inline]
fn is_zero(&self) -> bool {
self.is_zero()
}
}
impl One for Mpq {
#[inline]
fn one() -> Mpq {
Mpq::one()
}
}

1037
rust-gmp/src/mpz.rs Normal file

File diff suppressed because it is too large Load Diff

109
rust-gmp/src/rand.rs Normal file
View File

@ -0,0 +1,109 @@
use libc::{c_int, c_ulong, c_void};
use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr, mp_bitcnt_t};
use std::mem::uninitialized;
#[repr(C)]
pub struct gmp_randstate_struct {
_mp_seed: mpz_struct,
_mp_alg: c_int,
_mp_algdata: *const c_void
}
pub type gmp_randstate_t = *mut gmp_randstate_struct;
#[link(name = "gmp")]
extern "C" {
fn __gmp_randinit_default(state: gmp_randstate_t);
fn __gmp_randinit_mt(state: gmp_randstate_t);
fn __gmp_randinit_lc_2exp(state: gmp_randstate_t, a: mpz_srcptr, c: c_ulong, m2exp: mp_bitcnt_t);
fn __gmp_randinit_lc_2exp_size(state: gmp_randstate_t, size: mp_bitcnt_t);
fn __gmp_randinit_set(state: gmp_randstate_t, op: *const gmp_randstate_struct);
fn __gmp_randclear(state: gmp_randstate_t);
fn __gmp_randseed(state: gmp_randstate_t, seed: mpz_srcptr);
fn __gmp_randseed_ui(state: gmp_randstate_t, seed: c_ulong);
fn __gmpz_urandomb(rop: mpz_ptr, state: gmp_randstate_t, n: mp_bitcnt_t);
fn __gmpz_urandomm(rop: mpz_ptr, state: gmp_randstate_t, n: mpz_srcptr);
}
pub struct RandState {
state: gmp_randstate_struct,
}
unsafe impl Send for RandState { }
unsafe impl Sync for RandState { }
impl Drop for RandState {
fn drop(&mut self) {
unsafe { __gmp_randclear(&mut self.state) }
}
}
impl RandState {
pub fn new() -> RandState {
unsafe {
let mut state: gmp_randstate_struct = uninitialized();
__gmp_randinit_default(&mut state);
RandState { state: state }
}
}
pub fn new_mt() -> RandState {
unsafe {
let mut state: gmp_randstate_struct = uninitialized();
__gmp_randinit_mt(&mut state);
RandState { state: state }
}
}
pub fn new_lc_2exp(a: Mpz, c: u64, m2exp: u64) -> RandState {
unsafe {
let mut state: gmp_randstate_struct = uninitialized();
__gmp_randinit_lc_2exp(&mut state, a.inner(), c as c_ulong, m2exp as c_ulong);
RandState { state: state }
}
}
pub fn new_lc_2exp_size(size: u64) -> RandState {
unsafe {
let mut state: gmp_randstate_struct = uninitialized();
__gmp_randinit_lc_2exp_size(&mut state, size as c_ulong);
RandState { state: state }
}
}
pub fn seed(&mut self, seed: Mpz) {
unsafe { __gmp_randseed(&mut self.state, seed.inner()) }
}
pub fn seed_ui(&mut self, seed: u64) {
unsafe { __gmp_randseed_ui(&mut self.state, seed as c_ulong) }
}
/// Generate a uniform random integer in the range 0 to n-1, inclusive
pub fn urandom(&mut self, n: &Mpz) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpz_urandomm(res.inner_mut(), &mut self.state, n.inner());
res
}
}
/// Generate a uniformly distributed random integer in the range 0 to 2^n1, inclusive.
pub fn urandom_2exp(&mut self, n: u64) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpz_urandomb(res.inner_mut(), &mut self.state, n as c_ulong);
res
}
}
}
impl Clone for RandState {
fn clone(&self) -> RandState {
unsafe {
let mut state: gmp_randstate_struct = uninitialized();
__gmp_randinit_set(&mut state, &self.state);
RandState { state: state }
}
}
}

7
rust-gmp/src/sign.rs Normal file
View File

@ -0,0 +1,7 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)]
pub enum Sign {
Negative,
Zero,
Positive,
}

724
rust-gmp/src/test.rs Normal file
View File

@ -0,0 +1,724 @@
use super::mpz::mp_limb_t;
use std;
use libc::c_int;
#[link(name = "gmp")]
extern "C" {
static __gmp_bits_per_limb: c_int;
}
#[test]
fn test_limb_size() {
// We are assuming that the limb size is the same as the pointer size.
assert_eq!(std::mem::size_of::<mp_limb_t>() * 8,
unsafe { __gmp_bits_per_limb as usize });
}
mod mpz {
use super::super::mpz::Mpz;
use super::super::mpz::ProbabPrimeResult;
use super::super::sign::Sign;
use std::str::FromStr;
use std::convert::{From, Into};
use std::{i64, u64};
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
#[test]
fn test_set() {
let mut x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(5000);
assert!(x != y);
x.set(&y);
assert!(x == y);
}
#[test]
fn test_set_from_str_radix() {
let mut x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(5000);
assert!(x != y);
assert!(x.set_from_str_radix("5000", 10));
assert!(x == y);
assert!(!x.set_from_str_radix("aaaa", 2));
}
#[test]
#[should_panic]
fn test_from_str_radix_lower_bound() {
let _ = Mpz::from_str_radix("", 1);
}
#[test]
#[should_panic]
fn test_from_str_radix_upper_bound() {
let _ = Mpz::from_str_radix("", 63);
}
#[test]
#[should_panic]
fn test_set_from_str_radix_lower_bound() {
let mut x = Mpz::new();
x.set_from_str_radix("", 1);
}
#[test]
#[should_panic]
fn test_set_from_str_radix_upper_bound() {
let mut x = Mpz::new();
x.set_from_str_radix("", 63);
}
#[test]
fn test_eq() {
let x: Mpz = From::<i64>::from(4242142195);
let y: Mpz = From::<i64>::from(4242142195);
let z: Mpz = From::<i64>::from(4242142196);
assert!(x == y);
assert!(x != z);
assert!(y != z);
}
#[test]
fn test_ord() {
let x: Mpz = FromStr::from_str("40000000000000000000000").unwrap();
let y: Mpz = FromStr::from_str("45000000000000000000000").unwrap();
let z: Mpz = FromStr::from_str("50000000000000000000000").unwrap();
assert!(x < y && x < z && y < z);
assert!(x <= x && x <= y && x <= z && y <= z);
assert!(z > y && z > x && y > x);
assert!(z >= z && z >= y && z >= x && y >= x);
}
#[test]
#[should_panic]
fn test_div_zero() {
let x: Mpz = From::<i64>::from(1);
let y = Mpz::new();
x / y;
}
#[test]
#[should_panic]
fn test_rem_zero() {
let x: Mpz = From::<i64>::from(1);
let y = Mpz::new();
x % y;
}
#[test]
fn test_div_round() {
let x: Mpz = From::<i64>::from(2);
let y: Mpz = From::<i64>::from(3);
assert!((&x / &y).to_string() == (2i32 / 3).to_string());
assert!((&x / -&y).to_string() == (2i32 / -3).to_string());
}
#[test]
fn test_rem() {
let x: Mpz = From::<i64>::from(20);
let y: Mpz = From::<i64>::from(3);
assert!((&x % &y).to_string() == (20i32 % 3).to_string());
assert!((&x % 3).to_string() == (20i32 % 3).to_string());
assert!((&x % -&y).to_string() == (20i32 % -3).to_string());
assert!((-&x % &y).to_string() == (-20i32 % 3).to_string());
}
#[test]
fn test_add() {
let x: Mpz = From::<i64>::from(2);
let y: Mpz = From::<i64>::from(3);
let str5 = 5i32.to_string();
assert!((&x + &y).to_string() == str5);
assert!((&x + 3).to_string() == str5);
assert!((&y + 2).to_string() == str5);
}
#[test]
fn test_sub() {
let x: Mpz = From::<i64>::from(2);
let y: Mpz = From::<i64>::from(3);
assert!((&x - &y).to_string() == (-1i32).to_string());
assert!((&y - &x).to_string() == 1i32.to_string());
assert!((&y - 8).to_string() == (-5i32).to_string());
}
#[test]
fn test_mul() {
let x: Mpz = From::<i64>::from(2);
let y: Mpz = From::<i64>::from(3);
assert!((&x * &y).to_string() == 6i32.to_string());
assert!((&x * 3i64).to_string() == 6i32.to_string());
assert!((&y * -5i64).to_string() == (-15i32).to_string());
// check with values not fitting in 32 bits
assert!((&x * 5000000000i64).to_string() == 10000000000i64.to_string());
}
#[test]
fn test_to_str_radix() {
let x: Mpz = From::<i64>::from(255);
assert!(x.to_str_radix(16) == "ff".to_string());
}
#[test]
fn test_to_string() {
let x: Mpz = FromStr::from_str("1234567890").unwrap();
assert!(x.to_string() == "1234567890".to_string());
}
#[test]
fn test_invalid_str() {
let x: Result<Mpz, _> = FromStr::from_str("foobar");
assert!(x.is_err());
}
#[test]
fn test_clone() {
let a: Mpz = From::<i64>::from(100);
let b = a.clone();
let aplusb: Mpz = From::<i64>::from(200);
assert!(b == a);
assert!(a + b == aplusb);
}
#[test]
fn test_from_int() {
let x: Mpz = From::<i64>::from(150);
assert!(x.to_string() == "150".to_string());
assert!(x == FromStr::from_str("150").unwrap());
}
#[test]
fn test_from_slice_u8() {
let v: Vec<u8> = vec!(255, 255);
let x: Mpz = From::from(&v[..]);
assert!(x.to_string() == "65535".to_string());
}
#[test]
fn test_abs() {
let x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(-1000);
assert!(-&x == y);
assert!(x == -&y);
assert!(x == y.abs());
assert!(x.abs() == y.abs());
}
#[test]
fn test_div_floor() {
let two: Mpz = From::<i64>::from(2);
let eight: Mpz = From::<i64>::from(8);
let minuseight: Mpz = From::<i64>::from(-8);
let three: Mpz = From::<i64>::from(3);
let minusthree: Mpz = From::<i64>::from(-3);
assert_eq!(eight.div_floor(&three), two);
assert_eq!(eight.div_floor(&minusthree), minusthree);
assert_eq!(minuseight.div_floor(&three), minusthree);
assert_eq!(minuseight.div_floor(&minusthree), two);
}
#[test]
fn test_mod_floor() {
let one: Mpz = From::<i64>::from(1);
let minusone: Mpz = From::<i64>::from(-1);
let two: Mpz = From::<i64>::from(2);
let minustwo: Mpz = From::<i64>::from(-2);
let three: Mpz = From::<i64>::from(3);
let minusthree: Mpz = From::<i64>::from(-3);
let eight: Mpz = From::<i64>::from(8);
let minuseight: Mpz = From::<i64>::from(-8);
assert_eq!(eight.mod_floor(&three), two);
assert_eq!(eight.mod_floor(&minusthree), minusone);
assert_eq!(minuseight.mod_floor(&three), one);
assert_eq!(minuseight.mod_floor(&minusthree), minustwo);
}
#[test]
fn test_bitand() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a & b);
assert!(mpza & mpzb == mpzres);
}
#[test]
fn test_bitor() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a | b);
assert!(mpza | mpzb == mpzres);
}
#[test]
fn test_bitxor() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a ^ b);
assert!(mpza ^ mpzb == mpzres);
}
#[test]
fn test_shifts() {
let i = 227;
let j: Mpz = From::<i64>::from(i);
assert!((i << 4).to_string() == (&j << 4).to_string());
assert!((-i << 4).to_string() == (-&j << 4).to_string());
assert!((i >> 4).to_string() == (&j >> 4).to_string());
assert!((-i >> 4).to_string() == (-&j >> 4).to_string());
}
#[test]
fn test_compl() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(-442);
assert!(a.compl().to_string() == (!13i32).to_string());
assert!(b.compl().to_string() == (!-442i32).to_string());
}
#[test]
fn test_pow() {
let a: Mpz = From::<i64>::from(2);
let b: Mpz = From::<i64>::from(8);
assert!(a.pow(3) == b);
assert!(Mpz::ui_pow_ui(2, 3) == b);
}
#[test]
fn test_powm() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(7);
let p: Mpz = From::<i64>::from(19);
let c: Mpz = From::<i64>::from(10);
assert!(a.powm(&b, &p) == c);
}
#[test]
fn test_powm_sec() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(7);
let p: Mpz = From::<i64>::from(19);
let c: Mpz = From::<i64>::from(10);
assert!(a.powm_sec(&b, &p) == c);
}
#[test]
fn test_popcount() {
Mpz::from_str_radix("1010010011", 2).unwrap().popcount() == 5;
}
#[test]
fn test_hamdist() {
let a: Mpz = From::<i64>::from(0b1011_0001);
let b: Mpz = From::<i64>::from(0b0010_1011);
assert!(a.hamdist(&b) == 4);
}
#[test]
fn test_bit_length() {
let a: Mpz = From::<i64>::from(0b1011_0000_0001_0000);
let b: Mpz = From::<i64>::from(0b101);
assert!(a.bit_length() == 16);
assert!(b.bit_length() == 3);
}
#[test]
fn test_probab_prime() {
let prime: Mpz = From::<i64>::from(2);
assert!(prime.probab_prime(15) == ProbabPrimeResult::Prime);
let not_prime: Mpz = From::<i64>::from(4);
assert!(not_prime.probab_prime(15) == ProbabPrimeResult::NotPrime);
}
#[test]
fn test_nextprime() {
let a: Mpz = From::<i64>::from(123456);
let b: Mpz = From::<i64>::from(123457);
assert!(a.nextprime() == b);
}
#[test]
fn test_gcd() {
let zero: Mpz = From::<i64>::from(0);
let three: Mpz = From::<i64>::from(3);
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
assert!(zero.gcd(&zero) == zero);
assert!(three.gcd(&six) == three);
assert!(eighteen.gcd(&twentyfour) == six);
}
#[test]
fn test_gcdext() {
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
let (g, s, t) = eighteen.gcdext(&twentyfour);
assert!(g == six);
assert!(g == s*eighteen + t*twentyfour);
}
#[test]
fn test_lcm() {
let zero: Mpz = From::<i64>::from(0);
let three: Mpz = From::<i64>::from(3);
let five: Mpz = From::<i64>::from(5);
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
let seventytwo: Mpz = From::<i64>::from(72);
assert!(zero.lcm(&five) == zero);
assert!(five.lcm(&zero) == zero);
assert!(three.lcm(&six) == six);
assert!(eighteen.lcm(&twentyfour) == seventytwo);
}
#[test]
fn test_is_multiple_of() {
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
let six: Mpz = From::<i64>::from(6);
assert!(six.is_multiple_of(&two));
assert!(six.is_multiple_of(&three));
assert!(!three.is_multiple_of(&two));
}
#[test]
fn test_modulus() {
let minusone: Mpz = From::<i64>::from(-1);
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
assert_eq!(two.modulus(&three), two);
assert_eq!(minusone.modulus(&three), two);
}
#[test]
fn test_invert() {
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
let four: Mpz = From::<i64>::from(4);
let five: Mpz = From::<i64>::from(5);
let eleven: Mpz = From::<i64>::from(11);
assert!(three.invert(&eleven) == Some(four.clone()));
assert!(four.invert(&eleven) == Some(three.clone()));
assert!(two.invert(&five) == Some(three.clone()));
assert!(three.invert(&five) == Some(two.clone()));
assert!(two.invert(&four).is_none());
}
#[test]
fn test_one() {
let onea: Mpz = From::<i64>::from(1);
let oneb: Mpz = From::<i64>::from(1);
assert!(onea == oneb);
}
#[test]
fn test_bit_fiddling() {
let mut xs: Mpz = From::<i64>::from(0b1010_1000_0010_0011);
assert!(xs.bit_length() == 16);
let mut ys = [true, false, true, false,
true, false, false, false,
false, false, true, false,
false, false, true, true];
ys.reverse();
for i in 0..xs.bit_length() {
assert!(xs.tstbit(i) == ys[i]);
}
xs.setbit(0);
ys[0] = true;
xs.setbit(3);
ys[3] = true;
xs.clrbit(1);
ys[1] = false;
xs.clrbit(5);
ys[5] = false;
xs.combit(14);
ys[14] = !ys[14];
xs.combit(15);
ys[15] = !ys[15];
for i in 0..xs.bit_length() {
assert!(xs.tstbit(i) == ys[i]);
}
}
#[test]
fn test_root() {
let x: Mpz = From::<i64>::from(123456);
let y: Mpz = From::<i64>::from(49);
assert!(x.root(3) == y);
}
#[test]
fn test_sqrt() {
let x: Mpz = From::<i64>::from(567);
let y: Mpz = From::<i64>::from(23);
assert!(x.sqrt() == y);
}
#[test]
fn test_hash_short() {
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let two = &one + &one;
let hash = |x : &Mpz| {
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
assert!(hash(&zero) != hash(&one));
assert_eq!(hash(&one), hash(&(&two - &one)));
}
#[test]
fn test_hash_long() {
let a = Mpz::from_str_radix("348917329847193287498312749187234192387", 10)
.unwrap();
let b = Mpz::from_str_radix("348917329847193287498312749187234192386", 10)
.unwrap();
let one: Mpz = From::<i64>::from(1);
let hash = |x : &Mpz| {
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
assert!(hash(&a) != hash(&b));
assert_eq!(hash(&a), hash(&(&b + &one)));
assert_eq!(hash(&(&a - &a)), hash(&(&one - &one)));
}
#[test]
fn test_to_vec_u8() {
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let xffff: Mpz = From::<i64>::from(65535);
let max_u64: Mpz = From::<u64>::from(u64::MAX);
assert_eq!(Into::<Vec<u8>>::into(&minus_five), vec!(5u8));
assert_eq!(Into::<Vec<u8>>::into(&minus_one), vec!(1u8));
assert_eq!(Into::<Vec<u8>>::into(&zero), vec!(0u8));
assert_eq!(Into::<Vec<u8>>::into(&one), vec!(1u8));
assert_eq!(Into::<Vec<u8>>::into(&five), vec!(5u8));
assert_eq!(Into::<Vec<u8>>::into(&xffff), vec!(255u8, 255u8));
assert_eq!(Into::<Vec<u8>>::into(&max_u64), vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8));
}
#[test]
fn test_to_u64() {
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let max_u64: Mpz = From::<u64>::from(u64::MAX);
assert_eq!(Into::<Option<u64>>::into(&minus_five), None);
assert_eq!(Into::<Option<u64>>::into(&minus_one), None);
assert_eq!(Into::<Option<u64>>::into(&zero), Some(0u64));
assert_eq!(Into::<Option<u64>>::into(&one), Some(1u64));
assert_eq!(Into::<Option<u64>>::into(&five), Some(5u64));
assert_eq!(Into::<Option<u64>>::into(&max_u64), Some(u64::MAX));
assert_eq!(Into::<Option<u64>>::into(&(&max_u64 + &one)), None);
}
#[test]
fn test_to_i64() {
let min_i64: Mpz = From::<i64>::from(i64::MIN);
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let max_i64: Mpz = From::<i64>::from(i64::MAX);
assert_eq!(Into::<Option<i64>>::into(&(&min_i64 - &one)), None);
assert_eq!(Into::<Option<i64>>::into(&min_i64), Some(i64::MIN));
assert_eq!(Into::<Option<i64>>::into(&minus_five), Some(-5i64));
assert_eq!(Into::<Option<i64>>::into(&minus_one), Some(-1i64));
assert_eq!(Into::<Option<i64>>::into(&zero), Some(0i64));
assert_eq!(Into::<Option<i64>>::into(&one), Some(1i64));
assert_eq!(Into::<Option<i64>>::into(&five), Some(5i64));
assert_eq!(Into::<Option<i64>>::into(&max_i64), Some(i64::MAX));
assert_eq!(Into::<Option<i64>>::into(&(&max_i64 + &one)), None);
}
#[test]
fn test_sign() {
let zero: Mpz = From::<i64>::from(0);
let five: Mpz = From::<i64>::from(5);
let minus_five: Mpz = From::<i64>::from(-5);
assert_eq!(zero.sign(), Sign::Zero);
assert_eq!(five.sign(), Sign::Positive);
assert_eq!(minus_five.sign(), Sign::Negative);
}
#[test]
fn test_format() {
let zero = Mpz::zero();
assert_eq!(format!("{}", zero), "0");
let zero = Mpz::from(-51213);
assert_eq!(format!("{}", zero), "-51213");
}
}
mod rand {
use std::convert::From;
use super::super::mpz::Mpz;
use super::super::rand::RandState;
#[test]
fn test_randstate() {
let mut state = RandState::new();
state.seed_ui(42);
for _ in 1u32..1000 {
for x in 1i64..10 {
let upper: Mpz = From::<i64>::from(x);
assert!(state.urandom(&upper) < upper);
}
}
}
}
mod mpq {
use std::convert::From;
use std::u64;
use super::super::mpq::Mpq;
use super::super::mpz::Mpz;
use super::super::sign::Sign;
#[test]
fn test_one() {
let onea: Mpq = From::<i64>::from(1);
let oneb: Mpq = From::<i64>::from(1);
assert!(onea == oneb);
}
#[test]
#[should_panic]
fn test_div_zero() {
let x: Mpq = From::<i64>::from(1);
let y = Mpq::new();
x / y;
}
#[test]
#[should_panic]
fn test_invert_zero() {
Mpq::new().invert();
}
#[test]
fn test_fmt() {
let fourty: Mpq = From::<i64>::from(40);
let six: Mpq = From::<i64>::from(6);
let fourty_sixths = &fourty / &six;
assert_eq!(format!("{:?}", fourty), "40");
assert_eq!(format!("{:?}", -&fourty), "-40");
assert_eq!(format!("{:?}", fourty_sixths), "20/3");
assert_eq!(format!("{:?}", -&fourty_sixths), "-20/3");
}
#[test]
fn test_floor() {
let half = Mpq::ratio(&Mpz::from(1), &Mpz::from(2));
assert_eq!(half.floor(), Mpz::from(0));
let big = Mpz::from(u64::MAX) * Mpz::from(u64::MAX);
let slightly_more_than_one = Mpq::ratio(&(&big + Mpz::from(1)), &big);
assert_eq!(slightly_more_than_one.floor(), Mpz::from(1));
let minus_half = -half;
assert_eq!(minus_half.floor(), Mpz::from(-1));
}
#[test]
fn test_ceil() {
let half = Mpq::ratio(&Mpz::from(1), &Mpz::from(2));
assert_eq!(half.ceil(), Mpz::from(1));
let minus_half = -half;
assert_eq!(minus_half.ceil(), Mpz::from(0));
}
#[test]
fn test_sign() {
let zero: Mpq = From::<i64>::from(0);
let five: Mpq = From::<i64>::from(5);
let minus_five: Mpq = From::<i64>::from(-5);
assert_eq!(zero.sign(), Sign::Zero);
assert_eq!(five.sign(), Sign::Positive);
assert_eq!(minus_five.sign(), Sign::Negative);
}
#[test]
fn test_ratio() {
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let minus_one = -&one;
let two = &one + &one;
let four = &two + &two;
assert_eq!(Mpq::ratio(&one, &minus_one), Mpq::ratio(&minus_one, &one));
assert_eq!(Mpq::ratio(&zero, &one), Mpq::ratio(&zero, &minus_one));
assert_eq!(Mpq::ratio(&zero, &one), Mpq::ratio(&zero, &two));
assert_eq!(Mpq::ratio(&two, &four), Mpq::ratio(&one, &two));
}
#[test]
fn test_from_str_radix() {
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let minus_one = -&one;
let two = &one + &one;
assert_eq!(Mpq::from_str_radix("1/-1", 10).unwrap(), Mpq::ratio(&minus_one, &one));
assert_eq!(Mpq::from_str_radix("0/2", 10).unwrap(), Mpq::ratio(&zero, &one));
assert_eq!(Mpq::from_str_radix("2/4", 10).unwrap(), Mpq::ratio(&one, &two));
}
}
mod mpf {
use super::super::mpf::Mpf;
use super::super::sign::Sign;
#[test]
#[should_panic]
fn test_div_zero() {
let x = Mpf::new(0);
&x / &x;
}
#[test]
fn test_sign() {
let zero = Mpf::zero();
let mut five = Mpf::zero();
Mpf::set_from_si(&mut five, 5);
let mut minus_five = Mpf::zero();
Mpf::set_from_si(&mut minus_five, -5);
assert_eq!(zero.sign(), Sign::Zero);
assert_eq!(five.sign(), Sign::Positive);
assert_eq!(minus_five.sign(), Sign::Negative);
}
}