Skip to main content

baseless/
lib.rs

1#![allow(dead_code)]
2
3pub mod util;
4pub mod iter;
5
6use std::collections::VecDeque;
7use std::convert::TryFrom;
8use std::ops::{Shl, Shr};
9use util::*;
10use iter::BorrowedNumberIter;
11
12pub type Digit = u8;
13pub type Pair = (Digit, Digit);
14pub type Bucket = usize;
15
16#[derive(Debug)]
17pub struct Base {
18    base: u32,
19    addition_table: Vec<Pair>,
20    multiplication_table: Vec<Pair>,
21    digit_width: usize,
22    digits_per_bucket: usize,
23    digit_bitmask: usize,
24}
25impl Base {
26    pub fn new(base: u32) -> Self {
27        let mut addition_table = Vec::new(); // TODO capacity
28        let mut multiplication_table = Vec::new();
29        for (add, mul) in ArithmeticPrecomputation::new(base) {
30            addition_table.push(add);
31            multiplication_table.push(mul);
32        }
33        let (digit_width, digits_per_bucket, digit_bitmask) = bitwise_parameters(base);
34        Self {
35            base,
36            addition_table,
37            multiplication_table,
38            digit_width,
39            digits_per_bucket,
40            digit_bitmask
41        }
42    }
43
44    /// Given two digits, returns the digits of their sum in the form of (first_digit,
45    /// carry_digit).
46    pub fn add_digits(&self, a: Digit, b: Digit) -> Pair {
47        *self.addition_table.get(pair_index((a, b), self.base)).unwrap()
48    }
49    /// Given two digits, returns the digits of their product in the form of (first_digit,
50    /// carry_digit).
51    pub fn multiply_digits(&self, a: Digit, b: Digit) -> Pair {
52        *self.multiplication_table.get(pair_index((a, b), self.base)).unwrap()
53    }
54
55    pub fn digits_per_bucket(&self) -> usize {
56        self.digits_per_bucket
57    }
58    pub fn digit_width(&self) -> usize {
59        self.digit_width
60    }
61    pub fn digit_bitmask(&self) -> usize {
62        self.digit_bitmask
63    }
64
65    /// Returns the index of a bucket within a vector of buckets, given the index
66    /// of a digit
67    pub fn bucket_index(&self, idx: usize) -> usize {
68        idx / self.digits_per_bucket
69    }
70    /// Returns the index of a digit within it's respective bucket, given the index
71    /// of a digit
72    pub fn digit_index(&self, idx: usize) -> usize {
73        idx % self.digits_per_bucket
74    }
75    /// Given the index of a particular digit, returns the index of it's bucket
76    /// within the vector of buckets, and it's index within that bucket.
77    pub fn indexes(&self, idx: usize) -> (usize, usize) {
78        (self.bucket_index(idx), self.digit_index(idx))
79    }
80}
81
82#[derive(Debug)]
83pub struct Number<'base> {
84    buckets: VecDeque<Bucket>,
85    digits: usize,
86    power: isize,
87    sign: Sign,
88    base: &'base Base
89}
90impl<'base> Number<'base> {
91    pub fn new(base: &'base Base) -> Self {
92        Self {
93            buckets: VecDeque::new(),
94            digits: 0,
95            power: 0,
96            sign: Sign::Positive,
97            base
98        }
99    }
100    pub fn with_capacity(base: &'base Base, digits: usize) -> Self {
101        let mut buckets = digits / base.digits_per_bucket();
102        if digits % base.digits_per_bucket() != 0 {
103            buckets += 1;
104        }
105        Self {
106            buckets: VecDeque::with_capacity(buckets),
107            digits: 0,
108            power: 0,
109            sign: Sign::Positive,
110            base
111        }
112    }
113
114    pub fn digits(&self) -> usize {
115        self.digits
116    }
117    pub fn power(&self) -> isize {
118        self.power
119    }
120    pub fn sign(&self) -> Sign {
121        self.sign
122    }
123    pub fn positive(&self) -> bool {
124        self.sign == Sign::Positive
125    }
126    pub fn negative(&self) -> bool {
127        self.sign == Sign::Negative
128    }
129
130    /// Vector API
131
132    pub fn get(&self, idx: usize) -> Option<Digit> {
133        if idx > self.digits || self.digits == 0 {
134            return None;
135        }
136        let (bucket_idx, digit_idx) = self.base.indexes(idx);
137        Some(self.get_digit(bucket_idx, digit_idx))
138    }
139    pub fn set(&mut self, idx: usize, digit: Digit) {
140        if idx > self.digits {
141            panic!("Attempted to set inaccessible digit.");
142            // TODO make consistent with vec panic msg
143        }
144        if idx == self.digits {
145            self.push_high(digit);
146            return;
147        }
148        let (bucket_idx, digit_idx) = self.base.indexes(idx);
149        self.set_digit(bucket_idx, digit_idx, digit);
150    }
151    /// Adds a new digit to the highest-order position
152    pub fn push_high(&mut self, digit: Digit) {
153        let (bucket_idx, digit_idx) = self.base.indexes(self.digits);
154        if digit_idx == 0 { // New bucket
155            self.buckets.push_back(digit as Bucket)
156        } else {
157            self.set_digit(bucket_idx, digit_idx, digit)
158        }
159        self.digits += 1;
160    }
161    /// Removes the digit from the highest order position, and returns it (if it
162    /// exists)
163    pub fn pop_high(&mut self) -> Option<Digit> {
164        if self.digits == 0 {
165            return None;
166        }
167        let (bucket_idx, digit_idx) = self.base.indexes(self.digits - 1);
168        let digit = self.get_digit(bucket_idx, digit_idx);
169        self.digits -= 1;
170        if digit_idx == 0 {
171            self.buckets.pop_back();
172        }
173        Some(digit)
174    }
175    /// Adds a new digit to the lowest-order position
176    pub fn push_low(&mut self, digit: Digit) {
177        let (bucket_idx, digit_idx) = (0, 0);
178        // push_low always pushes to (0, 0) - no need to call indexes() 
179        if self.digits == 0 || self.base.digit_index(self.digits - 1) == self.base.digits_per_bucket - 1 { // New bucket
180            self.buckets.push_back(0)
181        }
182        self.shift_digits_high(1);
183        self.set_digit(bucket_idx, digit_idx, digit);
184        self.digits += 1;
185    }
186    /// Removes the digit from the lowest order position, and returns it (if it
187    /// exists)
188    pub fn pop_low(&mut self) -> Option<Digit> {
189        if self.digits == 0 {
190            return None;
191        }
192        let (bucket_idx, digit_idx) = (0, 0);
193        let digit = self.get_digit(bucket_idx, digit_idx);
194        self.shift_digits_low(1);
195        self.digits -= 1;
196        Some(digit)
197    }
198//     fn pad_high(&mut self, zeroes: usize) {
199//     }
200//     fn pad_low(&mut self, zeroes: usize) {
201//     }
202
203    /// Bucket Management
204
205    fn set_digit(&mut self, bucket_idx: usize, digit_idx: usize, digit: Digit) {
206        let bucket = self.buckets.get_mut(bucket_idx).expect("Attempted to set digit in uninitialzed bucket");
207        let shift = self.base.digit_width() * digit_idx;
208        *bucket = (*bucket & !(self.base.digit_bitmask() << shift)) | ((digit as usize) << shift);
209    }
210    fn get_digit(&self, bucket_idx: usize, digit_idx: usize) -> Digit {
211        let bucket = self.buckets.get(bucket_idx).expect("Attempted to fetch digit from uninitialzed bucket.");
212        let shift = self.base.digit_width() * digit_idx;
213        ((bucket & (self.base.digit_bitmask() << shift)) >> shift) as Digit
214    }
215    /// Assumes caller has allocated space as necessary.
216    fn shift_digits_high(&mut self, shift: usize) {
217        // TODO use bit shifts rather than set_digit to do an entire bucket at once
218        if self.digits == 0 {
219            return;
220        }
221        for _ in 0..shift {
222            for idx in (0..self.digits).into_iter().rev() {
223                let (current_bucket_idx, current_digit_idx) = self.base.indexes(idx);
224                let digit = self.get_digit(current_bucket_idx, current_digit_idx);
225                let (new_bucket_idx, new_digit_idx) = self.base.indexes(idx + 1);
226                self.set_digit(new_bucket_idx, new_digit_idx, digit);
227
228            }
229        }
230    }
231    /// Assumes caller has allocated space as necessary.
232    /// First digit is is overwritten
233    fn shift_digits_low(&mut self, shift: usize) {
234        // TODO use bit shifts rather than set_digit to do an entire bucket at once
235        if self.digits == 0 {
236            return;
237        }
238        for _ in 0..shift {
239            for idx in 1..self.digits {
240                let (current_bucket_idx, current_digit_idx) = self.base.indexes(idx);
241                let digit = self.get_digit(current_bucket_idx, current_digit_idx);
242                let (new_bucket_idx, new_digit_idx) = self.base.indexes(idx - 1);
243                self.set_digit(new_bucket_idx, new_digit_idx, digit);
244            }
245        }
246    }
247    fn add_buckets_high(&mut self, buckets: usize) {
248        self.buckets.reserve(buckets);
249        for _bucket in 0..buckets {
250            self.buckets.push_front(0);
251        }
252    }
253    fn add_buckets_low(&mut self, buckets: usize) {
254        self.buckets.reserve(buckets);
255        for _bucket in 0..buckets {
256            self.buckets.push_back(0);
257        }
258    }
259    fn pad_digits_high(&mut self, digits: usize) {
260        for _ in 0..digits {
261            self.push_high(0);
262        }
263        // TODO optimize
264    }
265    fn pad_digits_low(&mut self, digits: usize) {
266        for _ in 0..digits {
267            self.push_low(0);
268            // TODO optimize
269        }
270        self.power -= isize::try_from(digits).expect("Overflowed isize while adding low-order digits.");
271    }
272
273    /// Arithmetic
274
275    /// Returns the index of the digit representing a certain power, if it exists.
276    /// Otherwise returns an error containing the number of digits required, to which side, and
277    /// what the index will be after they are added.
278    fn power_idx(&self, power: isize) -> Result<usize, PowerIndexError> {
279        if self.digits == 0 {
280            if power == 0 {
281                return Err(PowerIndexError::InsufficientDigitsHigh(1));
282            } else if power > 0 {
283                return Err(PowerIndexError::InsufficientDigitsHigh(power as usize));
284            } else {
285                return Err(PowerIndexError::InsufficientDigitsLow(-power as usize));
286            }
287        }
288
289        let highest_digit = self.power + isize::try_from(self.digits - 1).expect("Couldn't convert digit count to isize");
290        // We can safely subtract 1 from self.digits because we've already determined it is not 0
291        // Below our arithmetic is always nonnegative, and so the casting to usize is safe
292        if power > highest_digit {
293            return Err(PowerIndexError::InsufficientDigitsHigh((power - highest_digit) as usize));
294        } else if power < self.power {
295            return Err(PowerIndexError::InsufficientDigitsLow((self.power - power) as usize));
296        }
297
298        Ok((power - self.power) as usize)
299    }
300
301    // TODO better name
302    fn arithmetic_setup(&mut self, power: isize) -> usize {
303        match self.power_idx(power) {
304            Ok(idx) => idx,
305            Err(PowerIndexError::InsufficientDigitsLow(digits_needed)) => {
306                self.pad_digits_low(digits_needed);
307                0 // If we need low order, then our index will always be 0
308                  // (eg the first digit)
309            },
310            Err(PowerIndexError::InsufficientDigitsHigh(digits_needed)) => {
311                let idx = (self.digits - 1) + digits_needed;
312                // If we need high order digits, then our index will always be
313                // the number of added digits past the highest digit
314                // -1 for zero indexing
315                self.pad_digits_high(digits_needed);
316                idx
317            }
318        }
319    }
320
321    pub fn add_digit(&mut self, digit: Digit, power: isize) {
322        // TODO add asserts
323        let mut idx = self.arithmetic_setup(power);
324        let (bucket_idx, digit_idx) = self.base.indexes(idx);
325        let (new_digit, mut carry) = self.base.add_digits(digit, self.get_digit(bucket_idx, digit_idx));
326        self.set_digit(bucket_idx, digit_idx, new_digit);
327        idx += 1;
328
329        while idx < self.digits && carry != 0 {
330            let (bucket_idx, digit_idx) = self.base.indexes(idx);
331            // TODO when destucturing is supported in assignment, change this :(
332            let (new_digit, new_carry) = self.base.add_digits(carry, self.get_digit(bucket_idx, digit_idx));
333            carry = new_carry;
334            self.set_digit(bucket_idx, digit_idx, new_digit);
335            idx += 1;
336        }
337        if carry != 0 {
338            self.push_high(carry);
339        }
340    }
341//     pub fn sub_digit(&mut self, digit: Digit, power: usize) {
342// 
343//     }
344
345    pub fn negate(&mut self) {
346        self.sign = match self.sign {
347            Sign::Positive => Sign::Negative,
348            Sign::Negative => Sign::Positive
349        }
350    }
351
352    pub fn iter(&self) -> BorrowedNumberIter {
353        BorrowedNumberIter::new(self)
354    }
355}
356
357impl Shl<usize> for Number<'_> {
358    type Output = Self;
359
360    fn shl(mut self, rhs: usize) -> Self::Output {
361        self.power += isize::try_from(rhs).expect("Failed to convert into isize during left shift.");
362        self
363    }
364}
365
366impl Shr<usize> for Number<'_> {
367    type Output = Self;
368
369    fn shr(mut self, rhs: usize) -> Self::Output {
370        self.power -= isize::try_from(rhs).expect("Failed to convert into isize during right shift.");
371        self
372    }
373}
374
375#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
376pub enum Sign {
377    Positive,
378    Negative
379}
380
381enum PowerIndexError {
382    InsufficientDigitsHigh(usize),
383    InsufficientDigitsLow(usize)
384}
385
386fn bitwise_parameters(base: u32) -> (usize, usize, usize) {
387    let base = base as usize;
388    let highest_digit = base - 1;
389    // TODO move to usize::BITS when the feature lands in stable
390    let usize_bits = 0usize.leading_zeros();
391
392    let digits_width = usize_bits - highest_digit.leading_zeros();
393    let digits_per_bucket = usize_bits / digits_width;
394    let mask = !(usize::MAX << digits_width as usize);
395
396    (digits_width as usize, digits_per_bucket as usize, mask)
397}
398
399#[cfg(test)]
400pub mod test {
401    use super::*;
402
403    /// Number Vector API
404
405    #[test]
406    fn push_high_puts_digit_on_left() {
407        let b = Base::new(10);
408        let mut n = Number::new(&b);
409        n.push_high(5);
410        n.push_high(1);
411        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1, 5));
412    }
413
414    #[test]
415    fn push_low_puts_digit_on_right() {
416        let b = Base::new(10);
417        let mut n = Number::new(&b);
418        n.push_low(1);
419        n.push_low(5);
420        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1, 5));
421    }
422
423    #[test]
424    fn pop_high_takes_digits_from_right() {
425        let b = Base::new(10);
426        let mut n = Number::new(&b);
427        n.push_high(5);
428        n.push_high(1);
429        assert_eq!(n.pop_high(), Some(1));
430        assert_eq!(n.pop_high(), Some(5));
431        assert_eq!(n.pop_high(), None);
432    }
433
434    #[test]
435    fn pop_low_takes_digits_from_left() {
436        let b = Base::new(10);
437        let mut n = Number::new(&b);
438        n.push_low(1);
439        n.push_low(5);
440        assert_eq!(n.pop_low(), Some(5));
441        assert_eq!(n.pop_low(), Some(1));
442        assert_eq!(n.pop_low(), None);
443    }
444
445    #[test]
446    fn push_high_and_pop_high_are_inverse() {
447        let b = Base::new(10);
448        let mut n = Number::new(&b);
449        n.push_high(5);
450        n.push_high(1);
451        assert_eq!(n.pop_high(), Some(1));
452        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(5));
453    }
454
455    #[test]
456    fn push_low_and_pop_low_are_inverse() {
457        let b = Base::new(10);
458        let mut n = Number::new(&b);
459        n.push_low(5);
460        n.push_low(1);
461        assert_eq!(n.pop_low(), Some(1));
462        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(5));
463    }
464
465    #[test]
466    fn pushing_increases_digits() {
467        let b = Base::new(10);
468        let mut n = Number::new(&b);
469        n.push_high(5);
470        assert_eq!(n.digits, 1);
471        n.push_low(1);
472        assert_eq!(n.digits, 2);
473    }
474
475    #[test]
476    fn popping_reduces_digits() {
477        let b = Base::new(10);
478        let mut n = Number::new(&b);
479        n.push_high(5);
480        n.push_low(1);
481        n.pop_high();
482        assert_eq!(n.digits, 1);
483        n.pop_low();
484        assert_eq!(n.digits, 0);
485    }
486
487    #[test]
488    fn alternating_pushing_high_and_low() {
489        let b = Base::new(10);
490        let mut n = Number::new(&b);
491        n.push_high(1);
492        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1));
493        n.push_low(2);
494        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1, 2));
495        n.push_high(3);
496        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(3, 1, 2));
497        n.push_low(4);
498        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(3, 1, 2, 4));
499    }
500
501    #[test]
502    fn alternating_popping_high_and_low() {
503        let b = Base::new(10);
504        let mut n = Number::new(&b);
505        for i in 1..=9 {
506            n.push_low(i);
507        }
508        assert_eq!(n.pop_high(), Some(1));
509        assert_eq!(n.pop_low(), Some(9));
510        assert_eq!(n.pop_high(), Some(2));
511        assert_eq!(n.pop_low(), Some(8));
512        assert_eq!(n.pop_high(), Some(3));
513        assert_eq!(n.pop_low(), Some(7));
514        assert_eq!(n.pop_high(), Some(4));
515        assert_eq!(n.pop_low(), Some(6));
516        assert_eq!(n.pop_high(), Some(5));
517
518        assert_eq!(n.pop_high(), None);
519        assert_eq!(n.pop_low(), None);
520    }
521
522    #[test]
523    fn pushing_high_past_bucket_boundary() {
524        let b = Base::new(10);
525        let mut n = Number::new(&b);
526        for _ in 0..(b.digits_per_bucket() + 1) {
527            n.push_high(1);
528        }
529        assert_eq!(
530            n.iter().collect::<Vec<_>>(),
531            (0..b.digits_per_bucket() + 1).map(|_| 1).collect::<Vec<_>>()
532        );
533    }
534
535    #[test]
536    fn pushing_low_past_bucket_boundary() {
537        let b = Base::new(10);
538        let mut n = Number::new(&b);
539        for _ in 0..(b.digits_per_bucket() + 1) {
540            n.push_low(1);
541        }
542        assert_eq!(
543            n.iter().collect::<Vec<_>>(),
544            (0..b.digits_per_bucket() + 1).map(|_| 1).collect::<Vec<_>>()
545        );
546    }
547
548    #[test]
549    fn popping_high_past_bucket_boundary() {
550        let b = Base::new(10);
551        let mut n = Number::new(&b);
552        for _ in 0..(b.digits_per_bucket() + 1) {
553            n.push_high(1);
554        }
555        for _ in 0..(b.digits_per_bucket() + 1) {
556            assert_eq!(n.pop_high(), Some(1));
557        }
558        assert_eq!(n.pop_high(), None);
559    }
560
561    #[test]
562    fn popping_low_past_bucket_boundary() {
563        let b = Base::new(10);
564        let mut n = Number::new(&b);
565        for _ in 0..(b.digits_per_bucket() + 1) {
566            n.push_high(1);
567        }
568        for _ in 0..(b.digits_per_bucket() + 1) {
569            assert_eq!(n.pop_low(), Some(1));
570        }
571        assert_eq!(n.pop_low(), None);
572    }
573
574    #[test]
575    fn get_returns_correct_digit() {
576        let b = Base::new(10);
577        let mut n = Number::new(&b);
578        for i in 1..=9 {
579            n.push_high(i);
580        }
581        for i in 0..8 {
582            assert_eq!(n.get(i), Some((i+1) as Digit));
583        }
584    }
585
586    #[test]
587    fn set_alters_correct_digit() {
588        let b = Base::new(10);
589        let mut n = Number::new(&b);
590        for i in 0..9 {
591            n.push_high(i);
592        }
593        for i in (0..9).into_iter().rev() {
594            n.set(i, (i+1) as Digit);
595        }
596        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(9, 8, 7, 6, 5, 4, 3, 2, 1));
597    }
598
599    #[test]
600    fn set_can_alter_1_digit_past_last_digit() {
601        let b = Base::new(10);
602        let mut n = Number::new(&b);
603        for i in 0..9 {
604            n.push_high(i);
605        }
606        n.set(9, 9);
607        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
608        // TODO iter weirdness
609    }
610
611    /// Arithmetic
612
613    #[test]
614    fn single_digit_addition() {
615        let b = Base::new(10);
616        let mut n = Number::new(&b);
617        n.push_high(1);
618        n.add_digit(1, 0);
619        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(2));
620    }
621
622    #[test]
623    fn single_digit_addition_with_carry() {
624        let b = Base::new(10);
625        let mut n = Number::new(&b);
626        for _ in 0..3 {
627            n.push_high(9);
628        }
629        n.add_digit(1, 0);
630        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1,0,0,0));
631    }
632
633    #[test]
634    fn single_digit_addition_with_carry_across_bucket_boundary() {
635        let b = Base::new(10);
636        let mut n = Number::new(&b);
637        for _ in 0..b.digits_per_bucket() {
638            n.push_high(9);
639        }
640        n.add_digit(1, 0);
641        let mut expected = Vec::new();
642        expected.push(1);
643        for _ in 0..b.digits_per_bucket() {
644            expected.push(0);
645        }
646        assert_eq!(n.iter().collect::<Vec<_>>(), expected);
647    }
648
649    #[test]
650    fn single_digit_addition_with_carry_that_does_not_travel_all_the_way() {
651        let b = Base::new(10);
652        let mut n = Number::new(&b);
653        n.push_high(8);
654        n.push_high(9);
655        n.push_high(9);
656        n.push_high(1);
657        n.add_digit(2, 0);
658        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(2, 0, 0, 0));
659    }
660
661    #[test]
662    fn single_digit_addition_with_new_digit_high() {
663        let b = Base::new(10);
664        let mut n = Number::new(&b);
665        n.push_high(1);
666        n.add_digit(2, 1);
667        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(2, 1));
668    }
669
670    #[test]
671    fn single_digit_addition_with_new_digit_low() {
672        let b = Base::new(10);
673        let mut n = Number::new(&b);
674        n.push_high(1);
675        n.add_digit(2, -1);
676        assert_eq!(n.iter().collect::<Vec<_>>(), vec!(1, 2));
677    }
678
679    #[test]
680    fn shift_left_increases_power() {
681        let b = Base::new(10);
682        let mut n = Number::new(&b);
683        n = n << 1;
684        assert_eq!(n.power(), 1);
685    }
686
687    #[test]
688    fn shift_right_decreases_power() {
689        let b = Base::new(10);
690        let mut n = Number::new(&b);
691        n = n >> 1;
692        assert_eq!(n.power(), -1);
693    }
694}