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 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}