From 52ce18b89716d53039c8cece885e0852f9208f2c Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 15 Feb 2022 10:20:16 -0500 Subject: [PATCH] Refactoring for a more convenient BigInt api --- justfile | 4 +- src/bigint.rs | 175 +++++++++++++++++++++++++------------------------- 2 files changed, 89 insertions(+), 90 deletions(-) diff --git a/justfile b/justfile index bada7b2..37654bd 100644 --- a/justfile +++ b/justfile @@ -10,8 +10,8 @@ coverage: # Remove generated files clean: cargo clean - rm cobertura.xml - rm coverage.html + rm -f cobertura.xml + rm -f coverage.html # Check code style lint: diff --git a/src/bigint.rs b/src/bigint.rs index 2ca7800..3d93d91 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -13,7 +13,7 @@ use core::convert::TryInto; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; -use core::usize; +use core::prelude::v1::*; #[cfg(feature = "std")] use std::prelude::v1::*; @@ -28,10 +28,10 @@ pub struct BigInt { #[macro_export] macro_rules! big_int { ($w:literal) => { - $crate::bigint::BigInt::from($w) + $crate::bigint::BigInt::new($w) }; (- $x:literal) => { - $crate::bigint::BigInt::from(-$x) + $crate::bigint::BigInt::new(-$x) }; } @@ -55,25 +55,26 @@ impl From for BigInt { impl From<&str> for BigInt { fn from(s: &str) -> Self { - Self::from_str_radix(s, 10) + Self::from_str(s, 10) } } impl From for BigInt { fn from(s: String) -> Self { - Self::from_str_radix(&s, 10) + Self::from_str(&s, 10) } } impl BigInt { /// Create a new Bigint, of value 0 /// - /// The various `From` implementations are more useful in most cases + /// In most cases, you probably want to use [new](`BigInt::new`) instead #[must_use] pub fn zero() -> Self { Self::default() } + /// Create a new `BigInt` from an existing Rust primitive type pub fn new(initial: impl Into) -> Self { initial.into() } @@ -130,7 +131,7 @@ impl BigInt { /// Convert a `&str` or a `String` representing a number in the specified radix to a Bigint. /// - /// For radix 10, use the `from` associated function instead. + /// For radix 10, use the `new` or `from` associated function instead. /// /// Radix must be between 1 and 36, inclusive, with radix higher /// than 11 represented by A-Z @@ -141,7 +142,7 @@ impl BigInt { /// # Panics /// * If radix is not between 1 and 36 inclusive /// * Some branches are not yet implemented - pub fn from_str_radix(s: &T, radix: usize) -> BigInt { + pub fn from_str(s: &T, radix: usize) -> BigInt { // Two lines due to borrow checker complaints let input = s.to_string().to_ascii_uppercase(); let input = input.trim(); @@ -162,12 +163,12 @@ impl BigInt { } } - return BigInt::from(raw_digits.len()); + return BigInt::new(raw_digits.len()); } // If the number fits in a usize, try the easy way if let Ok(easy_res) = usize::from_str_radix(input, radix.try_into().unwrap()) { - return BigInt::from(easy_res); + return BigInt::new(easy_res); } // TODO: consider parsing out the error, to tell if the @@ -289,7 +290,7 @@ impl Add for BigInt { if overflowed { out.inner.push(res + carry); carry = 1; - } else if res < core::usize::MAX { + } else if res < usize::MAX { out.inner.push(res + carry); carry = 0; } else { @@ -339,7 +340,7 @@ impl Sub for BigInt { // In base ten, this would be like: // 15 - 8 = (9 - 8) + (5 + 1) let rem = (a + 1) - borrow; - let res = (core::usize::MAX - b) + rem; + let res = (usize::MAX - b) + rem; out.inner.push(res); borrow = 1; @@ -527,8 +528,7 @@ macro_rules! impl_from_larger { impl From<$s> for BigInt { /// Create a `BigInt` from a signed integer primitive fn from(n: $s) -> Self { - use core::usize::MAX; - let target_radix: $s = (MAX as $s) + 1; + let target_radix: $s = (usize::MAX as $s) + 1; let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; let n = n.abs(); @@ -562,8 +562,7 @@ macro_rules! impl_from_larger { impl From<$u> for BigInt { /// Create a `BigInt` from an unsigned integer primitive fn from(n: $u) -> Self { - use core::usize::MAX; - let target_radix: $u = (MAX as $u) + 1; + let target_radix: $u = (usize::MAX as $u) + 1; let mut quotient = n / target_radix; let mut rem = n % target_radix; @@ -601,28 +600,28 @@ macro_rules! impl_ord_literal { impl PartialEq<$prim> for BigInt { #[must_use] fn eq(&self, other: &$prim) -> bool { - self == &BigInt::from(*other) + self == &BigInt::new(*other) } } impl PartialEq for $prim { #[must_use] fn eq(&self, other: &BigInt) -> bool { - &BigInt::from(*self) == other + &BigInt::new(*self) == other } } impl PartialOrd<$prim> for BigInt { #[must_use] fn partial_cmp(&self, other: &$prim) -> Option { - self.partial_cmp(&BigInt::from(*other)) + self.partial_cmp(&BigInt::new(*other)) } } impl PartialOrd for $prim { #[must_use] fn partial_cmp(&self, other: &BigInt) -> Option { - (&BigInt::from(*self)).partial_cmp(other) + (&BigInt::new(*self)).partial_cmp(other) } } )+ @@ -647,23 +646,23 @@ impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); mod tests { use super::*; - const RADIX: u128 = core::usize::MAX as u128 + 1; - const I_RADIX: i128 = core::usize::MAX as i128 + 1; + const RADIX: u128 = usize::MAX as u128 + 1; + const I_RADIX: i128 = usize::MAX as i128 + 1; #[test] fn sanity_checks() { - let int = BigInt::from(45u8); + let int = BigInt::new(45u8); assert_eq!(int.inner[0], 45usize) } #[test] fn test_macro() { let a = big_int!(75); - let b = BigInt::from(75); + let b = BigInt::new(75); assert_eq!(a, b); let a = big_int!(-75); - let b = BigInt::from(-75); + let b = BigInt::new(-75); assert_eq!(a, b); } @@ -676,7 +675,7 @@ mod tests { lots_of_leading.trim_zeros(); - assert_eq!(BigInt::from(1), lots_of_leading); + assert_eq!(BigInt::new(1), lots_of_leading); } #[test] @@ -685,32 +684,32 @@ mod tests { // so the sum should be // [MAX -1, 1] // Compare base 10: 9 + 9 = 18 - let a = BigInt::from(core::usize::MAX); - let b = BigInt::from(core::usize::MAX); + let a = BigInt::new(usize::MAX); + let b = BigInt::new(usize::MAX); let sum = a + b; assert_eq!( sum.inner[0], - core::usize::MAX - 1, + usize::MAX - 1, "least significant place should be MAX - 1" ); assert_eq!(sum.inner[1], 1usize, "most significant place should be 1"); - let a = BigInt::from(core::usize::MAX); - let b = BigInt::from(1usize); + let a = BigInt::new(usize::MAX); + let b = BigInt::new(1usize); let sum = a + b; assert_eq!(sum.inner[0], 0_usize); assert_eq!(sum.inner[1], 1usize); - let a = BigInt::from(10); - let b = -BigInt::from(5); + let a = BigInt::new(10); + let b = -BigInt::new(5); let sum = a + b; assert_eq!(sum.inner[0], 5usize); assert_eq!(sum.sign, Positive); - let a = -BigInt::from(5); - let b = BigInt::from(10); + let a = -BigInt::new(5); + let b = BigInt::new(10); let sum = a + b; assert_eq!(sum.inner[0], 5usize); assert_eq!(sum.sign, Positive); @@ -718,14 +717,14 @@ mod tests { #[test] fn test_add_assign() { - let mut a = BigInt::from(core::usize::MAX); - let b = BigInt::from(core::usize::MAX); + let mut a = BigInt::new(usize::MAX); + let b = BigInt::new(usize::MAX); a += b; assert_eq!( a.inner[0], - core::usize::MAX - 1, + usize::MAX - 1, "least significant place should be MAX - 1" ); assert_eq!(a.inner[1], 1usize, "most significant place should be 1"); @@ -733,24 +732,24 @@ mod tests { #[test] fn test_sub() { - let a = BigInt::from(core::usize::MAX); - let b = BigInt::from(core::u16::MAX); + let a = BigInt::new(usize::MAX); + let b = BigInt::new(core::u16::MAX); let diff = a - b; assert_eq!( diff.clone().inner[0], - core::usize::MAX - core::u16::MAX as usize + usize::MAX - core::u16::MAX as usize ); assert_eq!(diff.inner.len(), 1); - let a = BigInt::from(5); - let b = -BigInt::from(3); + let a = BigInt::new(5); + let b = -BigInt::new(3); let diff = a - b; assert_eq!(diff.sign, Positive); assert_eq!(diff.inner[0], 8usize); - let a = -BigInt::from(5); - let b = BigInt::from(3); + let a = -BigInt::new(5); + let b = BigInt::new(3); let diff = a - b; assert_eq!(diff.sign, Negative); assert_eq!(diff.inner[0], 8usize); @@ -763,10 +762,10 @@ mod tests { sign: Positive, }; - let b = BigInt::from(2); + let b = BigInt::new(2); let diff = a - b; assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone()); - assert_eq!(diff.inner[0], core::usize::MAX - 1); + assert_eq!(diff.inner[0], usize::MAX - 1); } #[test] @@ -775,7 +774,7 @@ mod tests { inner: vec![1, 0, 1], sign: Positive, }; - let b = BigInt::from(2); + let b = BigInt::new(2); a -= b; @@ -784,8 +783,8 @@ mod tests { #[test] fn test_mul() { - let a = BigInt::from(65536); - let b = BigInt::from(4); + let a = BigInt::new(65536); + let b = BigInt::new(4); let product = a * b; assert_eq!(product.inner[0], 65536usize * 4); @@ -793,26 +792,26 @@ mod tests { #[test] fn test_mul_signs() { - let a = BigInt::from(2); - let b = BigInt::from(-2); + let a = BigInt::new(2); + let b = BigInt::new(-2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Negative); - let a = -BigInt::from(2); - let b = BigInt::from(2); + let a = -BigInt::new(2); + let b = BigInt::new(2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Negative); - let a = BigInt::from(-2); - let b = BigInt::from(-2); + let a = BigInt::new(-2); + let b = BigInt::new(-2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Positive); - let a = BigInt::from(2); - let b = BigInt::from(2); + let a = BigInt::new(2); + let b = BigInt::new(2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Positive); @@ -821,8 +820,8 @@ mod tests { #[test] #[should_panic] fn test_mul_overflow() { - let a = BigInt::from(core::usize::MAX); - let b = BigInt::from(5); + let a = BigInt::new(usize::MAX); + let b = BigInt::new(5); let _product = a * b; } @@ -830,8 +829,8 @@ mod tests { #[test] #[should_panic] fn test_mul_assign_overflow() { - let mut a = BigInt::from(core::usize::MAX); - let b = BigInt::from(5); + let mut a = BigInt::new(usize::MAX); + let b = BigInt::new(5); a *= b; } @@ -839,8 +838,8 @@ mod tests { #[test] #[should_panic] fn test_div() { - let a = BigInt::from(128); - let b = BigInt::from(32); + let a = BigInt::new(128); + let b = BigInt::new(32); let _quotient = a / b; } @@ -848,8 +847,8 @@ mod tests { #[test] #[should_panic] fn test_div_assign() { - let mut a = BigInt::from(128); - let b = BigInt::from(32); + let mut a = BigInt::new(128); + let b = BigInt::new(32); a /= b; } @@ -857,8 +856,8 @@ mod tests { #[test] #[should_panic] fn test_rem() { - let a = BigInt::from(5); - let b = BigInt::from(2); + let a = BigInt::new(5); + let b = BigInt::new(2); let _rem = a % b; } @@ -866,8 +865,8 @@ mod tests { #[test] #[should_panic] fn test_rem_assign() { - let mut a = BigInt::from(5); - let b = BigInt::from(2); + let mut a = BigInt::new(5); + let b = BigInt::new(2); a %= b; } @@ -888,16 +887,16 @@ mod tests { #[test] fn test_not() { - let a = BigInt::from(0_u8); + let a = BigInt::new(0_u8); let b = !a; - assert_eq!(b.inner[0], core::usize::MAX); + assert_eq!(b.inner[0], usize::MAX); } #[test] fn test_partial_eq() { let a = 12345_u16; - let b = BigInt::from(a); + let b = BigInt::new(a); assert!(a.eq(&b)); assert!(b.eq(&a)); @@ -906,7 +905,7 @@ mod tests { #[test] fn test_partial_ord() { let a = 12345_u32; - let b = BigInt::from(a); + let b = BigInt::new(a); let c = 3_u8; assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal)); @@ -922,16 +921,16 @@ mod tests { #[test] fn test_from() { // Signed numbers - assert_eq!(-BigInt::from(2), BigInt::from(-2)); + assert_eq!(-BigInt::new(2), BigInt::new(-2)); // Larger than usize - assert_eq!(BigInt::from(45_u128), BigInt::from(45_usize)); + assert_eq!(BigInt::new(45_u128), BigInt::new(45_usize)); } #[test] fn test_from_large_unsigned() { let big_num: u128 = 9 * RADIX + 8; - let res = BigInt::from(big_num); + let res = BigInt::new(big_num); assert_eq!(res.sign, Sign::Positive, "{:#?}", res); assert_eq!(res.inner[0], 8_usize, "{:#?}", res); @@ -941,7 +940,7 @@ mod tests { #[test] fn test_from_large_signed() { let big_num: i128 = 2 * I_RADIX + 3; - let res = BigInt::from(-big_num); + let res = BigInt::new(-big_num); assert_eq!(res.sign, Sign::Negative, "{:#?}", res); assert_eq!(res.inner[0], 3_usize, "{:#?}", res); @@ -952,13 +951,13 @@ mod tests { #[should_panic] fn test_from_str_large() { let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"; - let _ = BigInt::from(str); + let _ = BigInt::new(str); } #[test] fn test_from_str_small() { let str = "012345"; - let num = BigInt::from(str); + let num = BigInt::new(str); assert_eq!(num.inner[0], 12345_usize); } @@ -966,20 +965,20 @@ mod tests { #[should_panic] fn test_from_string_large() { let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"); - let _ = BigInt::from(str); + let _ = BigInt::new(str); } #[test] fn test_from_string_small() { let str = String::from("012345"); - let num = BigInt::from(str); + let num = BigInt::new(str); assert_eq!(num.inner[0], 12345_usize); } #[test] fn test_from_str_radix_1() { let s = "1".repeat(32); - let num = BigInt::from_str_radix(&s, 1); + let num = BigInt::from_str(&s, 1); assert_eq!(num.inner[0], 32_usize); } @@ -989,25 +988,25 @@ mod tests { let zeroes = "0".repeat(24); let s = ones + &zeroes; - let num = BigInt::from_str_radix(&s, 1); + let num = BigInt::from_str(&s, 1); assert_eq!(num.inner[0], 32_usize); } #[test] #[should_panic] fn test_from_str_radix_invalid() { - let _ = BigInt::from_str_radix("foobar0", 50); + let _ = BigInt::from_str("foobar0", 50); } #[test] #[should_panic] fn test_from_str_radix_large() { - let _ = BigInt::from_str_radix("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321", 36); + let _ = BigInt::from_str("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321", 36); } #[test] fn test_from_str_radix_small() { - let num = BigInt::from_str_radix("FEDCBA", 16); + let num = BigInt::from_str("FEDCBA", 16); assert!(num.inner[0] > 0, "Number is not greater than 0"); assert!(num.inner[0] < usize::MAX, "Result is larger than usize"); assert_eq!(num.inner[0], 0xFEDCBA_usize); @@ -1015,7 +1014,7 @@ mod tests { #[test] fn test_from_str_radix_lowercase() { - let num = BigInt::from_str_radix("fedcba", 16); + let num = BigInt::from_str("fedcba", 16); assert_eq!(num.inner[0], 0xFEDCBA_usize); } }