gmp/
mpq.rs

1use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr};
2use super::mpf::{Mpf, mpf_srcptr};
3use super::sign::Sign;
4use ffi::*;
5use libc::{c_char, c_double, c_int, c_ulong};
6use std::ffi::CString;
7use std::str::FromStr;
8use std::error::Error;
9use std::convert::From;
10use std::mem::uninitialized;
11use std::fmt;
12use std::cmp::Ordering::{self, Greater, Less, Equal};
13use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
14use num_traits::{Zero, One};
15
16#[repr(C)]
17pub struct mpq_struct {
18    _mp_num: mpz_struct,
19    _mp_den: mpz_struct
20}
21
22pub type mpq_srcptr = *const mpq_struct;
23pub type mpq_ptr = *mut mpq_struct;
24
25#[link(name = "gmp")]
26extern "C" {
27    fn __gmpq_init(x: mpq_ptr);
28    fn __gmpq_clear(x: mpq_ptr);
29    fn __gmpq_set(rop: mpq_ptr, op: mpq_srcptr);
30    fn __gmpq_set_z(rop: mpq_ptr, op: mpz_srcptr);
31    fn __gmpq_set_ui(rop: mpq_ptr, op1: c_ulong, op2: c_ulong);
32    fn __gmpq_set_d(rop: mpq_ptr, op: c_double);
33    fn __gmpq_set_f(rop: mpq_ptr, op: mpf_srcptr);
34    fn __gmpq_cmp(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
35    fn __gmpq_cmp_ui(op1: mpq_srcptr, num2: c_ulong, den2: c_ulong) -> c_int;
36    fn __gmpq_equal(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
37    fn __gmpq_add(sum: mpq_ptr, addend1: mpq_srcptr, addend2: mpq_srcptr);
38    fn __gmpq_sub(difference: mpq_ptr, minuend: mpq_srcptr, subtrahend: mpq_srcptr);
39    fn __gmpq_mul(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
40    fn __gmpq_div(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
41    fn __gmpq_neg(negated_operand: mpq_ptr, operand: mpq_srcptr);
42    fn __gmpq_abs(rop: mpq_ptr, op: mpq_srcptr);
43    fn __gmpq_inv(inverted_number: mpq_ptr, number: mpq_srcptr);
44    fn __gmpq_get_num(numerator: mpz_ptr, rational: mpq_srcptr);
45    fn __gmpq_get_den(denominator: mpz_ptr, rational: mpq_srcptr);
46    fn __gmpq_set_num(rational: mpq_ptr, numerator: mpz_srcptr);
47    fn __gmpq_set_den(rational: mpq_ptr, denominator: mpz_srcptr);
48    fn __gmpq_canonicalize(rational: mpq_ptr);
49    fn __gmpq_get_d(rational: mpq_srcptr) -> c_double;
50    fn __gmpq_set_str(rop: mpq_ptr, str: *const c_char, base: c_int) -> c_int;
51}
52
53pub struct Mpq {
54    mpq: mpq_struct,
55}
56
57unsafe impl Send for Mpq { }
58unsafe impl Sync for Mpq { }
59
60impl Drop for Mpq {
61    fn drop(&mut self) { unsafe { __gmpq_clear(&mut self.mpq) } }
62}
63
64impl Mpq {
65    pub unsafe fn inner(&self) -> mpq_srcptr {
66        &self.mpq
67    }
68
69    pub unsafe fn inner_mut(&mut self) -> mpq_ptr {
70        &mut self.mpq
71    }
72
73    pub fn new() -> Mpq {
74        unsafe {
75            let mut mpq = uninitialized();
76            __gmpq_init(&mut mpq);
77            Mpq { mpq: mpq }
78        }
79    }
80
81    pub fn ratio(num: &Mpz, den: &Mpz) -> Mpq {
82        unsafe {
83            let mut res = Mpq::new();
84            __gmpq_set_num(&mut res.mpq, num.inner());
85            __gmpq_set_den(&mut res.mpq, den.inner());
86            // Not canonicalizing is unsafe
87            __gmpq_canonicalize(&mut res.mpq);
88            res
89        }
90    }
91
92    pub fn from_str_radix(s: &str, base: u8) -> Result<Mpq, ParseMpqError> {
93        let s = CString::new(s).map_err(|_| ParseMpqError { _priv: () })?;
94        let mut res = Mpq::new();
95        unsafe {
96            assert!(base == 0 || (base >= 2 && base <= 62));
97            let r = __gmpq_set_str(&mut res.mpq, s.as_ptr(), base as c_int);
98
99            if r == 0 {
100                // Not canonicalizing is unsafe
101                __gmpq_canonicalize(&mut res.mpq);
102                Ok(res)
103            } else {
104                Err(ParseMpqError { _priv: () })
105            }
106        }
107    }
108
109    pub fn set(&mut self, other: &Mpq) {
110        unsafe { __gmpq_set(&mut self.mpq, &other.mpq) }
111    }
112
113    pub fn set_z(&mut self, other: &Mpz) {
114        unsafe { __gmpq_set_z(&mut self.mpq, other.inner()) }
115    }
116
117    pub fn set_d(&mut self, other: f64) {
118        unsafe { __gmpq_set_d(&mut self.mpq, other) }
119    }
120
121    pub fn set_f(&mut self, other: &Mpf) {
122        unsafe { __gmpq_set_f(&mut self.mpq, other.inner()) }
123    }
124
125    pub fn get_num(&self) -> Mpz {
126        unsafe {
127            let mut res = Mpz::new();
128            __gmpq_get_num(res.inner_mut(), &self.mpq);
129            res
130        }
131    }
132
133    pub fn get_den(&self) -> Mpz {
134        unsafe {
135            let mut res = Mpz::new();
136            __gmpq_get_den(res.inner_mut(), &self.mpq);
137            res
138        }
139    }
140
141    pub fn abs(&self) -> Mpq {
142        unsafe {
143            let mut res = Mpq::new();
144            __gmpq_abs(&mut res.mpq, &self.mpq);
145            res
146        }
147    }
148
149    pub fn invert(&self) -> Mpq {
150        unsafe {
151            if self.is_zero() {
152                panic!("divide by zero")
153            }
154
155            let mut res = Mpq::new();
156            __gmpq_inv(&mut res.mpq, &self.mpq);
157            res
158        }
159    }
160
161    pub fn floor(&self) -> Mpz {
162        let mut res = Mpz::new();
163        unsafe {
164            __gmpz_fdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
165        }
166        res
167    }
168
169    pub fn ceil(&self) -> Mpz {
170        let mut res = Mpz::new();
171        unsafe {
172            __gmpz_cdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
173        }
174        res
175    }
176
177    pub fn sign(&self) -> Sign {
178        self.get_num().sign()
179    }
180
181    pub fn one() -> Mpq {
182        let mut res = Mpq::new();
183        unsafe { __gmpq_set_ui(&mut res.mpq, 1, 1) }
184        res
185    }
186
187    pub fn zero() -> Mpq { Mpq::new() }
188    pub fn is_zero(&self) -> bool {
189        unsafe { __gmpq_cmp_ui(&self.mpq, 0, 1) == 0 }
190    }
191}
192
193#[derive(Debug)]
194pub struct ParseMpqError {
195    _priv: ()
196}
197
198impl fmt::Display for ParseMpqError {
199    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200        self.description().fmt(f)
201    }
202}
203
204impl Error for ParseMpqError {
205    fn description(&self) -> &'static str {
206        "invalid rational number"
207    }
208
209    fn cause(&self) -> Option<&'static Error> {
210        None
211    }
212}
213
214impl Clone for Mpq {
215    fn clone(&self) -> Mpq {
216        let mut res = Mpq::new();
217        res.set(self);
218        res
219    }
220}
221
222impl Eq for Mpq { }
223impl PartialEq for Mpq {
224    fn eq(&self, other: &Mpq) -> bool {
225        unsafe { __gmpq_equal(&self.mpq, &other.mpq) != 0 }
226    }
227}
228
229impl Ord for Mpq {
230    fn cmp(&self, other: &Mpq) -> Ordering {
231        let cmp = unsafe { __gmpq_cmp(&self.mpq, &other.mpq) };
232        if cmp == 0 {
233            Equal
234        } else if cmp < 0 {
235            Less
236        } else {
237            Greater
238        }
239    }
240}
241impl PartialOrd for Mpq {
242    fn partial_cmp(&self, other: &Mpq) -> Option<Ordering> {
243        Some(self.cmp(other))
244    }
245}
246
247macro_rules! div_guard {
248    (Div, $what: expr) => {
249        if $what.is_zero() {
250            panic!("divide by zero")
251        }
252    };
253    ($tr: ident, $what: expr) => {}
254}
255
256macro_rules! impl_oper {
257    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
258        impl $tr<Mpq> for Mpq {
259            type Output = Mpq;
260            #[inline]
261            fn $meth(self, other: Mpq) -> Mpq {
262                self.$meth(&other)
263            }
264        }
265
266        impl<'a> $tr<&'a Mpq> for Mpq {
267            type Output = Mpq;
268            #[inline]
269            fn $meth(mut self, other: &Mpq) -> Mpq {
270                self.$meth_assign(other);
271                self
272            }
273        }
274
275        impl<'a> $tr<Mpq> for &'a Mpq {
276            type Output = Mpq;
277            #[inline]
278            fn $meth(self, mut other: Mpq) -> Mpq {
279                unsafe {
280                    div_guard!($tr, other);
281                    $fun(&mut other.mpq, &self.mpq, &other.mpq);
282                    other
283                }
284            }
285        }
286
287        impl<'a, 'b> $tr<&'a Mpq> for &'b Mpq {
288            type Output = Mpq;
289            fn $meth(self, other: &Mpq) -> Mpq {
290                unsafe {
291                    div_guard!($tr, *other);
292                    let mut res = Mpq::new();
293                    $fun(&mut res.mpq, &self.mpq, &other.mpq);
294                    res
295                }
296            }
297        }
298
299        impl<'a> $tr_assign<Mpq> for Mpq {
300            #[inline]
301            fn $meth_assign(&mut self, other: Mpq) {
302                self.$meth_assign(&other)
303            }
304        }
305
306        impl<'a> $tr_assign<&'a Mpq> for Mpq {
307            #[inline]
308            fn $meth_assign(&mut self, other: &Mpq) {
309                unsafe {
310                    div_guard!($tr, *other);
311                    $fun(&mut self.mpq, &self.mpq, &other.mpq)
312                }
313            }
314        }
315    }
316}
317
318impl_oper!(Add, add, AddAssign, add_assign, __gmpq_add);
319impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpq_sub);
320impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpq_mul);
321impl_oper!(Div, div, DivAssign, div_assign, __gmpq_div);
322
323impl<'b> Neg for &'b Mpq {
324    type Output = Mpq;
325    fn neg(self) -> Mpq {
326        unsafe {
327            let mut res = Mpq::new();
328            __gmpq_neg(&mut res.mpq, &self.mpq);
329            res
330        }
331    }
332}
333
334impl Neg for Mpq {
335    type Output = Mpq;
336    #[inline]
337    fn neg(mut self) -> Mpq {
338        unsafe {
339            __gmpq_neg(&mut self.mpq, &self.mpq);
340            self
341        }
342    }
343}
344
345impl From<Mpq> for f64 {
346    fn from(other: Mpq) -> f64 {
347        f64::from(&other)
348    }
349}
350
351impl<'a> From<&'a Mpq> for f64 {
352    fn from(other: &Mpq) -> f64 {
353        unsafe {
354            __gmpq_get_d(&other.mpq) as f64
355        }
356    }
357}
358
359impl From<Mpz> for Mpq {
360    fn from(other: Mpz) -> Mpq {
361        Mpq::from(&other)
362    }
363}
364
365impl<'a> From<&'a Mpz> for Mpq {
366    fn from(other: &Mpz) -> Mpq {
367        let mut res = Mpq::new();
368        res.set_z(&other);
369        res
370    }
371}
372
373impl From<i64> for Mpq {
374    fn from(other: i64) -> Mpq {
375        From::<Mpz>::from(From::<i64>::from(other))
376    }
377}
378
379impl From<i32> for Mpq {
380    fn from(other: i32) -> Mpq {
381        From::<Mpz>::from(From::<i32>::from(other))
382    }
383}
384
385impl From<u64> for Mpq {
386    fn from(other: u64) -> Mpq {
387        From::<Mpz>::from(From::<u64>::from(other))
388    }
389}
390
391impl From<u32> for Mpq {
392    fn from(other: u32) -> Mpq {
393        From::<Mpz>::from(From::<u32>::from(other))
394    }
395}
396
397impl FromStr for Mpq {
398    type Err = ParseMpqError;
399    fn from_str(s: &str) -> Result<Mpq, ParseMpqError> {
400        Mpq::from_str_radix(s, 10)
401    }
402}
403
404
405impl fmt::Debug for Mpq {
406    /// Renders as `numer/denom`. If denom=1, renders as numer.
407    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
408        fmt::Display::fmt(&self, f)
409    }
410}
411
412impl fmt::Display for Mpq {
413    /// Renders as `numer/denom`. If denom=1, renders as numer.
414    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415        let numer = self.get_num();
416        let denom = self.get_den();
417
418        if denom == From::<i64>::from(1) {
419            write!(f, "{}", numer)
420        } else {
421            write!(f, "{}/{}", numer, denom)
422        }
423    }
424}
425
426impl Zero for Mpq {
427    #[inline]
428    fn zero() -> Mpq {
429        Mpq::zero()
430    }
431
432    #[inline]
433    fn is_zero(&self) -> bool {
434        self.is_zero()
435    }
436}
437
438impl One for Mpq {
439    #[inline]
440    fn one() -> Mpq {
441        Mpq::one()
442    }
443}