astro_float_num/common/
int.rs

1//! Lightweigh integer.
2
3use crate::common::util::add_carry;
4use crate::common::util::shift_slice_right;
5use crate::common::util::{shift_slice_left, sub_borrow};
6use crate::defs::{DoubleWord, SignedWord, Word, WORD_BASE, WORD_MAX};
7use core::ops::Deref;
8use core::ops::DerefMut;
9use itertools::izip;
10
11// Internal repr of SliceWithSign.
12#[derive(Debug)]
13enum SliceWithSignType<'a> {
14    Mut(&'a mut [Word]),
15    Immut(&'a [Word]),
16}
17
18// Slice of words with sign is a lightweight integer number representation.
19#[derive(Debug)]
20pub struct SliceWithSign<'a> {
21    m: SliceWithSignType<'a>,
22    sign: i8,
23}
24
25impl<'a> SliceWithSign<'a> {
26    pub fn new_mut(m: &'a mut [Word], sign: i8) -> Self {
27        SliceWithSign {
28            m: SliceWithSignType::Mut(m),
29            sign,
30        }
31    }
32
33    pub fn new(m: &'a [Word], sign: i8) -> Self {
34        SliceWithSign {
35            m: SliceWithSignType::Immut(m),
36            sign,
37        }
38    }
39
40    #[inline]
41    pub fn add(&self, s2: &SliceWithSign<'_>, dst: &mut SliceWithSign<'_>) {
42        self.add_sub(s2, dst, 1);
43    }
44
45    #[inline]
46    pub fn sub(&self, s2: &SliceWithSign<'_>, dst: &mut SliceWithSign<'_>) {
47        self.add_sub(s2, dst, -1);
48    }
49
50    #[inline]
51    pub fn add_assign(&mut self, s2: &SliceWithSign<'_>) {
52        self.add_sub_assign(s2, 1);
53    }
54
55    #[inline]
56    pub fn sub_assign(&mut self, s2: &SliceWithSign<'_>) {
57        self.add_sub_assign(s2, -1);
58    }
59
60    fn add_sub(&self, s2: &SliceWithSign<'_>, dst: &mut SliceWithSign<'_>, op: i8) {
61        if (self.sign != s2.sign && op > 0) || (op < 0 && self.sign == s2.sign) {
62            // subtract
63            let cmp = Self::abs_cmp(self, s2);
64
65            if cmp > 0 {
66                dst.sign = self.sign;
67                Self::abs_sub(self, s2, dst);
68            } else if cmp < 0 {
69                dst.sign = s2.sign * op;
70                Self::abs_sub(s2, self, dst);
71            } else {
72                dst.fill(0);
73            };
74        } else {
75            dst.sign = self.sign;
76            Self::abs_add(self, s2, dst);
77        }
78    }
79
80    fn add_sub_assign(&mut self, s2: &SliceWithSign<'_>, op: i8) {
81        if (self.sign != s2.sign && op > 0) || (op < 0 && self.sign == s2.sign) {
82            // subtract
83            let cmp = Self::abs_cmp(self, s2);
84            if cmp > 0 {
85                Self::abs_sub_assign_1(self, s2);
86            } else if cmp < 0 {
87                Self::abs_sub_assign_2(self, s2);
88                self.sign = s2.sign * op;
89            } else {
90                self.fill(0);
91            };
92        } else {
93            Self::abs_add_assign(self, s2);
94        }
95    }
96
97    #[cfg(test)]
98    pub fn mul_assign<'c>(&mut self, s2: &SliceWithSign<'c>, work_buf: &mut [Word]) {
99        work_buf.fill(0);
100        for (i, d1mi) in self.deref().iter().enumerate() {
101            let d1mi = *d1mi as DoubleWord;
102            if d1mi == 0 {
103                continue;
104            }
105
106            let mut k = 0;
107            for (m2j, m3ij) in s2.deref().iter().zip(work_buf[i..].iter_mut()) {
108                let m = d1mi * (*m2j as DoubleWord) + *m3ij as DoubleWord + k;
109
110                *m3ij = m as Word;
111                k = m >> (crate::WORD_BIT_SIZE);
112            }
113            work_buf[i + s2.len()] += k as Word;
114        }
115        self.deref_mut().copy_from_slice(work_buf);
116        self.sign *= s2.sign;
117    }
118
119    #[inline]
120    pub fn shift_left(&mut self, shift: usize) {
121        shift_slice_left(self, shift);
122    }
123
124    #[inline]
125    pub fn shift_right(&mut self, shift: usize) {
126        shift_slice_right(self, shift);
127    }
128
129    pub fn div_by_word(&mut self, d: Word) {
130        debug_assert!(d != 0);
131
132        let d = d as DoubleWord;
133        let mut rh = 0;
134        let m = self.deref_mut();
135        let mut iter = m.iter_mut().rev();
136        let mut val;
137
138        if let Some(v) = iter.next() {
139            val = v;
140        } else {
141            return;
142        }
143
144        if (*val as DoubleWord) < d {
145            rh = *val as DoubleWord;
146            *val = 0;
147            if let Some(v) = iter.next() {
148                val = v;
149            } else {
150                return;
151            }
152        }
153
154        loop {
155            let qh = rh * WORD_BASE as DoubleWord + *val as DoubleWord;
156
157            rh = qh % d;
158
159            *val = (qh / d) as Word;
160
161            if let Some(v) = iter.next() {
162                val = v;
163            } else {
164                break;
165            }
166        }
167    }
168
169    pub fn copy_from(&mut self, s2: &SliceWithSign<'_>) {
170        match &mut self.m {
171            SliceWithSignType::Mut(m) => {
172                match &s2.m {
173                    SliceWithSignType::Mut(s) => m[..s.len()].copy_from_slice(s),
174                    SliceWithSignType::Immut(s) => m[..s.len()].copy_from_slice(s),
175                };
176            }
177            _ => panic!(),
178        }
179    }
180
181    fn abs_add(s1: &[Word], s2: &[Word], dst: &mut [Word]) {
182        let mut c = 0;
183
184        let (iter1, mut iter2) = if s1.len() < s2.len() {
185            (s1.iter(), s2.iter())
186        } else {
187            (s2.iter(), s1.iter())
188        };
189
190        let mut iter3 = dst.iter_mut();
191
192        for (a, b, x) in izip!(iter1, iter2.by_ref(), iter3.by_ref()) {
193            c = add_carry(*a, *b, c, x);
194        }
195
196        for (b, x) in iter2.zip(iter3.by_ref()) {
197            c = add_carry(0, *b, c, x);
198        }
199
200        if c > 0 {
201            *iter3.next().unwrap() = c as Word; // dst is supposed to be longer than s1 and s2 to process carry successfully.
202        }
203
204        for v in iter3 {
205            *v = 0;
206        }
207    }
208
209    fn abs_add_assign(s1: &mut [Word], s2: &[Word]) {
210        let mut c = 0;
211        let mut iter1 = s1.iter_mut();
212        let iter2 = s2.iter();
213
214        for (b, a) in izip!(iter2, iter1.by_ref()) {
215            c = add_carry(*a, *b, c, a);
216        }
217
218        for a in iter1 {
219            c = add_carry(*a, 0, c, a);
220        }
221    }
222
223    // prereq: val of s1 >= val of s2
224    fn abs_sub_assign_1(s1: &mut [Word], s2: &[Word]) {
225        let mut c = 0;
226        let mut iter1 = s1.iter_mut();
227        let iter2 = s2.iter();
228
229        for (b, a) in izip!(iter2, iter1.by_ref()) {
230            c = sub_borrow(*a, *b, c, a);
231        }
232
233        for a in iter1 {
234            c = sub_borrow(*a, 0, c, a);
235        }
236
237        debug_assert!(c == 0);
238    }
239
240    // prereq: val of s2 > val of s1
241    fn abs_sub_assign_2(s1: &mut [Word], s2: &[Word]) {
242        let mut c = 0;
243
244        for (a, b) in s2.iter().zip(s1.iter_mut()) {
245            c = sub_borrow(*a, *b, c, b);
246        }
247
248        debug_assert!(c == 0);
249    }
250
251    fn abs_sub(s1: &[Word], s2: &[Word], dst: &mut [Word]) {
252        let mut c = 0;
253
254        let mut iter1 = s1.iter();
255        let iter2 = s2.iter();
256        let mut iter3 = dst.iter_mut();
257
258        for (b, a, d) in izip!(iter2, iter1.by_ref(), iter3.by_ref()) {
259            c = sub_borrow(*a, *b, c, d);
260        }
261
262        if c > 0 {
263            for (a, d) in iter1.zip(iter3.by_ref()) {
264                c = sub_borrow(*a, 0, c, d);
265            }
266        } else {
267            for (a, d) in iter1.zip(iter3.by_ref()) {
268                *d = *a;
269            }
270        }
271
272        for v in iter3 {
273            *v = 0;
274        }
275    }
276
277    // decrement absolute value by 1
278    pub fn decrement_abs(&mut self) {
279        for v in self.iter_mut() {
280            if *v == 0 {
281                *v = WORD_MAX;
282            } else {
283                *v -= 1;
284                return;
285            }
286        }
287        panic!("numeric overflow");
288    }
289
290    pub fn is_zero(&self) -> bool {
291        for v in self.iter() {
292            if *v != 0 {
293                return false;
294            }
295        }
296        true
297    }
298
299    fn abs_cmp(s1: &[Word], s2: &[Word]) -> SignedWord {
300        let len = s1.len().min(s2.len());
301
302        for v in &s1[len..] {
303            if *v != 0 {
304                return 1;
305            }
306        }
307
308        for v in &s2[len..] {
309            if *v != 0 {
310                return -1;
311            }
312        }
313
314        for (a, b) in core::iter::zip(s1[..len].iter().rev(), s2[..len].iter().rev()) {
315            let diff = *a as SignedWord - *b as SignedWord;
316            if diff != 0 {
317                return diff;
318            }
319        }
320
321        0
322    }
323
324    #[inline]
325    pub fn set_sign(&mut self, sign: i8) {
326        self.sign = sign;
327    }
328
329    #[inline]
330    pub fn sign(&self) -> i8 {
331        self.sign
332    }
333
334    pub fn cmp(&self, d2: &Self) -> SignedWord {
335        if self.is_zero() && d2.is_zero() {
336            return 0;
337        }
338
339        if self.sign != d2.sign {
340            return self.sign as SignedWord;
341        }
342
343        Self::abs_cmp(self, d2) * self.sign as SignedWord
344    }
345}
346
347impl<'a> Deref for SliceWithSign<'a> {
348    type Target = [Word];
349
350    #[inline]
351    fn deref(&self) -> &[Word] {
352        match &self.m {
353            SliceWithSignType::Mut(m) => m,
354            SliceWithSignType::Immut(m) => m,
355        }
356    }
357}
358
359impl<'a> DerefMut for SliceWithSign<'a> {
360    #[inline]
361    fn deref_mut(&mut self) -> &mut [Word] {
362        match &mut self.m {
363            SliceWithSignType::Mut(m) => m,
364            _ => panic!(),
365        }
366    }
367}