gmp/
mpf.rs

1use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char, free};
2use std;
3use std::mem::uninitialized;
4use std::cmp;
5use std::cmp::Ordering::{self, Greater, Less, Equal};
6use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
7use std::ffi::CString;
8use std::string::String;
9use super::mpz::mp_bitcnt_t;
10use super::mpz::{Mpz, mpz_srcptr};
11use super::mpq::{Mpq, mpq_srcptr};
12use super::sign::Sign;
13use num_traits::{Zero, One};
14
15type mp_exp_t = c_long;
16
17#[repr(C)]
18pub struct mpf_struct {
19    _mp_prec: c_int,
20    _mp_size: c_int,
21    _mp_exp: mp_exp_t,
22    _mp_d: *mut c_void
23}
24
25pub type mpf_srcptr = *const mpf_struct;
26pub type mpf_ptr = *mut mpf_struct;
27
28#[link(name = "gmp")]
29extern "C" {
30    fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
31    fn __gmpf_init_set(rop: mpf_ptr, op: mpf_srcptr);
32    fn __gmpf_clear(x: mpf_ptr);
33    fn __gmpf_get_prec(op: mpf_srcptr) -> mp_bitcnt_t;
34    fn __gmpf_set_prec(rop: mpf_ptr, prec: mp_bitcnt_t);
35    fn __gmpf_set(rop: mpf_ptr, op: mpf_srcptr);
36    fn __gmpf_set_z(rop: mpf_ptr, op: mpz_srcptr);
37    fn __gmpf_set_q(rop: mpf_ptr, op: mpq_srcptr);
38
39    fn __gmpf_set_str(rop: mpf_ptr, str: *const c_char, base: c_int);
40    fn __gmpf_set_si(rop: mpf_ptr, op: c_long);
41    fn __gmpf_get_str(str: *const c_char, expptr: *const mp_exp_t, base: i32, n_digits: i32, op: mpf_ptr) -> *mut c_char;
42
43    fn __gmpf_cmp(op1: mpf_srcptr, op2: mpf_srcptr) -> c_int;
44    fn __gmpf_cmp_d(op1: mpf_srcptr, op2: c_double) -> c_int;
45    fn __gmpf_cmp_ui(op1: mpf_srcptr, op2: c_ulong) -> c_int;
46    fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int;
47    fn __gmpf_reldiff(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
48    fn __gmpf_add(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
49    fn __gmpf_sub(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
50    fn __gmpf_mul(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
51    fn __gmpf_div(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
52    fn __gmpf_neg(rop: mpf_ptr, op: mpf_srcptr);
53    fn __gmpf_abs(rop: mpf_ptr, op: mpf_srcptr);
54    fn __gmpf_ceil(rop: mpf_ptr, op: mpf_srcptr);
55    fn __gmpf_floor(rop: mpf_ptr, op: mpf_srcptr);
56    fn __gmpf_trunc(rop: mpf_ptr, op: mpf_srcptr);
57    fn __gmpf_sqrt(rop: mpf_ptr, op: mpf_srcptr);
58}
59
60pub struct Mpf {
61    mpf: mpf_struct,
62}
63
64unsafe impl Send for Mpf { }
65unsafe impl Sync for Mpf { }
66
67impl Drop for Mpf {
68    fn drop(&mut self) { unsafe { __gmpf_clear(&mut self.mpf) } }
69}
70
71impl Mpf {
72    pub unsafe fn inner(&self) -> mpf_srcptr {
73        &self.mpf
74    }
75
76    pub unsafe fn inner_mut(&mut self) -> mpf_ptr {
77        &mut self.mpf
78    }
79
80    pub fn zero() -> Mpf { Mpf::new(32) }
81
82    pub fn new(precision: usize) -> Mpf {
83        unsafe {
84            let mut mpf = uninitialized();
85            __gmpf_init2(&mut mpf, precision as c_ulong);
86            Mpf { mpf: mpf }
87        }
88    }
89
90    pub fn set(&mut self, other: &Mpf) {
91        unsafe { __gmpf_set(&mut self.mpf, &other.mpf) }
92    }
93
94    pub fn set_z(&mut self, other: &Mpz) {
95        unsafe { __gmpf_set_z(&mut self.mpf, other.inner()) }
96    }
97
98    pub fn set_q(&mut self, other: &Mpq) {
99        unsafe { __gmpf_set_q(&mut self.mpf, other.inner()) }
100    }
101
102    pub fn get_prec(&self) -> usize {
103        unsafe { __gmpf_get_prec(&self.mpf) as usize }
104    }
105
106    pub fn set_prec(&mut self, precision: usize) {
107        unsafe { __gmpf_set_prec(&mut self.mpf, precision as c_ulong) }
108    }
109
110    pub fn set_from_str(&mut self, string: &str, base: i32){
111        let c_str = CString::new(string).unwrap();
112        unsafe {
113            __gmpf_set_str(&mut self.mpf, c_str.as_ptr(), base as c_int);
114        }
115    }
116
117    pub fn set_from_si(&mut self, int: i64){
118        unsafe{
119            __gmpf_set_si(&mut self.mpf,int as c_long);
120        }
121    }
122
123    pub fn get_str(&mut self, n_digits: i32, base: i32, exp: &mut c_long) -> String{
124	let out;
125        unsafe{
126            out = CString::from_raw(__gmpf_get_str(std::ptr::null(), exp, base, n_digits, &mut self.mpf));
127        }
128        let r = out.to_str().unwrap().to_string();
129	// Free the pointer returned to us, as r already took a copy of the data inside of it
130	// Stops memory leaking
131	unsafe { free(out.into_raw() as _) };
132	r
133    }
134
135    pub fn abs(&self) -> Mpf {
136        unsafe {
137            let mut res = Mpf::new(self.get_prec());
138            __gmpf_abs(&mut res.mpf, &self.mpf);
139            res
140        }
141    }
142
143    pub fn ceil(&self) -> Mpf {
144        unsafe {
145            let mut res = Mpf::new(self.get_prec());
146            __gmpf_ceil(&mut res.mpf, &self.mpf);
147            res
148        }
149    }
150
151    pub fn floor(&self) -> Mpf {
152        unsafe {
153            let mut res = Mpf::new(self.get_prec());
154            __gmpf_floor(&mut res.mpf, &self.mpf);
155            res
156        }
157    }
158
159    pub fn trunc(&self) -> Mpf {
160        unsafe {
161            let mut res = Mpf::new(self.get_prec());
162            __gmpf_trunc(&mut res.mpf, &self.mpf);
163            res
164        }
165    }
166
167    pub fn reldiff(&self, other: &Mpf) -> Mpf {
168        unsafe {
169            let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
170            __gmpf_reldiff(&mut res.mpf, &self.mpf, &other.mpf);
171            res
172        }
173    }
174
175    pub fn sqrt(self) -> Mpf {
176        let mut retval:Mpf;
177        unsafe {
178            retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize);
179            retval.set_from_si(0);
180            if __gmpf_cmp_si(&self.mpf, 0) > 0 {
181                __gmpf_sqrt(&mut retval.mpf, &self.mpf);
182            } else {
183                panic!("Square root of negative/zero");
184            }
185        }
186        retval
187    }
188
189    pub fn sign(&self) -> Sign {
190        let size = self.mpf._mp_size;
191        if size == 0 {
192            Sign::Zero
193        } else if size > 0 {
194            Sign::Positive
195        } else {
196            Sign::Negative
197        }
198    }
199}
200
201impl Clone for Mpf {
202    fn clone(&self) -> Mpf {
203        unsafe {
204            let mut mpf = uninitialized();
205            __gmpf_init_set(&mut mpf, &self.mpf);
206            Mpf { mpf: mpf }
207        }
208    }
209}
210
211impl Eq for Mpf { }
212impl PartialEq for Mpf {
213    fn eq(&self, other: &Mpf) -> bool {
214        unsafe { __gmpf_cmp(&self.mpf, &other.mpf) == 0 }
215    }
216}
217
218impl Ord for Mpf {
219    fn cmp(&self, other: &Mpf) -> Ordering {
220        let cmp = unsafe { __gmpf_cmp(&self.mpf, &other.mpf) };
221        if cmp == 0 {
222            Equal
223        } else if cmp > 0 {
224            Greater
225        } else {
226            Less
227        }
228    }
229}
230
231impl PartialOrd for Mpf {
232    fn partial_cmp(&self, other: &Mpf) -> Option<Ordering> {
233        Some(self.cmp(other))
234    }
235}
236
237macro_rules! div_guard {
238    (Div, $is_zero: expr) => {
239        if $is_zero {
240            panic!("divide by zero")
241        }
242    };
243    ($tr: ident, $what: expr) => {}
244}
245
246macro_rules! impl_oper {
247    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
248        impl<'a> $tr<Mpf> for &'a Mpf {
249            type Output = Mpf;
250            #[inline]
251            fn $meth(self, other: Mpf) -> Mpf {
252                self.$meth(&other)
253            }
254        }
255
256        impl<'a> $tr<&'a Mpf> for Mpf {
257            type Output = Mpf;
258            #[inline]
259            fn $meth(mut self, other: &Mpf) -> Mpf {
260                self.$meth_assign(other);
261                self
262            }
263        }
264
265        impl $tr<Mpf> for Mpf {
266            type Output = Mpf;
267            #[inline]
268            fn $meth(self, other: Mpf) -> Mpf {
269                self.$meth(&other)
270            }
271        }
272
273        impl<'a, 'b> $tr<&'a Mpf> for &'b Mpf {
274            type Output = Mpf;
275            fn $meth(self, other: &Mpf) -> Mpf {
276                unsafe {
277                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
278                    let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
279                    $fun(&mut res.mpf, &self.mpf, &other.mpf);
280                    res
281                }
282            }
283        }
284
285        impl<'a> $tr_assign<Mpf> for Mpf {
286            #[inline]
287            fn $meth_assign(&mut self, other: Mpf) {
288                self.$meth_assign(&other)
289            }
290        }
291
292        impl<'a> $tr_assign<&'a Mpf> for Mpf {
293            #[inline]
294            fn $meth_assign(&mut self, other: &Mpf) {
295                unsafe {
296                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
297                    $fun(&mut self.mpf, &self.mpf, &other.mpf)
298                }
299            }
300        }
301    }
302}
303
304impl_oper!(Add, add, AddAssign, add_assign, __gmpf_add);
305impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpf_sub);
306impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpf_mul);
307impl_oper!(Div, div, DivAssign, div_assign, __gmpf_div);
308
309
310impl<'b> Neg for &'b Mpf {
311    type Output = Mpf;
312    fn neg(self) -> Mpf {
313        unsafe {
314            let mut res = Mpf::new(self.get_prec());
315            __gmpf_neg(&mut res.mpf, &self.mpf);
316            res
317        }
318    }
319}
320
321impl Neg for Mpf {
322    type Output = Mpf;
323    #[inline]
324    fn neg(mut self) -> Mpf {
325        unsafe {
326            __gmpf_neg(&mut self.mpf, &self.mpf);
327            self
328        }
329    }
330}
331
332impl Zero for Mpf {
333    #[inline]
334    fn zero() -> Mpf {
335        Mpf::zero()
336    }
337
338    #[inline]
339    fn is_zero(&self) -> bool {
340        unsafe {
341            __gmpf_cmp_ui(&self.mpf, 0) == 0
342        }
343    }
344}
345
346impl One for Mpf {
347    #[inline]
348    fn one() -> Mpf {
349        let mut res = Mpf::new(32);
350        res.set_from_si(1);
351        res
352    }
353}