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}