gmp/
mpf.rs

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