number_theory/arithmetic/
mpz_arith.rs

1use crate::arithmetic::inlineops::*;
2use crate::arithmetic::muldiv::*;
3use crate::arithmetic::sliceops::*;
4use crate::Mpz;
5use crate::arithmetic::sign::Sign;
6use std::cmp::Ordering;
7use crate::ntrait::NumberTheory;
8
9impl std::cmp::PartialOrd for Mpz{
10    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
11        match (self.sign,other.sign){
12         (Sign::Negative,Sign::Positive) => Some(std::cmp::Ordering::Less),
13         (Sign::Positive,Sign::Negative) => Some(std::cmp::Ordering::Greater),
14         _=> Some(self.u_cmp(other)),
15       }
16     }  
17}
18
19impl std::cmp::Eq for Mpz{}
20
21impl std::cmp::Ord for Mpz{
22    fn cmp(&self,other: &Self) -> std::cmp::Ordering{
23       match (self.sign,other.sign){
24         (Sign::Negative,Sign::Positive) => std::cmp::Ordering::Less,
25         (Sign::Positive,Sign::Negative) => std::cmp::Ordering::Greater,
26         _=> self.u_cmp(other),
27       }
28        
29    }
30}
31
32impl Mpz {
33    /*
34      Shifting operations
35
36    */
37   /// Performs bitwise AND operation between x and y storing the result in x
38    pub fn mut_and(&mut self, other: &Self) {
39        for (i, j) in self.limbs.iter_mut().zip(other.limbs.iter()) {
40            *i &= j
41        }
42        self.limbs.truncate(other.len());
43        self.normalize();
44    }
45
46   /// Performs bitwise OR operation between x and y storing the result in x
47    pub fn mut_or(&mut self, other: &Self) {
48        for (i, j) in self.limbs.iter_mut().zip(other.limbs.iter()) {
49            *i |= j
50        }
51
52        if self.len() < other.len() {
53            self.limbs.extend_from_slice(&other.limbs[self.len()..])
54        }
55    }
56   /// Performs bitwise XOR operation between x and y storing the result in x
57    pub fn mut_xor(&mut self, other: &Self) {
58        for (i, j) in self.limbs.iter_mut().zip(other.limbs.iter()) {
59            *i ^= j
60        }
61
62        if self.len() < other.len() {
63            self.limbs.extend_from_slice(&other.limbs[self.len()..])
64        }
65    }
66  /// Performs bitwise NOT on x in-place
67    pub fn mut_not(&mut self) {
68        for i in self.limbs.iter_mut() {
69            *i = !*i
70        }
71        self.normalize();
72    }
73/// Shift-left k places in-place
74    pub fn mut_shl(&mut self, shift: usize) {
75        //let mut k = self.clone();
76        let mut trail_zeroes = vec![0; shift / 64usize];
77
78        let carry = shl_slice(&mut self.limbs[..], (shift % 64usize) as u32);
79
80        trail_zeroes.extend_from_slice(&self.limbs[..]);
81
82        if carry > 0 {
83            trail_zeroes.push(carry)
84        }
85
86        self.limbs = trail_zeroes;
87    }
88    
89/// Shift-left k places in-place
90    pub fn mut_shr(&mut self, shift: usize) {
91        let mut carry = 0u64;
92
93        let mut vector: Vec<u64> = self
94            .limbs
95            .drain((shift / 64usize)..self.limbs.len())
96            .collect();
97        let sub_shift = shift % 64usize;
98
99        for i in vector.iter_mut().rev() {
100            carry = carry_shr(carry, *i, sub_shift as u32, i);
101        }
102
103        self.limbs = vector;
104    }
105
106/// Returns x * 2^k
107    pub fn shl(&self, shift: usize) -> Mpz {
108        let mut k = self.clone();
109        k.mut_shl(shift);
110        k
111    }
112/// Returns x / 2^k
113    pub fn shr(&self, shift: usize) -> Mpz {
114        let mut k = self.clone();
115        k.mut_shr(shift);
116        k
117    }
118/// Returns x AND y 
119    pub fn and(&self, other: &Self) -> Self {
120        let mut k = self.clone();
121        k.mut_and(other);
122        k
123    }
124///  Returns x OR y 
125    pub fn or(&self, other: &Self) -> Self {
126        let mut k = self.clone();
127        k.mut_or(other);
128        k
129    }
130/// Returns x XOR y
131    pub fn xor(&self, other: &Self) -> Self {
132        let mut k = self.clone();
133        k.mut_xor(other);
134        k
135    }
136
137    /*
138        Arithmetic operations
139    */
140   /// x+y stored in x
141    pub fn mut_addition(&mut self, mut other: Self) {
142        let carry: u8;
143
144        if self.sign == other.sign {
145            if self.limbs.len() < other.limbs.len() {
146                let len = self.len();
147                self.limbs.extend_from_slice(&other.limbs[len..]);
148                carry = add_slice(&mut self.limbs[..], &other.limbs[..len]);
149            } else {
150                carry = add_slice(&mut self.limbs[..], &other.limbs[..]);
151            }
152            if carry == 1u8 {
153                self.limbs.push(1u64)
154            }
155        } else {
156            if self.u_cmp(&other) == Ordering::Less {
157                sub_slice(&mut other.limbs[..], &self.limbs[..]);
158                *self = other;
159                self.normalize();
160            } else if self.u_cmp(&other) == Ordering::Equal {
161                self.limbs.truncate(0);
162                self.limbs.push(0);
163                self.sign = Sign::Positive;
164            } else {
165                sub_slice(&mut self.limbs[..], &other.limbs[..]);
166                self.normalize();
167            }
168        }
169    }
170   /// Returns x+y 
171    pub fn ref_addition(&self, other: &Self) -> Self {
172        let mut k = self.clone();
173        k.mut_addition(other.clone());
174        k
175    }
176   /// x-y stored in x 
177    pub fn mut_subtraction(&mut self, mut other: Self) {
178        other.neg();
179        self.mut_addition(other)
180    }
181    /// Returns x-y
182    pub fn ref_subtraction(&self, other: &Self) -> Self {
183        let mut k = self.clone();
184        k.mut_subtraction(other.clone());
185        k
186    }
187   /// Returns x*y 
188    pub fn ref_product(&self, other: &Self) -> Self {
189        if self == &Mpz::zero() {
190            return Mpz::zero();
191        }
192
193        if other == &Mpz::zero() {
194            return Mpz::zero();
195        }
196
197        if self.is_unit() {
198            return Mpz::unchecked_new(self.sign.mul(&other.sign), other.limbs.clone());
199        }
200
201        if other.is_unit() {
202            return Mpz::unchecked_new(self.sign.mul(&other.sign), self.limbs.clone());
203        }
204
205        let mut t = vec![0u64; self.len() + other.len() + 1];
206
207        mul_slice(&self.limbs[..], &other.limbs[..], &mut t[..]);
208        remove_lead_zeros(&mut t);
209        Mpz::unchecked_new(self.sign.mul(&other.sign), t)
210    }
211
212/// x*y stored in x 
213    pub fn mut_product(&mut self, other: Self) {
214        if self == &Mpz::zero() {}
215
216        if other == Mpz::zero() {
217            self.limbs.truncate(0);
218            self.limbs.push(0u64);
219            self.sign = Sign::Positive;
220        }
221
222        if self.is_unit() {
223            self.limbs.truncate(0);
224            self.limbs.extend_from_slice(&other.limbs[..]);
225            self.sign = self.sign.mul(&other.sign);
226        }
227
228        if other.is_unit() {
229            self.sign = self.sign.mul(&other.sign);
230        } else {
231            let mut t = vec![0u64; self.len() + other.len() + 1];
232
233            mul_slice(&self.limbs[..], &other.limbs[..], &mut t[..]);
234            remove_lead_zeros(&mut t);
235            self.limbs = t;
236            self.sign = self.sign.mul(&other.sign);
237        }
238    }
239    /// Unsigned in-place multiply by x and add y 
240    pub fn mut_scale_add(&mut self, x: u64, y: u64){
241     let mut carry = scale_slice(&mut self.limbs[..],x);
242     carry += add_slice(&mut self.limbs[..],&[y]) as u64;
243     if carry > 0{
244       self.limbs.push(carry);
245     }
246    }
247    
248     /// Unsigned in-place multiply by x and add y 
249    pub fn scale_add(&self, x: u64, y: u64) -> Self{
250     let mut k = self.clone();
251     k.mut_scale_add(x,y);
252     k
253    }
254    
255    
256    /// x*x squaring 
257    pub fn sqr(&self) -> Self {
258      self.ref_product(self)
259    }
260    
261    /// x*x squaring in-place
262    pub fn mut_sqr(&mut self){
263      self.mut_product(self.clone());
264    }
265        
266  /// Returns x/y and x mod y 
267    pub fn ref_euclidean(&self, other: &Self) -> (Self, Self) {
268        let mut dividend = Mpz::from_slice(Sign::Positive, &self.limbs[..]);
269
270        if dividend == Mpz::zero() {
271            return (Mpz::zero(), Mpz::zero());
272        }
273
274        if dividend.len() == 0usize {
275            return (Mpz::zero(), Mpz::zero());
276        }
277
278        if other.len() == 0usize || other == &Mpz::zero() {
279            panic!("Division by zero is undefined in Z")
280        }
281
282        if other.len() == 1 {
283            if other.limbs == [1] {
284                return (dividend, Mpz::zero());
285            }
286
287            let rem = div_slice(&mut dividend.limbs, other.limbs[0]);
288
289            remove_lead_zeros(&mut dividend.limbs);
290            return (dividend, Mpz::unchecked_new(Sign::Positive, vec![rem]));
291        }
292
293        if dividend.u_cmp(other) == Ordering::Equal {
294            return (Mpz::one(), Mpz::zero());
295        }
296
297        if dividend.u_cmp(other) == Ordering::Less {
298            return (Mpz::zero(), dividend);
299        }
300
301        let shift = other.limbs.last().unwrap().leading_zeros() as usize;
302
303        if shift == 0 {
304            let (quo, rem) = euclidean_slice(&mut dividend.limbs, &other.limbs[..]);
305            (
306                Mpz::unchecked_new(Sign::Positive, quo),
307                Mpz::unchecked_new(Sign::Positive, rem),
308            )
309        } else {
310            let (q, r) =
311                euclidean_slice(&mut dividend.shl(shift).limbs, &other.shl(shift).limbs[..]);
312
313            (
314                Mpz::unchecked_new(Sign::Positive, q),
315                Mpz::unchecked_new(Sign::Positive, r).shr(shift),
316            )
317        }
318    }
319}