mirror of https://github.com/poanetwork/vdf.git
Make ready for publication
This commit is contained in:
parent
7fd43b8b79
commit
1016cb998a
|
@ -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.
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/target/
|
||||
Cargo.lock
|
||||
*.swp
|
|
@ -0,0 +1,4 @@
|
|||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y libgmp3-dev
|
||||
language: rust
|
|
@ -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"
|
|
@ -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.
|
|
@ -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)
|
|
@ -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 }
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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^n−1, 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 }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)]
|
||||
pub enum Sign {
|
||||
Negative,
|
||||
Zero,
|
||||
Positive,
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue