From d90b76275459d8561667a48c433620558a5128a2 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 11 Sep 2020 15:23:42 -0400 Subject: [PATCH] Implement Bigint from implementation for integer types larger than the pointer type --- src/bigint.rs | 84 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/src/bigint.rs b/src/bigint.rs index a7af4c9..be85e9e 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -14,7 +14,7 @@ use alloc::string::*; use std::prelude::v1::*; use core::cmp::{Ordering, PartialOrd, PartialEq}; -use core::convert::TryInto; +use core::convert::*; use core::mem::replace; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, @@ -465,7 +465,36 @@ macro_rules! impl_from_larger { impl From<$s> for BigInt { /// Create a `BigInt` from a signed integer primitive fn from(n: $s) -> Self { - todo!(); + use core::usize::MAX; + let target_radix: $s = (MAX as $s) + 1; + let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; + let n = n.abs(); + + let mut quotient = n / target_radix; + let mut rem = n % target_radix; + + if quotient == 0 { + Self::from(rem as usize) + } else { + let mut inner: Vec = Vec::new(); + inner.push(rem as usize); + + loop { + rem = quotient % target_radix; + quotient = quotient / target_radix; + + inner.push(rem as usize); + + if (quotient == 0) { + break; + } + } + + BigInt { + inner, + sign, + } + } } } @@ -473,14 +502,32 @@ macro_rules! impl_from_larger { /// 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 base_usize_value = n / MAX as $u; - let rem = n % MAX as $u; + let mut quotient = n / target_radix; + let mut rem = n % target_radix; - if base_usize_value == 0 { + if quotient == 0 { Self::from(rem as usize) } else { - todo!(); + let mut inner: Vec = Vec::new(); + inner.push(rem as usize); + + loop { + rem = quotient % target_radix; + quotient = quotient / target_radix; + + inner.push(rem as usize); + + if (quotient == 0) { + break; + } + } + + BigInt { + inner, + sign: Sign::Positive + } } } } @@ -536,6 +583,9 @@ 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; + #[test] fn sanity_checks() { let int = BigInt::from(45u8); @@ -555,14 +605,14 @@ mod tests { #[test] fn test_trim_zeros() { - let mut lotsoftrailing = BigInt { + let mut lots_of_leading = BigInt { inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0], sign: Positive, }; - lotsoftrailing.trim_zeros(); + lots_of_leading.trim_zeros(); - assert_eq!(BigInt::from(1), lotsoftrailing); + assert_eq!(BigInt::from(1), lots_of_leading); } #[test] @@ -815,15 +865,23 @@ mod tests { } #[test] - #[should_panic] fn test_from_large_unsigned() { - BigInt::from(core::u128::MAX); + let big_num: u128 = 9*RADIX + 8; + let res = BigInt::from(big_num); + + assert_eq!(res.sign, Sign::Positive, "{:#?}", res); + assert_eq!(res.inner[0], 8usize, "{:#?}", res); + assert_eq!(res.inner[1], 9usize, "{:#?}", res); } #[test] - #[should_panic] fn test_from_large_signed() { - BigInt::from(128i128); + let big_num: i128 = 2*I_RADIX + 3; + let res = BigInt::from(-big_num); + + assert_eq!(res.sign, Sign::Negative, "{:#?}", res); + assert_eq!(res.inner[0], 3usize, "{:#?}", res); + assert_eq!(res.inner[1], 2usize, "{:#?}", res); } #[test]