add a "solutions" crate with a BigInt class
authorRalf Jung <post@ralfj.de>
Mon, 15 Jun 2015 15:40:22 +0000 (17:40 +0200)
committerRalf Jung <post@ralfj.de>
Mon, 15 Jun 2015 15:40:22 +0000 (17:40 +0200)
solutions/Cargo.lock [new file with mode: 0644]
solutions/Cargo.toml [new file with mode: 0644]
solutions/src/bigint.rs [new file with mode: 0644]
solutions/src/lib.rs [new file with mode: 0644]

diff --git a/solutions/Cargo.lock b/solutions/Cargo.lock
new file mode 100644 (file)
index 0000000..ffb21e6
--- /dev/null
@@ -0,0 +1,4 @@
+[root]
+name = "solutions"
+version = "0.1.0"
+
diff --git a/solutions/Cargo.toml b/solutions/Cargo.toml
new file mode 100644 (file)
index 0000000..8aebfa9
--- /dev/null
@@ -0,0 +1,4 @@
+[package]
+name = "solutions"
+version = "0.1.0"
+authors = ["Ralf Jung <post@ralfj.de>"]
diff --git a/solutions/src/bigint.rs b/solutions/src/bigint.rs
new file mode 100644 (file)
index 0000000..e9dfdf0
--- /dev/null
@@ -0,0 +1,211 @@
+use std::ops;
+use std::cmp;
+use std::fmt;
+
+pub struct BigInt {
+    data: Vec<u64>, // least significant digits first. The last block will *not* be 0.
+}
+
+// Add with carry, returning the sum and the carry
+fn overflowing_add(a: u64, b: u64, carry: bool) -> (u64, bool) {
+    match u64::checked_add(a, b) {
+        Some(sum) if !carry => (sum, false),
+        Some(sum) => { // we have to increment the sum by 1, where it may overflow again
+            match u64::checked_add(sum, 1) {
+                Some(total_sum) => (total_sum, false),
+                None => (0, true) // we overflowed incrementing by 1, so we are just "at the edge"
+            }
+        },
+        None => {
+            // Get the remainder, i.e., the wrapping sum. This cannot overflow again by adding just 1, so it is safe
+            // to add the carry here.
+            let rem = u64::wrapping_add(a, b) + if carry { 1 } else { 0 };
+            (rem, true)
+        }
+    }
+}
+
+
+impl BigInt {
+    /// Construct a BigInt from a "small" one.
+    pub fn new(x: u64) -> Self {
+        if x == 0 { // take care of our invariant!
+            BigInt { data: vec![] }
+        } else {
+            BigInt { data: vec![x] }
+        }
+    }
+
+    fn test_invariant(&self) -> bool {
+        if self.data.len() == 0 {
+            true
+        } else {
+            self.data[self.data.len() - 1] != 0
+        }
+    }
+
+    /// Construct a BigInt from a vector of 64-bit "digits", with the last significant digit being first
+    pub fn from_vec(mut v: Vec<u64>) -> Self {
+        // remove trailing zeroes
+        while v.len() > 0 && v[v.len()-1] == 0 {
+            v.pop();
+        }
+        BigInt { data: v }
+    }
+
+    /// Return the smaller of the two numbers
+    pub fn min(self, other: Self) -> Self {
+        debug_assert!(self.test_invariant() && other.test_invariant());
+        if self.data.len() < other.data.len() {
+            self
+        } else if self.data.len() > other.data.len() {
+            other
+        } else {
+            // compare back-to-front, i.e., most significant digit first
+            let mut idx = self.data.len()-1;
+            while idx > 0 {
+                if self.data[idx] < other.data[idx] {
+                    return self;
+                } else if self.data[idx] > other.data[idx] {
+                    return other;
+                }
+                else {
+                    idx = idx-1;
+                }
+            }
+            // the two are equal
+            return self;
+        }
+    }
+
+    /// Returns a view on the raw digits representing the number.
+    /// 
+    /// ```
+    /// use solutions::bigint::BigInt;
+    /// let b = BigInt::new(13);
+    /// let d = b.data();
+    /// assert_eq!(d, [13]);
+    /// ```
+    pub fn data(&self) -> &[u64] {
+        &self.data[..]
+    }
+
+    /// Increments the number by "by".
+    pub fn inc(&mut self, mut by: u64) {
+        let mut idx = 0;
+        // This loop adds "by * (1 << idx)". Think of "by" as the carry from incrementing the last digit.
+        while idx < self.data.len() {
+            let cur = self.data[idx];
+            let sum = u64::wrapping_add(cur, by);
+            self.data[idx] = sum;
+            if sum >= cur {
+                // No overflow, we are done.
+                return;
+            } else {
+                // We need to add a carry.
+                by = 1;
+                idx += 1;
+            }
+        }
+        // If we came here, there is a last carry to add
+        self.data.push(by);
+    }
+
+    /// Return the nth power-of-2 as BigInt
+    pub fn power_of_2(mut power: u64) -> BigInt {
+        let mut v = Vec::new();
+        while power >= 64 {
+            v.push(0);
+            power -= 64;
+        }
+        v.push(1 << power);
+        BigInt::from_vec(v)
+    }
+}
+
+impl Clone for BigInt {
+    fn clone(&self) -> Self {
+        BigInt { data: self.data.clone() }
+    }
+}
+
+
+impl PartialEq for BigInt {
+    fn eq(&self, other: &BigInt) -> bool {
+        debug_assert!(self.test_invariant() && other.test_invariant());
+        self.data() == other.data()
+    }
+}
+
+impl fmt::Debug for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.data().fmt(f)
+    }
+}
+
+impl<'a, 'b> ops::Add<&'a BigInt> for &'b BigInt {
+    type Output = BigInt;
+    fn add(self, rhs: &'a BigInt) -> Self::Output {
+        let mut result_vec:Vec<u64> = Vec::with_capacity(cmp::max(self.data().len(), rhs.data().len()));
+        let mut carry:bool = false; // the carry bit
+        for (i, val) in self.data().into_iter().enumerate() {
+            // compute next digit and carry
+            let rhs_val = if i < rhs.data().len() { rhs.data()[i] } else { 0 };
+            let (sum, new_carry) = overflowing_add(*val, rhs_val, carry);
+            // store them
+            result_vec.push(sum);
+            carry = new_carry;
+        }
+        BigInt::from_vec(result_vec)
+    }
+}
+
+impl<'a> ops::Add<BigInt> for &'a BigInt {
+    type Output = BigInt;
+    #[inline]
+    fn add(self, rhs: BigInt) -> Self::Output {
+        self + &rhs
+    }
+}
+
+impl<'a> ops::Add<&'a BigInt> for BigInt {
+    type Output = BigInt;
+    #[inline]
+    fn add(self, rhs: &'a BigInt) -> Self::Output {
+        &self + rhs
+    }
+}
+
+impl ops::Add<BigInt> for BigInt {
+    type Output = BigInt;
+    #[inline]
+    fn add(self, rhs: BigInt) -> Self::Output {
+        &self + &rhs
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::overflowing_add;
+    use super::BigInt;
+
+    #[test]
+    fn test_overflowing_add() {
+        assert_eq!(overflowing_add(10, 100, false), (110, false));
+        assert_eq!(overflowing_add(10, 100, true), (111, false));
+        assert_eq!(overflowing_add(1 << 63, 1 << 63, false), (0, true));
+        assert_eq!(overflowing_add(1 << 63, 1 << 63, true), (1, true));
+        assert_eq!(overflowing_add(1 << 63, (1 << 63) -1 , true), (0, true));
+    }
+
+    #[test]
+    fn test_power_of_2() {
+        assert_eq!(BigInt::power_of_2(0), BigInt::new(1));
+        assert_eq!(BigInt::power_of_2(13), BigInt::new(1 << 13));
+        assert_eq!(BigInt::power_of_2(64), BigInt::from_vec(vec![0, 1]));
+        assert_eq!(BigInt::power_of_2(96), BigInt::from_vec(vec![0, 1 << 32]));
+        assert_eq!(BigInt::power_of_2(128), BigInt::from_vec(vec![0, 0, 1]));
+    }
+}
+
+
diff --git a/solutions/src/lib.rs b/solutions/src/lib.rs
new file mode 100644 (file)
index 0000000..8f8d148
--- /dev/null
@@ -0,0 +1 @@
+pub mod bigint;