2020-03-05 21:29:54 -05:00
|
|
|
#![allow(unused_variables)]
|
2020-02-19 16:22:01 -05:00
|
|
|
//! \[WIP\] Arbitrarily large integers
|
2021-03-11 15:38:37 -05:00
|
|
|
use crate::num::FracOp;
|
|
|
|
use crate::num::Sign::{self, Positive, Negative};
|
2020-04-16 14:07:12 -04:00
|
|
|
|
|
|
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
|
|
|
extern crate alloc;
|
|
|
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
|
|
|
use alloc::string::*;
|
2020-09-11 15:25:05 -04:00
|
|
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
|
|
|
use alloc::vec::*;
|
2020-04-16 14:07:12 -04:00
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
use std::prelude::v1::*;
|
|
|
|
|
2020-09-11 15:25:05 -04:00
|
|
|
use core::cmp::{Ordering, PartialEq, PartialOrd};
|
2020-09-11 15:23:42 -04:00
|
|
|
use core::convert::*;
|
2020-03-13 16:31:37 -04:00
|
|
|
use core::mem::replace;
|
2020-03-04 16:16:28 -05:00
|
|
|
use core::ops::{
|
|
|
|
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign,
|
|
|
|
};
|
2020-03-05 21:29:54 -05:00
|
|
|
use core::usize;
|
2020-02-12 22:29:57 -05:00
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2020-02-12 22:29:57 -05:00
|
|
|
pub struct BigInt {
|
|
|
|
inner: Vec<usize>,
|
2020-02-12 23:10:08 -05:00
|
|
|
sign: Sign,
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
|
2020-04-07 13:46:51 -04:00
|
|
|
/// Create a [BigInt](bigint/struct.BigInt.html) type with signed or unsigned number literals
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! big_int {
|
|
|
|
($w:literal) => {
|
|
|
|
$crate::bigint::BigInt::from($w)
|
|
|
|
};
|
|
|
|
(-$x:literal) => {
|
|
|
|
$crate::bigint::BigInt::from(-$x)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
impl Default for BigInt {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2020-03-03 16:33:21 -05:00
|
|
|
inner: vec![0],
|
2020-03-05 21:29:54 -05:00
|
|
|
sign: Sign::default(),
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-03 16:33:21 -05:00
|
|
|
impl From<usize> for BigInt {
|
|
|
|
fn from(n: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
inner: vec![n],
|
2020-03-05 21:29:54 -05:00
|
|
|
sign: Sign::default(),
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 16:22:01 -05:00
|
|
|
impl From<&str> for BigInt {
|
2020-03-04 16:16:28 -05:00
|
|
|
fn from(s: &str) -> Self {
|
|
|
|
Self::from_str_radix(s, 10)
|
2020-02-19 16:22:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<String> for BigInt {
|
2020-03-04 16:16:28 -05:00
|
|
|
fn from(s: String) -> Self {
|
|
|
|
Self::from_str_radix(s, 10)
|
2020-02-19 16:22:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 23:10:08 -05:00
|
|
|
impl BigInt {
|
2020-03-05 21:29:54 -05:00
|
|
|
/// Create a new Bigint, of value 0
|
|
|
|
///
|
|
|
|
/// The various `From` implementations are more useful in most cases
|
2020-02-13 17:13:25 -05:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
fn new_empty() -> Self {
|
|
|
|
Self {
|
|
|
|
inner: Vec::new(),
|
|
|
|
sign: Sign::Positive,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 14:17:25 -04:00
|
|
|
/// Create a new BigInt, with the specified inner capacity
|
|
|
|
pub fn with_capacity(size: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
inner: Vec::with_capacity(size),
|
|
|
|
sign: Positive,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
/// Remove digits that are zero from the internal representation.
|
|
|
|
///
|
|
|
|
/// Similar to 007 -> 7 in base 10
|
|
|
|
pub fn trim_zeros(&mut self) {
|
|
|
|
let current_len = self.inner.len();
|
|
|
|
if current_len < 2 {
|
2020-03-13 14:17:25 -04:00
|
|
|
return;
|
2020-03-05 21:29:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut trailing_zeros = 0usize;
|
|
|
|
for val in self.inner.iter().rev() {
|
|
|
|
if *val != 0 {
|
2020-03-13 14:17:25 -04:00
|
|
|
break;
|
2020-03-05 21:29:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
trailing_zeros += 1;
|
|
|
|
}
|
|
|
|
|
2020-03-11 13:58:56 -04:00
|
|
|
// Always keep at least one digit
|
|
|
|
if trailing_zeros == current_len {
|
|
|
|
trailing_zeros -= 1;
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
let new_len = current_len - trailing_zeros;
|
|
|
|
|
|
|
|
self.inner.truncate(new_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove unused digits, and shrink the internal vector
|
2020-02-24 16:30:59 -05:00
|
|
|
pub fn shrink_to_fit(&mut self) {
|
2020-03-05 21:29:54 -05:00
|
|
|
self.trim_zeros();
|
|
|
|
self.inner.shrink_to_fit();
|
2020-02-24 16:30:59 -05:00
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
/// 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.
|
2020-09-11 15:57:17 -04:00
|
|
|
///
|
|
|
|
/// Radix must be between 1 and 36, inclusive, with radix higher
|
|
|
|
/// than 11 represented by A-Z
|
|
|
|
///
|
|
|
|
/// Only alphanumeric characters are considered, so exponents and
|
|
|
|
/// other forms are not parsed
|
2020-03-04 16:16:28 -05:00
|
|
|
pub fn from_str_radix<T: ToString>(s: T, radix: usize) -> BigInt {
|
2020-09-24 11:28:13 -04:00
|
|
|
let input = s.to_string().to_ascii_uppercase();
|
|
|
|
let input = input.trim();
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
radix > 0 && radix <= 36,
|
|
|
|
"Radix must be between 1 and 36, inclusive. Given radix: {}",
|
|
|
|
radix
|
|
|
|
);
|
|
|
|
|
|
|
|
// In base 1, number of place values = total value
|
|
|
|
if radix == 1 {
|
|
|
|
let mut raw_digits: Vec<usize> = Vec::with_capacity(input.len());
|
|
|
|
for char in input.chars() {
|
|
|
|
match char {
|
|
|
|
'1' => raw_digits.push(1),
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return BigInt::from(raw_digits.len());
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the number fits in a usize, try the easy way
|
|
|
|
let easy_res = usize::from_str_radix(input, radix as u32);
|
|
|
|
if easy_res.is_ok() {
|
|
|
|
return BigInt::from(easy_res.unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: consider parsing out the error, to tell if the
|
|
|
|
// parsed result is valid for the base
|
2020-09-11 15:57:17 -04:00
|
|
|
|
|
|
|
// Convert each digit to it's decimal representation
|
|
|
|
let mut raw_digits: Vec<usize> = Vec::with_capacity(input.len());
|
|
|
|
for maybe_digit in input.chars() {
|
|
|
|
match maybe_digit.to_digit(radix as u32) {
|
|
|
|
Some(d) => raw_digits.push(d as usize),
|
|
|
|
None => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the decimal value by calculating the value
|
|
|
|
// of each place value
|
2020-02-12 22:29:57 -05:00
|
|
|
todo!();
|
|
|
|
}
|
2020-03-11 13:58:56 -04:00
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
fn get_ceil_digit_count(a: &Self, b: &Self) -> usize {
|
2020-03-11 13:58:56 -04:00
|
|
|
let a_digits = a.inner.len();
|
|
|
|
let b_digits = b.inner.len();
|
|
|
|
|
2020-03-13 23:02:27 -04:00
|
|
|
if a_digits == 0 && b_digits == 0 {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if b_digits > a_digits {
|
2020-03-11 13:58:56 -04:00
|
|
|
b_digits
|
|
|
|
} else {
|
|
|
|
a_digits
|
|
|
|
}
|
|
|
|
}
|
2020-03-24 13:26:00 -04:00
|
|
|
|
|
|
|
/// Determine the output sign given the two input signs and operation
|
|
|
|
fn get_sign(a: Self, b: Self, op: FracOp) -> Sign {
|
|
|
|
// -a + -b = -c
|
|
|
|
if op == FracOp::Addition && a.sign == Negative && b.sign == Negative {
|
|
|
|
return Negative;
|
|
|
|
}
|
|
|
|
|
|
|
|
// a - -b = c
|
|
|
|
if op == FracOp::Subtraction && a.sign == Positive && b.sign == Negative {
|
|
|
|
return Positive;
|
|
|
|
}
|
|
|
|
|
|
|
|
if a.sign != b.sign {
|
|
|
|
Negative
|
|
|
|
} else {
|
|
|
|
Positive
|
|
|
|
}
|
|
|
|
}
|
2020-05-05 15:41:27 -04:00
|
|
|
|
|
|
|
/// Normal primitive multiplication
|
|
|
|
fn prim_mul(self, rhs: Self, digits: usize) -> Self {
|
|
|
|
let mut out = BigInt::with_capacity(digits);
|
|
|
|
|
|
|
|
let mut carry = 0usize;
|
|
|
|
for i in 0..digits {
|
|
|
|
let a = *self.inner.get(i).unwrap_or(&0usize);
|
|
|
|
let b = *rhs.inner.get(i).unwrap_or(&0usize);
|
|
|
|
|
|
|
|
if a == 0 || b == 0 {
|
|
|
|
out.inner.push(0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (res, overflowed) = a.overflowing_mul(b);
|
|
|
|
|
|
|
|
if overflowed {
|
|
|
|
todo!()
|
|
|
|
} else {
|
|
|
|
let (res, overflowed) = res.overflowing_add(carry);
|
|
|
|
|
|
|
|
out.inner.push(res);
|
|
|
|
carry = if overflowed { 1 } else { 0 };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out.sign = Self::get_sign(self, rhs, FracOp::Other);
|
|
|
|
out.shrink_to_fit();
|
|
|
|
|
|
|
|
out
|
|
|
|
}
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
|
2020-03-04 16:16:28 -05:00
|
|
|
impl Add for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
2020-03-24 13:26:00 -04:00
|
|
|
// If the sign of one input differs,
|
|
|
|
// subtraction is equivalent
|
|
|
|
if self.sign == Negative && rhs.sign == Positive {
|
|
|
|
return rhs - -self;
|
|
|
|
} else if self.sign == Positive && rhs.sign == Negative {
|
2020-03-11 10:52:49 -04:00
|
|
|
return self - -rhs;
|
|
|
|
}
|
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
let digits = Self::get_ceil_digit_count(&self, &rhs) + 1;
|
2020-03-13 14:17:25 -04:00
|
|
|
let mut out = BigInt::with_capacity(digits);
|
2020-03-04 16:16:28 -05:00
|
|
|
|
|
|
|
let mut carry = 0usize;
|
2020-03-11 13:58:56 -04:00
|
|
|
for i in 0..digits {
|
2020-03-04 16:16:28 -05:00
|
|
|
let a = *self.inner.get(i).unwrap_or(&0usize);
|
|
|
|
let b = *rhs.inner.get(i).unwrap_or(&0usize);
|
|
|
|
|
|
|
|
let (res, overflowed) = a.overflowing_add(b);
|
2020-03-11 13:58:56 -04:00
|
|
|
if res == 0 && !overflowed {
|
|
|
|
out.inner.push(res + carry);
|
|
|
|
carry = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-04 16:16:28 -05:00
|
|
|
if overflowed {
|
2020-03-05 21:29:54 -05:00
|
|
|
out.inner.push(res + carry);
|
2020-03-05 16:24:33 -05:00
|
|
|
carry = 1;
|
2020-03-05 21:29:54 -05:00
|
|
|
} else if res < core::usize::MAX {
|
|
|
|
out.inner.push(res + carry);
|
2020-03-04 16:16:28 -05:00
|
|
|
carry = 0;
|
2020-03-05 21:29:54 -05:00
|
|
|
} else {
|
|
|
|
out.inner.push(0usize);
|
|
|
|
carry = 1;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 13:26:00 -04:00
|
|
|
out.sign = Self::get_sign(self, rhs, FracOp::Addition);
|
|
|
|
|
2020-03-11 13:58:56 -04:00
|
|
|
out.trim_zeros();
|
|
|
|
|
2020-03-04 16:16:28 -05:00
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
2020-05-05 15:41:27 -04:00
|
|
|
let digits = Self::get_ceil_digit_count(&self, &rhs);
|
2020-03-13 14:17:25 -04:00
|
|
|
let mut out = BigInt::with_capacity(digits);
|
2020-03-10 20:46:51 -04:00
|
|
|
|
2020-03-24 13:26:00 -04:00
|
|
|
// Handle cases where addition makes more sense
|
|
|
|
if self.sign == Positive && rhs.sign == Negative {
|
|
|
|
return self + -rhs;
|
|
|
|
} else if self.sign == Negative && rhs.sign == Positive {
|
|
|
|
return -(rhs + -self);
|
|
|
|
}
|
|
|
|
|
2020-03-10 20:46:51 -04:00
|
|
|
let mut borrow = 0usize;
|
|
|
|
for i in 0..digits {
|
|
|
|
let a = *self.inner.get(i).unwrap_or(&0usize);
|
|
|
|
let b = *rhs.inner.get(i).unwrap_or(&0usize);
|
|
|
|
|
2020-03-11 14:01:45 -04:00
|
|
|
if a >= borrow && (a - borrow) >= b {
|
2020-05-05 15:41:27 -04:00
|
|
|
// This is the easy way, no additional borrowing or underflow
|
2020-03-11 10:52:49 -04:00
|
|
|
let res = a - b - borrow;
|
|
|
|
|
|
|
|
out.inner.push(res);
|
2020-03-10 20:46:51 -04:00
|
|
|
borrow = 0;
|
2020-03-13 14:17:25 -04:00
|
|
|
} else {
|
2020-05-05 15:41:27 -04:00
|
|
|
// To prevent overflow, the max borrowed value is
|
|
|
|
// usize::MAX (place-value - 1). The rest of the borrowed value
|
2020-03-11 10:52:49 -04:00
|
|
|
// will be added on afterwords.
|
|
|
|
// In base ten, this would be like:
|
2020-05-05 15:41:27 -04:00
|
|
|
// 15 - 8 = (9 - 8) + (5 + 1)
|
2020-03-11 10:52:49 -04:00
|
|
|
let rem = (a + 1) - borrow;
|
|
|
|
let res = (core::usize::MAX - b) + rem;
|
|
|
|
out.inner.push(res);
|
|
|
|
|
|
|
|
borrow = 1;
|
2020-03-10 20:46:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 13:26:00 -04:00
|
|
|
out.sign = Self::get_sign(self, rhs, FracOp::Subtraction);
|
|
|
|
|
2020-03-11 10:52:49 -04:00
|
|
|
out.trim_zeros();
|
|
|
|
|
2020-03-10 20:46:51 -04:00
|
|
|
out
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Mul for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn mul(self, rhs: Self) -> Self::Output {
|
2020-05-05 15:41:27 -04:00
|
|
|
let input_digits = Self::get_ceil_digit_count(&self, &rhs);
|
2020-04-02 17:01:55 -04:00
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
// Multiplication can result in twice the number of digits
|
|
|
|
let out_digits = Self::get_ceil_digit_count(&self, &rhs) * 2;
|
2020-03-13 14:17:25 -04:00
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
self.prim_mul(rhs, out_digits)
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Div for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn div(self, rhs: Self) -> Self::Output {
|
2020-03-05 21:29:54 -05:00
|
|
|
todo!()
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Rem for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn rem(self, rhs: Self) -> Self::Output {
|
2020-03-05 21:29:54 -05:00
|
|
|
todo!()
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AddAssign for BigInt {
|
|
|
|
fn add_assign(&mut self, rhs: Self) {
|
2020-03-13 16:31:37 -04:00
|
|
|
let this = replace(self, BigInt::new());
|
|
|
|
*self = this + rhs;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SubAssign for BigInt {
|
|
|
|
fn sub_assign(&mut self, rhs: Self) {
|
2020-03-13 16:31:37 -04:00
|
|
|
let this = replace(self, BigInt::new());
|
|
|
|
*self = this - rhs;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MulAssign for BigInt {
|
|
|
|
fn mul_assign(&mut self, rhs: Self) {
|
2020-03-13 16:31:37 -04:00
|
|
|
let this = replace(self, BigInt::new());
|
|
|
|
*self = this * rhs;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DivAssign for BigInt {
|
|
|
|
fn div_assign(&mut self, rhs: Self) {
|
2020-03-13 16:31:37 -04:00
|
|
|
let this = replace(self, BigInt::new());
|
|
|
|
*self = this / rhs;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RemAssign for BigInt {
|
|
|
|
fn rem_assign(&mut self, rhs: Self) {
|
2020-03-13 16:31:37 -04:00
|
|
|
let this = replace(self, BigInt::new());
|
|
|
|
*self = this % rhs;
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Neg for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
/// Flip the sign of the current `BigInt` value
|
2020-03-13 14:17:25 -04:00
|
|
|
fn neg(mut self) -> Self::Output {
|
|
|
|
self.sign = !self.sign;
|
2020-03-04 16:16:28 -05:00
|
|
|
|
2020-03-13 14:17:25 -04:00
|
|
|
self
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 09:20:02 -05:00
|
|
|
impl Not for BigInt {
|
|
|
|
type Output = Self;
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
/// Do a bitwise negation of every digit's value
|
2020-03-05 09:20:02 -05:00
|
|
|
fn not(self) -> Self::Output {
|
|
|
|
let mut flipped: Vec<usize> = Vec::with_capacity(self.inner.len());
|
|
|
|
|
2021-03-11 15:38:37 -05:00
|
|
|
for val in &self.inner {
|
2020-03-05 16:24:33 -05:00
|
|
|
let rev = !*val;
|
|
|
|
flipped.push(rev);
|
2020-03-05 09:20:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
BigInt {
|
|
|
|
sign: self.sign,
|
|
|
|
inner: flipped,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
impl PartialOrd for BigInt {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
// The signs differ
|
|
|
|
if self.sign != other.sign {
|
|
|
|
// If the signs are different, the magnitude doesn't matter
|
|
|
|
// unless the value is zero on both sides
|
|
|
|
return if self.eq(&0) && other.eq(&0) {
|
|
|
|
Some(Ordering::Equal)
|
|
|
|
} else {
|
|
|
|
self.sign.partial_cmp(&other.sign)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Everything is the same
|
|
|
|
if self.inner == other.inner {
|
|
|
|
return Some(Ordering::Equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The number of place values differs
|
|
|
|
if self.inner.len() != other.inner.len() {
|
|
|
|
return if self.inner.len() > other.inner.len() {
|
|
|
|
Some(Ordering::Greater)
|
|
|
|
} else {
|
|
|
|
Some(Ordering::Less)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the sign is the same, and the number of place values is equal,
|
|
|
|
// so compare the individual place values (from greatest to least) until they
|
|
|
|
// are different. At this point, the digits can not all be equal.
|
|
|
|
for i in (0usize..self.inner.len()).rev() {
|
|
|
|
if self.inner[i] < other.inner[i] {
|
|
|
|
return Some(Ordering::Less);
|
|
|
|
} else if self.inner[i] > other.inner[i] {
|
|
|
|
return Some(Ordering::Greater);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
macro_rules! impl_from_smaller {
|
|
|
|
($(($s: ty, $u: ty)),* ) => {
|
|
|
|
$(
|
|
|
|
impl From<$s> for BigInt {
|
|
|
|
/// Create a `BigInt` from a signed integer primitive
|
|
|
|
fn from(n: $s) -> Self {
|
|
|
|
let sign = if n < 0 { Sign::Negative } else { Sign::Positive };
|
|
|
|
let n = n.abs();
|
|
|
|
let raw: usize = <$s>::try_into(n).unwrap();
|
|
|
|
|
|
|
|
Self {
|
|
|
|
inner: vec![raw],
|
|
|
|
sign,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<$u> for BigInt {
|
|
|
|
/// Create a `BigInt` from an unsigned integer primitive
|
|
|
|
fn from(n: $u) -> Self {
|
|
|
|
let mut new = Self::new_empty();
|
|
|
|
new.inner.push(n as usize);
|
|
|
|
|
|
|
|
new
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_from_larger {
|
|
|
|
($(($s: ty, $u: ty)),* ) => {
|
|
|
|
$(
|
|
|
|
impl From<$s> for BigInt {
|
|
|
|
/// Create a `BigInt` from a signed integer primitive
|
|
|
|
fn from(n: $s) -> Self {
|
2020-09-11 15:23:42 -04:00
|
|
|
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<usize> = Vec::new();
|
|
|
|
inner.push(rem as usize);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
rem = quotient % target_radix;
|
2021-03-11 15:38:37 -05:00
|
|
|
quotient /= target_radix;
|
2020-09-11 15:23:42 -04:00
|
|
|
|
|
|
|
inner.push(rem as usize);
|
|
|
|
|
|
|
|
if (quotient == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BigInt {
|
|
|
|
inner,
|
|
|
|
sign,
|
|
|
|
}
|
|
|
|
}
|
2020-03-05 21:29:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<$u> for BigInt {
|
|
|
|
/// Create a `BigInt` from an unsigned integer primitive
|
|
|
|
fn from(n: $u) -> Self {
|
|
|
|
use core::usize::MAX;
|
2020-09-11 15:23:42 -04:00
|
|
|
let target_radix: $u = (MAX as $u) + 1;
|
2020-03-05 21:29:54 -05:00
|
|
|
|
2020-09-11 15:23:42 -04:00
|
|
|
let mut quotient = n / target_radix;
|
|
|
|
let mut rem = n % target_radix;
|
2020-03-05 21:29:54 -05:00
|
|
|
|
2020-09-11 15:23:42 -04:00
|
|
|
if quotient == 0 {
|
2020-03-05 21:29:54 -05:00
|
|
|
Self::from(rem as usize)
|
|
|
|
} else {
|
2020-09-11 15:23:42 -04:00
|
|
|
let mut inner: Vec<usize> = Vec::new();
|
|
|
|
inner.push(rem as usize);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
rem = quotient % target_radix;
|
2021-03-11 15:38:37 -05:00
|
|
|
quotient /= target_radix;
|
2020-09-11 15:23:42 -04:00
|
|
|
|
|
|
|
inner.push(rem as usize);
|
|
|
|
|
|
|
|
if (quotient == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BigInt {
|
|
|
|
inner,
|
|
|
|
sign: Sign::Positive
|
|
|
|
}
|
2020-03-05 21:29:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
macro_rules! impl_ord_literal {
|
2020-05-05 18:49:19 -04:00
|
|
|
($($prim: ty),+) => {
|
2020-05-05 15:41:27 -04:00
|
|
|
$(
|
2020-05-05 18:49:19 -04:00
|
|
|
impl PartialEq<$prim> for BigInt {
|
|
|
|
fn eq(&self, other: &$prim) -> bool {
|
|
|
|
self == &BigInt::from(*other)
|
2020-05-05 15:41:27 -04:00
|
|
|
}
|
2020-05-05 18:49:19 -04:00
|
|
|
}
|
2020-05-05 15:41:27 -04:00
|
|
|
|
2020-05-05 18:49:19 -04:00
|
|
|
impl PartialEq<BigInt> for $prim {
|
|
|
|
fn eq(&self, other: &BigInt) -> bool {
|
|
|
|
&BigInt::from(*self) == other
|
2020-05-05 15:41:27 -04:00
|
|
|
}
|
2020-05-05 18:49:19 -04:00
|
|
|
}
|
2020-05-05 15:41:27 -04:00
|
|
|
|
2020-05-05 18:49:19 -04:00
|
|
|
impl PartialOrd<$prim> for BigInt {
|
|
|
|
fn partial_cmp(&self, other: &$prim) -> Option<Ordering> {
|
|
|
|
self.partial_cmp(&BigInt::from(*other))
|
2020-05-05 15:41:27 -04:00
|
|
|
}
|
2020-05-05 18:49:19 -04:00
|
|
|
}
|
2020-05-05 15:41:27 -04:00
|
|
|
|
2020-05-05 18:49:19 -04:00
|
|
|
impl PartialOrd<BigInt> for $prim {
|
|
|
|
fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
|
|
|
|
(&BigInt::from(*self)).partial_cmp(other)
|
2020-05-05 15:41:27 -04:00
|
|
|
}
|
2020-05-05 18:49:19 -04:00
|
|
|
}
|
|
|
|
)+
|
2020-05-05 15:41:27 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
|
|
impl_from_larger!((i64, u64), (i128, u128));
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
|
|
impl_from_smaller!((i8, u8), (i16, u16), (i32, u32));
|
|
|
|
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
|
|
|
impl_from_larger!((i128, u128));
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
|
|
|
impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64));
|
2020-05-05 18:49:19 -04:00
|
|
|
|
|
|
|
// Implement PartialEq and PartialOrd to compare against BigInt values
|
2020-09-11 15:25:05 -04:00
|
|
|
impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
|
2020-03-05 21:29:54 -05:00
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
#[cfg(test)]
|
2020-09-15 10:31:44 -04:00
|
|
|
#[cfg(not(tarpaulin_include))]
|
2020-02-24 16:30:59 -05:00
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2020-09-11 15:23:42 -04:00
|
|
|
const RADIX: u128 = core::usize::MAX as u128 + 1;
|
|
|
|
const I_RADIX: i128 = core::usize::MAX as i128 + 1;
|
|
|
|
|
2020-02-24 16:30:59 -05:00
|
|
|
#[test]
|
|
|
|
fn sanity_checks() {
|
2020-03-03 16:33:21 -05:00
|
|
|
let int = BigInt::from(45u8);
|
|
|
|
assert_eq!(int.inner[0], 45usize)
|
2020-02-24 16:30:59 -05:00
|
|
|
}
|
2020-03-03 16:33:21 -05:00
|
|
|
|
2020-04-07 13:46:51 -04:00
|
|
|
#[test]
|
|
|
|
fn test_macro() {
|
|
|
|
let a = big_int!(75);
|
|
|
|
let b = BigInt::from(75);
|
|
|
|
assert_eq!(a, b);
|
|
|
|
|
|
|
|
let a = big_int!(-75);
|
|
|
|
let b = BigInt::from(-75);
|
|
|
|
assert_eq!(a, b);
|
|
|
|
}
|
|
|
|
|
2020-03-11 11:16:40 -04:00
|
|
|
#[test]
|
|
|
|
fn test_trim_zeros() {
|
2020-09-11 15:23:42 -04:00
|
|
|
let mut lots_of_leading = BigInt {
|
2020-03-11 11:16:40 -04:00
|
|
|
inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0],
|
2020-03-13 14:17:25 -04:00
|
|
|
sign: Positive,
|
2020-03-11 11:16:40 -04:00
|
|
|
};
|
|
|
|
|
2020-09-11 15:23:42 -04:00
|
|
|
lots_of_leading.trim_zeros();
|
2020-03-11 11:16:40 -04:00
|
|
|
|
2020-09-11 15:23:42 -04:00
|
|
|
assert_eq!(BigInt::from(1), lots_of_leading);
|
2020-03-11 11:16:40 -04:00
|
|
|
}
|
|
|
|
|
2020-03-04 09:19:33 -05:00
|
|
|
#[test]
|
2020-03-03 16:33:21 -05:00
|
|
|
fn test_add() {
|
2020-03-04 09:19:33 -05:00
|
|
|
// MAX is 2^Bitsize - 1,
|
|
|
|
// 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);
|
2020-03-03 16:33:21 -05:00
|
|
|
|
2020-03-04 16:16:28 -05:00
|
|
|
let sum = a + b;
|
2020-03-03 16:33:21 -05:00
|
|
|
|
2020-03-04 16:16:28 -05:00
|
|
|
assert_eq!(
|
|
|
|
sum.inner[0],
|
|
|
|
core::usize::MAX - 1,
|
|
|
|
"least significant place should be MAX - 1"
|
|
|
|
);
|
2020-03-04 09:19:33 -05:00
|
|
|
assert_eq!(sum.inner[1], 1usize, "most significant place should be 1");
|
2020-03-05 09:20:02 -05:00
|
|
|
|
2020-03-05 16:24:33 -05:00
|
|
|
let a = BigInt::from(core::usize::MAX);
|
2020-03-05 09:20:02 -05:00
|
|
|
let b = BigInt::from(1usize);
|
|
|
|
let sum = a + b;
|
|
|
|
assert_eq!(sum.inner[0], 0usize);
|
2020-03-05 16:24:33 -05:00
|
|
|
assert_eq!(sum.inner[1], 1usize);
|
2020-03-26 11:40:14 -04:00
|
|
|
|
|
|
|
let a = BigInt::from(10);
|
|
|
|
let b = -BigInt::from(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 sum = a + b;
|
|
|
|
assert_eq!(sum.inner[0], 5usize);
|
|
|
|
assert_eq!(sum.sign, Positive);
|
2020-03-05 16:24:33 -05:00
|
|
|
}
|
|
|
|
|
2020-03-13 16:31:37 -04:00
|
|
|
#[test]
|
|
|
|
fn test_add_assign() {
|
|
|
|
let mut a = BigInt::from(core::usize::MAX);
|
|
|
|
let b = BigInt::from(core::usize::MAX);
|
|
|
|
|
|
|
|
a += b;
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
a.inner[0],
|
|
|
|
core::usize::MAX - 1,
|
|
|
|
"least significant place should be MAX - 1"
|
|
|
|
);
|
|
|
|
assert_eq!(a.inner[1], 1usize, "most significant place should be 1");
|
|
|
|
}
|
|
|
|
|
2020-03-10 20:46:51 -04:00
|
|
|
#[test]
|
|
|
|
fn test_sub() {
|
|
|
|
let a = BigInt::from(core::usize::MAX);
|
|
|
|
let b = BigInt::from(core::u16::MAX);
|
|
|
|
|
|
|
|
let diff = a - b;
|
|
|
|
assert_eq!(
|
2020-03-11 10:52:49 -04:00
|
|
|
diff.clone().inner[0],
|
2020-03-10 20:46:51 -04:00
|
|
|
core::usize::MAX - core::u16::MAX as usize
|
|
|
|
);
|
2020-03-11 10:52:49 -04:00
|
|
|
assert_eq!(diff.inner.len(), 1);
|
2020-03-26 11:40:14 -04:00
|
|
|
|
|
|
|
let a = BigInt::from(5);
|
|
|
|
let b = -BigInt::from(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 diff = a - b;
|
|
|
|
assert_eq!(diff.sign, Negative);
|
|
|
|
assert_eq!(diff.inner[0], 8usize);
|
2020-03-11 10:52:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sub_borrow() {
|
|
|
|
let a = BigInt {
|
|
|
|
inner: vec![0, 1],
|
2020-03-13 14:17:25 -04:00
|
|
|
sign: Positive,
|
2020-03-11 10:52:49 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let b = BigInt::from(2);
|
|
|
|
let diff = a - b;
|
|
|
|
assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone());
|
2020-03-13 14:17:25 -04:00
|
|
|
assert_eq!(diff.inner[0], core::usize::MAX - 1);
|
2020-03-11 13:58:56 -04:00
|
|
|
}
|
2020-03-11 11:16:40 -04:00
|
|
|
|
2020-03-11 13:58:56 -04:00
|
|
|
#[test]
|
|
|
|
fn test_sub_assign() {
|
|
|
|
let mut a = BigInt {
|
2020-03-13 14:17:25 -04:00
|
|
|
inner: vec![1, 0, 1],
|
|
|
|
sign: Positive,
|
2020-03-11 11:16:40 -04:00
|
|
|
};
|
|
|
|
let b = BigInt::from(2);
|
2020-03-11 13:58:56 -04:00
|
|
|
|
|
|
|
a -= b;
|
|
|
|
|
2020-03-13 14:17:25 -04:00
|
|
|
assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]);
|
2020-03-10 20:46:51 -04:00
|
|
|
}
|
|
|
|
|
2020-03-13 16:31:37 -04:00
|
|
|
#[test]
|
|
|
|
fn test_mul() {
|
|
|
|
let a = BigInt::from(65536);
|
|
|
|
let b = BigInt::from(4);
|
|
|
|
|
|
|
|
let product = a * b;
|
|
|
|
assert_eq!(product.inner[0], 65536usize * 4);
|
|
|
|
}
|
|
|
|
|
2020-04-02 17:01:55 -04:00
|
|
|
#[test]
|
|
|
|
fn test_mul_signs() {
|
|
|
|
let a = BigInt::from(2);
|
|
|
|
let b = BigInt::from(-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 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 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 product = a * b;
|
|
|
|
assert_eq!(product.inner[0], 4usize);
|
|
|
|
assert_eq!(product.sign, Positive);
|
|
|
|
}
|
|
|
|
|
2020-03-13 16:31:37 -04:00
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_mul_overflow() {
|
|
|
|
let a = BigInt::from(core::usize::MAX);
|
|
|
|
let b = BigInt::from(5);
|
|
|
|
|
|
|
|
let product = a * b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_mul_assign_overflow() {
|
|
|
|
let mut a = BigInt::from(core::usize::MAX);
|
|
|
|
let b = BigInt::from(5);
|
|
|
|
|
|
|
|
a *= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_div() {
|
|
|
|
let a = BigInt::from(128);
|
|
|
|
let b = BigInt::from(32);
|
|
|
|
|
|
|
|
let quotient = a / b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_div_assign() {
|
|
|
|
let mut a = BigInt::from(128);
|
|
|
|
let b = BigInt::from(32);
|
|
|
|
|
|
|
|
a /= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_rem() {
|
|
|
|
let a = BigInt::from(5);
|
|
|
|
let b = BigInt::from(2);
|
|
|
|
|
|
|
|
let rem = a % b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_rem_assign() {
|
|
|
|
let mut a = BigInt::from(5);
|
|
|
|
let b = BigInt::from(2);
|
|
|
|
|
|
|
|
a %= b;
|
|
|
|
}
|
|
|
|
|
2020-03-11 13:58:56 -04:00
|
|
|
#[test]
|
|
|
|
fn test_zeros() {
|
|
|
|
let a = BigInt::new();
|
|
|
|
let b = BigInt::new();
|
|
|
|
|
2020-03-11 14:01:45 -04:00
|
|
|
let c = a.clone() - b.clone();
|
|
|
|
assert_eq!(a.clone(), b.clone());
|
|
|
|
assert_eq!(c, a.clone());
|
2020-03-11 13:58:56 -04:00
|
|
|
|
|
|
|
let c = a.clone() + b.clone();
|
|
|
|
assert_eq!(a.clone(), b.clone());
|
|
|
|
assert_eq!(c, a.clone());
|
|
|
|
}
|
|
|
|
|
2020-03-05 16:24:33 -05:00
|
|
|
#[test]
|
|
|
|
fn test_not() {
|
|
|
|
let a = BigInt::from(0u8);
|
|
|
|
let b = !a;
|
|
|
|
|
|
|
|
assert_eq!(b.inner[0], core::usize::MAX);
|
2020-03-04 16:16:28 -05:00
|
|
|
}
|
|
|
|
|
2020-05-05 15:41:27 -04:00
|
|
|
#[test]
|
|
|
|
fn test_partial_eq() {
|
|
|
|
let a = 12345u16;
|
|
|
|
let b = BigInt::from(a);
|
|
|
|
|
|
|
|
assert!(a.eq(&b));
|
|
|
|
assert!(b.eq(&a));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_partial_ord() {
|
|
|
|
let a = 12345u32;
|
|
|
|
let b = BigInt::from(a);
|
|
|
|
let c = 3u8;
|
|
|
|
|
|
|
|
assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
|
|
|
|
assert_eq!(c.partial_cmp(&b), Some(Ordering::Less));
|
|
|
|
assert_eq!(b.partial_cmp(&c), Some(Ordering::Greater));
|
|
|
|
|
|
|
|
assert!(big_int!(-32) < big_int!(3));
|
|
|
|
assert!(big_int!(3) > big_int!(-32));
|
|
|
|
assert!(big_int!(152) > big_int!(132));
|
|
|
|
assert_eq!(big_int!(123), big_int!(123));
|
|
|
|
}
|
|
|
|
|
2020-03-05 21:29:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_from() {
|
|
|
|
// Signed numbers
|
|
|
|
assert_eq!(-BigInt::from(2), BigInt::from(-2));
|
|
|
|
|
|
|
|
// Larger than usize
|
|
|
|
assert_eq!(BigInt::from(45u128), BigInt::from(45usize));
|
|
|
|
}
|
2020-03-13 16:31:37 -04:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_large_unsigned() {
|
2020-09-11 15:25:05 -04:00
|
|
|
let big_num: u128 = 9 * RADIX + 8;
|
2020-09-11 15:23:42 -04:00
|
|
|
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);
|
2020-03-13 16:31:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_large_signed() {
|
2020-09-11 15:25:05 -04:00
|
|
|
let big_num: i128 = 2 * I_RADIX + 3;
|
2020-09-11 15:23:42 -04:00
|
|
|
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);
|
2020-03-13 16:31:37 -04:00
|
|
|
}
|
2020-03-13 23:02:27 -04:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
2020-09-24 11:28:13 -04:00
|
|
|
fn test_from_str_large() {
|
|
|
|
let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321";
|
2020-03-13 23:02:27 -04:00
|
|
|
BigInt::from(str);
|
|
|
|
}
|
|
|
|
|
2020-09-24 11:28:13 -04:00
|
|
|
#[test]
|
|
|
|
fn test_from_str_small() {
|
|
|
|
let str = "012345";
|
|
|
|
let num = BigInt::from(str);
|
|
|
|
assert_eq!(num.inner[0], 12345usize);
|
|
|
|
}
|
|
|
|
|
2020-03-13 23:02:27 -04:00
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
2020-09-24 11:28:13 -04:00
|
|
|
fn test_from_string_large() {
|
|
|
|
let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321");
|
2020-03-13 23:02:27 -04:00
|
|
|
BigInt::from(str);
|
|
|
|
}
|
|
|
|
|
2020-09-24 11:28:13 -04:00
|
|
|
#[test]
|
|
|
|
fn test_from_string_small() {
|
|
|
|
let str = String::from("012345");
|
|
|
|
let num = BigInt::from(str);
|
|
|
|
assert_eq!(num.inner[0], 12345usize);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_str_radix_1() {
|
|
|
|
let s = "1".repeat(32);
|
|
|
|
let num = BigInt::from_str_radix(s, 1);
|
|
|
|
assert_eq!(num.inner[0], 32usize);
|
|
|
|
}
|
|
|
|
|
2020-03-13 23:02:27 -04:00
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
2020-09-24 11:28:13 -04:00
|
|
|
fn test_from_str_radix_large() {
|
|
|
|
BigInt::from_str_radix("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321", 36);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_str_radix_small() {
|
|
|
|
let num = BigInt::from_str_radix("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], 0xFEDCBAusize);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_str_radix_lowercase() {
|
|
|
|
let num = BigInt::from_str_radix("fedcba", 16);
|
|
|
|
assert_eq!(num.inner[0], 0xFEDCBAusize);
|
2020-03-13 23:02:27 -04:00
|
|
|
}
|
2020-02-24 16:30:59 -05:00
|
|
|
}
|