bigint_base10/
lib.rs

1//! This crate contains the [`BigInteger`] type.
2//!
3//! The API is currently experimental and is subject to change.
4//!
5//! # Example
6//!
7//! There are currently two ways of creating a [`BigInteger`].
8//!
9//! Using a string literal.
10//!
11//! ```
12//! // This is only necessary for 2015.
13//! extern crate bigint_base10;
14//!
15//! use bigint_base10::BigInteger;
16//!
17//! let my_int = BigInteger::new("123");
18//!
19//! assert_eq!(format!("{}", my_int), "+123");
20//! ```
21//!
22//! Using a vector of `u8` values.
23//!
24//! ```
25//! # use bigint_base10::BigInteger;
26//! use bigint_base10::Sign;
27//!
28//! let digits = [1, 2, 3];
29//! let my_int = BigInteger::from_digits(&digits, Sign::Positive);
30//!
31//! assert_eq!(format!("{}", my_int), "+123");
32//! ```
33//!
34//! [`BigInteger`]: struct.BigInteger.html
35
36use std::char;
37use std::cmp::Ordering;
38use std::fmt;
39use std::iter;
40use std::iter::{DoubleEndedIterator, Iterator};
41use std::ops::{Add, Deref, Index, Mul, Neg, Shl, Sub};
42
43mod ops;
44
45/// Sign indicating postivity of a value.
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
47pub enum Sign {
48    Positive,
49    Negative,
50    NoSign,
51}
52
53impl Sign {
54    /// Return `true` if the enum value is positive, `false` otherwise.
55    pub fn is_positive(self) -> bool {
56        match self {
57            Sign::Positive => true,
58            _ => false,
59        }
60    }
61
62    /// Return `true` if the enum value is negative, `false` otherwise.
63    pub fn is_negative(self) -> bool {
64        match self {
65            Sign::Negative => true,
66            _ => false,
67        }
68    }
69
70    /// Return `true` if the enum value has no sign (equivalent to zero), `false` otherwise.
71    pub fn is_nosign(self) -> bool {
72        match self {
73            Sign::NoSign => true,
74            _ => false,
75        }
76    }
77}
78
79impl fmt::Display for Sign {
80    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
81        match *self {
82            Sign::Positive => write!(formatter, "+"),
83            Sign::Negative => write!(formatter, "-"),
84            Sign::NoSign => Ok(()),
85        }
86    }
87}
88
89// FIXME: Implement Eq.
90// FIXME: Implement Ord.
91// FIXME: Implement Shr.
92// TODO: Implement conversion to/from POD integer.
93// TODO: Optimize operations to write to u8 buffer in-place (mut self).
94/// A type for arbitrarily-long representations of integer values.
95///
96/// This is helpful for representing integer values that are expected
97/// to exceed the largest representation possible with "plain-old-data"
98/// types, i.e. `u64` / `i64`.
99///
100/// Usage is demonstrated in crate documentation.
101#[derive(Clone, Debug, PartialEq)]
102pub struct BigInteger {
103    digits: Vec<u8>,
104    sign: Sign,
105}
106
107impl BigInteger {
108    /// Create a `BigInteger` from string representation.
109    ///
110    /// # Example
111    ///
112    /// Requires a minimum of one digit to initialize a `BigInteger`.
113    /// The value is assumed to be positive by default.
114    ///
115    /// ```
116    /// # use bigint_base10::BigInteger;
117    /// let my_int = BigInteger::new("1");
118    ///
119    /// assert_eq!(format!("{}", my_int), "+1");
120    /// ```
121    ///
122    /// A sign can be specified.
123    ///
124    /// ```
125    /// # use bigint_base10::BigInteger;
126    /// let my_int = BigInteger::new("-1");
127    ///
128    /// assert_eq!(format!("{}", my_int), "-1");
129    /// ```
130    ///
131    /// Zero has no sign. Any provided signs are discarded.
132    ///
133    /// ```
134    /// # use bigint_base10::BigInteger;
135    /// let my_int = BigInteger::new("-0");
136    ///
137    /// assert_eq!(format!("{}", my_int), "0");
138    /// ```
139    ///
140    /// # Panics
141    ///
142    /// - If the literal is empty.
143    /// - If invalid numeric characters are passed in the literal.
144    pub fn new(literal: &str) -> BigInteger {
145        // FIXME: to_digit() also converts A-Z, a-z characters.
146        let char_to_digit = |character: char| {
147            character
148                .to_digit(10)
149                .expect("BigInteger literal must use numeric characters") as u8
150        };
151
152        let mut digits: Vec<u8> = Vec::new();
153        let mut chars = literal.chars();
154
155        // Process the first character. This may be a sign or a digit.
156        let sign = match chars.next() {
157            Some(character) if character == '+' => Sign::Positive,
158            Some(character) if character == '-' => Sign::Negative,
159            Some(character) => {
160                digits.push(char_to_digit(character));
161
162                // We assume the value is positive by default.
163                Sign::Positive
164            }
165            None => panic!("BigInteger literal must begin with a sign or a digit"),
166        };
167
168        // Process the rest of the characters as digits.
169        digits.extend(chars.map(char_to_digit));
170
171        BigInteger::from_digits(&digits[..], sign)
172    }
173
174    /// Create a `BigInteger` from a slice of `u8` digits.
175    pub fn from_digits(digits: &[u8], sign: Sign) -> BigInteger {
176        let digits = Vec::from(digits);
177
178        let mut result = BigInteger { digits, sign };
179
180        result.trim();
181        result
182    }
183
184    /// Return `true` if the integer value is positive, `false` otherwise.
185    pub fn is_positive(&self) -> bool {
186        self.sign.is_positive()
187    }
188
189    /// Return `true` if the integer value is negative, `false` otherwise.
190    pub fn is_negative(&self) -> bool {
191        self.sign.is_negative()
192    }
193
194    /// Count the number of digits in the integer.
195    pub fn count(&self) -> usize {
196        self.digits.len()
197    }
198
199    /// View the integer as a slice of the contained digits.
200    pub fn as_slice(&self) -> &[u8] {
201        self
202    }
203
204    /// Return an iterator of digits from smallest unit to the largest
205    /// (right-to-left).
206    ///
207    /// # Example
208    ///
209    /// Usage.
210    ///
211    /// ```
212    /// # use bigint_base10::BigInteger;
213    /// let my_int = BigInteger::new("123");
214    ///
215    /// let mut iter = my_int.digits();
216    ///
217    /// assert_eq!(iter.next(), Some(3));
218    /// assert_eq!(iter.next(), Some(2));
219    /// assert_eq!(iter.next(), Some(1));
220    /// assert_eq!(iter.next(), None);
221    /// ```
222    pub fn digits(&self) -> impl Iterator<Item = u8> + DoubleEndedIterator + '_ {
223        // TODO: Check rev() performance. Since the elements should be
224        // contiguous, I imagine this should be reasonably fast.
225        self.digits.iter().cloned().rev()
226    }
227
228    /// Filter extraneous digits from digits buffer in integer.
229    fn trim(&mut self) {
230        // Prune zeroes at the beginning of the digits.
231        // TODO: Is there a way to perform this in-place?
232        self.digits = self
233            .digits
234            .iter()
235            .cloned()
236            .skip_while(|&digit| digit == 0)
237            .collect();
238
239        // If no digits remain, we assume the integer represents zero.
240        if self.digits.is_empty() {
241            self.digits.push(0);
242            self.sign = Sign::NoSign;
243        }
244    }
245}
246
247impl fmt::Display for BigInteger {
248    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
249        let mut display_value = String::new();
250
251        display_value.extend(self.digits.iter().map(|digit| {
252            char::from_digit(u32::from(*digit), 10)
253                .expect("Error occured whilst encoding BigInteger digit")
254        }));
255
256        write!(formatter, "{}{}", self.sign, display_value)
257    }
258}
259
260impl Deref for BigInteger {
261    type Target = Vec<u8>;
262
263    fn deref(&self) -> &Vec<u8> {
264        &self.digits
265    }
266}
267
268impl Index<usize> for BigInteger {
269    type Output = u8;
270
271    fn index(&self, index: usize) -> &u8 {
272        &self.digits[index]
273    }
274}
275
276impl PartialOrd for BigInteger {
277    fn partial_cmp(&self, other: &BigInteger) -> Option<Ordering> {
278        // FIXME: Handle zero.
279
280        match (self.is_positive(), other.is_positive()) {
281            (true, true) => Some(ops::cmp(self, other)),
282            (false, true) => Some(Ordering::Less),
283            (true, false) => Some(Ordering::Greater),
284            (false, false) => {
285                // The result is reversed if both integers are negative.
286                match ops::cmp(self, other) {
287                    Ordering::Less => Some(Ordering::Greater),
288                    Ordering::Equal => Some(Ordering::Equal),
289                    Ordering::Greater => Some(Ordering::Less),
290                }
291            }
292        }
293    }
294}
295
296impl Neg for BigInteger {
297    type Output = BigInteger;
298
299    fn neg(mut self) -> BigInteger {
300        self.sign = match self.sign {
301            Sign::Positive => Sign::Negative,
302            Sign::NoSign => Sign::NoSign,
303            Sign::Negative => Sign::Negative,
304        };
305        self
306    }
307}
308
309impl Shl<usize> for BigInteger {
310    type Output = Self;
311
312    fn shl(mut self, count: usize) -> BigInteger {
313        self.digits.extend(iter::repeat(0u8).take(count));
314        self
315    }
316}
317
318impl<'a> Add<&'a BigInteger> for BigInteger {
319    type Output = Self;
320
321    fn add(self, other: &BigInteger) -> BigInteger {
322        match (self.sign, other.sign) {
323            (Sign::NoSign, Sign::NoSign) => self,
324            (Sign::NoSign, _) => other.clone(),
325            (_, Sign::NoSign) => self,
326            (Sign::Positive, Sign::Positive) => ops::add(&self, other),
327            (Sign::Negative, Sign::Positive) => ops::sub(other, &self),
328            (Sign::Positive, Sign::Negative) => ops::sub(&self, other),
329            (Sign::Negative, Sign::Negative) => -ops::add(&self, other),
330        }
331    }
332}
333
334impl<'a> Sub<&'a BigInteger> for BigInteger {
335    type Output = Self;
336
337    fn sub(self, other: &BigInteger) -> BigInteger {
338        match (self.sign, other.sign) {
339            (Sign::NoSign, Sign::NoSign) => self,
340            (Sign::NoSign, _) => other.clone(),
341            (_, Sign::NoSign) => self,
342            (Sign::Positive, Sign::Positive) => ops::sub(&self, other),
343            (Sign::Negative, Sign::Positive) => -ops::add(&self, other),
344            (Sign::Positive, Sign::Negative) => ops::add(&self, other),
345            (Sign::Negative, Sign::Negative) => ops::sub(other, &self),
346        }
347    }
348}
349
350impl<'a> Mul<&'a BigInteger> for BigInteger {
351    type Output = Self;
352
353    #[allow(clippy::suspicious_arithmetic_impl)]
354    fn mul(self, other: &BigInteger) -> BigInteger {
355        if self.sign.is_nosign() || other.sign.is_nosign() {
356            return BigInteger::from_digits(&[0], Sign::NoSign);
357        }
358
359        let positive = self.is_positive() == other.is_positive();
360
361        let mut result = ops::mul(&self, other);
362
363        result.sign = if positive {
364            Sign::Positive
365        } else {
366            Sign::Negative
367        };
368        result
369    }
370}
371
372#[cfg(test)]
373mod tests {
374    use super::BigInteger;
375
376    ///////////////////////////////////////////////////////////////////////////
377
378    #[test]
379    fn new_from_literal() {
380        assert_eq!(BigInteger::new("123456789").to_string(), "+123456789");
381    }
382
383    #[test]
384    fn new_from_positive_literal() {
385        assert_eq!(BigInteger::new("+123456789").to_string(), "+123456789");
386    }
387
388    #[test]
389    fn new_from_negative_literal() {
390        assert_eq!(BigInteger::new("-123456789").to_string(), "-123456789");
391    }
392
393    #[test]
394    fn new_with_extraneous_zeroes() {
395        assert_eq!(BigInteger::new("000001").to_string(), "+1");
396    }
397
398    ///////////////////////////////////////////////////////////////////////////
399
400    #[test]
401    fn add_single_digits() {
402        let result = BigInteger::new("2") + &BigInteger::new("2");
403
404        assert_eq!(result, BigInteger::new("4"));
405    }
406
407    #[test]
408    fn add_zero() {
409        let result = BigInteger::new("2") + &BigInteger::new("0");
410
411        assert_eq!(result, BigInteger::new("2"));
412    }
413
414    #[test]
415    fn add_with_carry() {
416        let result = BigInteger::new("6") + &BigInteger::new("6");
417
418        assert_eq!(result, BigInteger::new("12"));
419    }
420
421    #[test]
422    fn add_multiple_digits() {
423        let result = BigInteger::new("123") + &BigInteger::new("456");
424
425        assert_eq!(result, BigInteger::new("579"));
426    }
427
428    #[test]
429    fn add_large() {
430        let result = BigInteger::new("999999999999") + &BigInteger::new("999999999999");
431
432        assert_eq!(result, BigInteger::new("1999999999998"));
433    }
434
435    #[test]
436    fn add_negative() {
437        let result = BigInteger::new("456") + &BigInteger::new("-123");
438
439        assert_eq!(result, BigInteger::new("333"));
440    }
441
442    ///////////////////////////////////////////////////////////////////////////
443
444    #[test]
445    fn subtract_single_digits() {
446        let result = BigInteger::new("4") - &BigInteger::new("2");
447
448        assert_eq!(result, BigInteger::new("2"));
449    }
450
451    #[test]
452    fn subtract_zero() {
453        let result = BigInteger::new("2") - &BigInteger::new("0");
454
455        assert_eq!(result, BigInteger::new("2"));
456    }
457
458    #[test]
459    fn subtract_multiple_digits() {
460        let result = BigInteger::new("456") - &BigInteger::new("123");
461
462        assert_eq!(result, BigInteger::new("333"));
463    }
464
465    #[test]
466    fn subtract_negative() {
467        let result = BigInteger::new("123") - &BigInteger::new("-456");
468
469        assert_eq!(result, BigInteger::new("579"));
470    }
471
472    #[test]
473    fn subtract_below_zero() {
474        let result = BigInteger::new("2") - &BigInteger::new("4");
475
476        assert_eq!(result, BigInteger::new("-2"));
477    }
478
479    #[test]
480    fn subtract_from_negative() {
481        let result = BigInteger::new("-123") - &BigInteger::new("456");
482
483        assert_eq!(result, BigInteger::new("-579"));
484    }
485
486    #[test]
487    fn subtract_large() {
488        let result = BigInteger::new("2") - &BigInteger::new("999999999999");
489
490        assert_eq!(result, BigInteger::new("-999999999997"));
491    }
492
493    ///////////////////////////////////////////////////////////////////////////
494
495    #[test]
496    fn multiply_single_digits() {
497        let result = BigInteger::new("2") * &BigInteger::new("2");
498
499        assert_eq!(result, BigInteger::new("4"));
500    }
501
502    #[test]
503    fn multiply_uneven() {
504        let result = BigInteger::new("2") * &BigInteger::new("16384");
505
506        assert_eq!(result, BigInteger::new("32768"));
507    }
508
509    #[test]
510    fn multiply_large() {
511        let result = BigInteger::new("901238123") * &BigInteger::new("238271282");
512
513        assert_eq!(result, BigInteger::new("214739162954483686"));
514    }
515}