diff --git a/.gitignore b/.gitignore index ad67955..9a850e5 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ target # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +.DS_Store diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d610d6a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "rust_big_int" +version = "0.1.0" +dependencies = [ + "num-traits", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0b33848 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust_big_int" +version = "0.1.0" +edition = "2024" + +[dependencies] +num-traits = { version = "0.2.19", features = ["i128"] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9a7579f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Adam Sedláček + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e629a75 --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +# RustBigInt + +BigInt written in Rust. + +## Description + +My own implementation of BigInt (type of integer with unlimited size) as project to learn Rust. + +## Example + +```rs +use RustBigInt::BigInt; +use std::str::FromStr; + +//from +let x: BigInt = 66.into(); +let y: BigInt = BigInt::from(34); +let z: BigInt = BigInt::from_str("999999").unwrap(); + +//tryInto +let x: BigInt = 32.into(); +let x_num: i32 = x.try_into.unwrap(); +assert_eq!(32, x_num); + +let y: BigInt = i16:MAX.into(); +let y_num: i8 = y.try_into(); +assert!(y_num.is_err()); + +//Display +let x: BigInt = BigInt::from(1003); +assert_eq!(format!("Number is: {x}"), "Number is: 1003"); +assert_eq!(format!("Number is: {x:0^11}"), "Number is: 00010030000"); +assert_eq!(format!("Number is: {x:0>10}"), "Number is: 0000001003"); +assert_eq!(format!("Number is: {x:0<10}"), "Number is: 1003000000"); +assert_eq!(format!("Number is: {x:->10}"), "Number is: ------1003"); +assert_eq!(format!("Number is: {x:9}"), "Number is: 1003"); + +//Binary +let x: BigInt = BigInt::from(11); +assert_eq!(format!("{x:#b}"), "0b1011"); +assert_eq!(format!("{x:b}"), "1011"); +assert_eq!(format!("{x:0^11b}"), "00010110000"); + + +//Hexadecimal +let x: BigInt = BigInt::from(11); +assert_eq!(format!("{x:x}"), "a"); +assert_eq!(format!("{x:X}"), "A"); +assert_eq!(format!("{x:#X}"), "0xA"); +assert_eq!(format!("{x:0^11X}"), "00000A00000"); + +let x: BigInt = BigInt::from(20); +assert_eq!(x.to_words(), "two zero"); + +//Math operations +let x: BigInt = BigInt::from(66); +let y: BigInt = BigInt::from(34); +assert!(x != y); +assert_eq!(x + y, 100); +assert_eq!(x - y, 32); +assert_eq!(x * y, 2244); +assert_eq!(x / y, 1); +assert_eq!(x % y, 32); +assert_eq!(x.pow(2), 4356); + +//Binary operations +let x: BigInt = 11; //Ob1011 +let y: BigInt = 6; //Ob0110 +assert_eq!(x & y, 2); //0b0010 +assert_eq!(x | y, 15); //0b1111 +assert_eq!(x ^ y, 13); //0b1101 +assert_eq!(x >> 2, 2) //0b10 +assert_eq!(x << 2, 44) //0b101100 +``` + +## All implemented traits and functions + +
+From and Into traits + +- Default +- New +- FromStr +- From +- TryInto + +
+ +
+ Display traits + +- Display +- Binary +- UpperHex +- LowerHex +- to_words +
+ +
+ Comparing traits + +- PartialEq +- PartialOrd +
+ +
+ Math traits + +- Neg (-) +- Add (+) +- AddAssign(+=) +- Sub (-) +- SubAssign (-=) +- Mul (*) +- MulAssign (*=) +- Div (/) +- DivAssign (/=) +- Rem (%) +- RemAssign (%=) +- Pow +
+ + +
+ Bit operation traits + +- BitAnd (&) +- BitAndAssign (&=) +- BitOr (|) +- BitOrAssign (|=) +- BitXor (^) +- BitXorAssign (^=) +- Shl (<<) +- ShlAssign (<<=) +- Shr (>>) +- ShrAssign (>>=) +
+ + +## Acknowledgments + +Special thanks to [magnusi](https://github.com/luciusmagn) for leading me throughout this project. + +## License + +Project is licensed under the MIT license. See the LICENSE file for more info. + +Adam Sedláček, 2025 (C) \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7973e05 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,1137 @@ +use num_traits::{Pow, ToPrimitive, Zero}; + +use std::cmp::Ordering; +use std::error::Error; +use std::fmt::{self, Alignment, Binary, Display, LowerHex, UpperHex}; +use std::ops::*; +use std::str::FromStr; + +#[derive(Debug)] +pub enum BigIntError { + NaN, + LargeNumber, +} + +impl Error for BigIntError {} + +impl Display for BigIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BigIntError::NaN => write!(f, "Not a Number"), + BigIntError::LargeNumber => write!(f, "Too large"), + } + } +} + +#[derive(Clone, Eq, Debug)] +pub struct BigInt { + positive: bool, + numbers: Vec, +} + +impl Default for BigInt { + fn default() -> Self { + BigInt { + positive: true, + numbers: vec![0], + } + } +} + +impl FromStr for BigInt { + type Err = BigIntError; + fn from_str(string_of_numbers: &str) -> Result { + let original = string_of_numbers; + + //empty string edgecaase + if string_of_numbers.is_empty() { + return Err(BigIntError::NaN); + } + + let mut positive = !(string_of_numbers.starts_with('-')); + let mut numbers: Vec = Vec::new(); + + //if negative - remove '-' + let string_of_numbers = &string_of_numbers[!positive as usize..]; + + for char in string_of_numbers.chars() { + if !char.is_ascii_digit() { + return BigInt::parse_word_digits(if positive { + string_of_numbers + } else { + original + }); + } + + numbers.push(char.to_digit(10).unwrap().to_u8().unwrap()); + } + + if numbers.as_slice() == [0] { + positive = true; + } + + Ok(BigInt { positive, numbers }) + } +} + +macro_rules! from_int { + ($($t:ty),*)=>{ + $( + impl From<$t> for BigInt{ + fn from(mut original_number: $t) -> Self { + + //zero edgecase + if original_number == 0 { + return BigInt::default(); + } + + let mut numbers = Vec::new(); + let positive = !(original_number < 0); + + //negative number + if original_number < 0 { + original_number = -original_number; + } + + //transformation of digits + while original_number != 0{ + numbers.push((original_number % 10).to_u8().unwrap()); + original_number /= 10; + } + + numbers.reverse(); + + //return value + BigInt {positive, numbers} + + } + } + )* + } +} + +macro_rules! from_uint { + ($($t:ty),*)=>{ + $( + impl From<$t> for BigInt{ + fn from(mut original_number: $t) -> Self { + + //zero edgecase + if original_number == 0 { + return BigInt::default(); + } + + let mut numbers = Vec::new(); + + //transformation of digits + while original_number != 0{ + numbers.push((original_number % 10).to_u8().unwrap()); + original_number /= 10; + } + + numbers.reverse(); + + //return value + BigInt { + positive: true, numbers} + + } + } + )* + } +} + +from_int!(i8, i16, i32, i64, i128); +from_uint!(u8, u16, u32, u64, u128); + +macro_rules! try_into_uint { + ($($t:ty),*) => { + $(impl TryInto<$t> for BigInt{ + type Error = BigIntError; + fn try_into(self) -> Result<$t, Self::Error> { + + if self > <$t>::MAX { + return Err(BigIntError::LargeNumber); + } + if self == 0 { + return Ok(0 as $t); + } + + let mut result: $t = 0; + + for (position, number) in self.numbers.iter().rev().enumerate() { + result += BigInt::create_new_digit(position, number) as $t; + } + + Ok(result) + } + })* + + }; +} + +macro_rules! try_into_int { + ($($t:ty),*) => { + $(impl TryInto<$t> for BigInt{ + type Error = BigIntError; + fn try_into(self) -> Result<$t, Self::Error> { + + if self > <$t>::MAX { + return Err(BigIntError::LargeNumber); + } + if self == 0 { + return Ok(0 as $t); + } + + let mut result: $t = 0; + + for (position, number) in self.numbers.iter().rev().enumerate() { + result += BigInt::create_new_digit(position, number) as $t; + } + + if !self.positive { + result *= -1; + } + + + Ok(result) + } + })* + + }; +} + +try_into_uint!(u8, u16, u32, u64, u128); +try_into_int!(i8, i16, i32, i64, i128); + +impl Display for BigInt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut output = String::new(); + + if !self.positive { + output.push('-'); + } + if f.sign_plus() && self.positive { + output.push('+'); + } + + for digit in &self.numbers { + output.push_str(&digit.to_string()); + } + + BigInt::add_alignment(&mut output, f); + + write!(f, "{output}")?; + + Ok(()) + } +} + +impl Binary for BigInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (positive, binary) = self.to_binary(); + let mut output = String::new(); + + if !positive { + output.push('-'); + } + if f.sign_plus() && positive { + output.push('+'); + } + + if f.alternate() { + output.push_str("0b"); + } + + for bit in binary { + if bit { + output.push('1'); + } else { + output.push('0'); + } + } + + BigInt::add_alignment(&mut output, f); + + write!(f, "{output}")?; + + Ok(()) + } +} + +impl UpperHex for BigInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let output = self.create_hexa_string(f, true); + + write!(f, "{output}")?; + + Ok(()) + } +} + +impl LowerHex for BigInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let output = self.create_hexa_string(f, false); + + write!(f, "{output}")?; + + Ok(()) + } +} + +impl PartialEq for BigInt { + fn eq(&self, other: &BigInt) -> bool { + if self.positive != other.positive { + false + } else { + self.numbers == other.numbers + } + } +} + +macro_rules! eq_with_int { + ($($t:ty),*) => { + $( + impl PartialEq<$t> for BigInt{ + fn eq(&self, other: &$t) -> bool { + self == &BigInt::from(*other) + } + } + )* + }; +} + +eq_with_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + +impl PartialEq<&str> for BigInt { + fn eq(&self, other: &&str) -> bool { + match BigInt::from_str(other) { + Ok(right) => self == &right, + Err(_) => false, + } + } +} + +impl Neg for BigInt { + type Output = Self; + fn neg(mut self) -> Self::Output { + if self != 0 { + self.positive = !self.positive; + } + self + } +} + +macro_rules! partial_ord_intieger { + ($($t:ty),*) => { + $( + impl PartialOrd<$t> for BigInt{ + fn partial_cmp(&self, other: &$t) -> Option { + return self.partial_cmp(&BigInt::from(*other)); + } + } + )* + }; +} + +partial_ord_intieger!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + +impl PartialOrd for BigInt { + fn partial_cmp(&self, other: &Self) -> Option { + if self == other { + return Some(Ordering::Equal); + } + + let mut greater = false; + + //check +/- + if self.positive != other.positive { + greater = self.positive; + } + //check length + else if self.numbers.len() != other.numbers.len() { + if self.positive { + greater = self.numbers.len() > other.numbers.len(); + } else { + greater = self.numbers.len() < other.numbers.len(); + } + } + //compare digits + else { + let numbers_iterator = self.numbers.iter().zip(other.numbers.iter()); + + for (left, right) in numbers_iterator { + if left != right { + greater = left > right; + break; + } + } + + if !self.positive { + greater = !greater; + } + } + + //return value + if greater { + Some(Ordering::Greater) + } else { + Some(Ordering::Less) + } + } +} + +impl PartialOrd<&str> for BigInt { + fn partial_cmp(&self, other: &&str) -> Option { + let other = BigInt::from_str(other); + + if other.is_err() { + return None; + } + + self.partial_cmp(&other.unwrap()) + } +} + +macro_rules! assign_trait { + ($trait:ident, $function:ident, $operation:ident) => { + impl $trait for BigInt + where + T: Into, + { + fn $function(&mut self, rhs: T) { + *self = self.clone().$operation(rhs); + } + } + }; +} + +impl Add for BigInt +where + T: Into, +{ + type Output = Self; + fn add(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + // X + 0 edgecase + if self == 0 { + return right; + } + if right == 0 { + return self; + } + + // negative numbers edgecases + if !self.positive && right.positive { + // -X + Y => Y - X => -(X - Y) + //self.positive = true; + return right - (-self); + } else if self.positive && !right.positive { + //X - Y + //right.positive = true; + return self - (-right); + } + + let mut result = BigInt { + positive: self.positive, + numbers: vec![], + }; + + let (longer, shorter) = BigInt::equalize_vectors_length(self.numbers, right.numbers); + + let numbers_set = longer.iter().zip(shorter.iter()); + + let mut new_number; + let mut carry: u8 = 0; + + for number_set in numbers_set { + new_number = 0; + + new_number += number_set.0; + new_number += number_set.1; + new_number += carry; + + let new_digit = new_number % 10; + carry = new_number / 10; + + result.numbers.push(new_digit); + } + + if carry != 0 { + result.numbers.push(carry); + } + + result.numbers.reverse(); + + result + } +} + +assign_trait!(AddAssign, add_assign, add); + +impl Sub for BigInt +where + T: Into, +{ + type Output = Self; + + fn sub(mut self, rhs: T) -> Self::Output { + let mut right: BigInt = rhs.into(); + + // 0 - X edgecase + if self == 0 { + return -right; + } + if right == 0 { + return self; + } + if right == self { + return 0.into(); + } + + // negative numbers edgecases + if !self.positive && right.positive { + // -X - Y => -(X+Y) + self.positive = true; + return -(self + right); + } else if self.positive && !right.positive { + //X - (-Y) + right.positive = true; + return self + right; + } else if !self.positive && !right.positive { + // -X - (-Y) => -X + Y => Y - X + self.positive = true; + right.positive = true; + return right - self; + } + + if self < right { + return -(right - self); + } + + let mut result: BigInt = BigInt { + positive: self >= right, + numbers: vec![], + }; + + self.numbers.reverse(); + right.numbers.reverse(); + + if self.numbers.len() >= right.numbers.len() { + right + .numbers + .extend(vec![0; self.numbers.len() - right.numbers.len()]); + } else { + self.numbers + .extend(vec![0; right.numbers.len() - self.numbers.len()]); + } + + let numbers_set = self.numbers.iter().zip(right.numbers.iter()); + + let mut new_number: i8; + let mut carry = 0; + + for number_set in numbers_set { + new_number = 0; + + new_number += *number_set.0 as i8; + new_number -= *number_set.1 as i8; + new_number -= carry; + + if new_number < 0 { + new_number += 10; + carry = 1; + } else { + carry = 0; + } + + result.numbers.push(new_number as u8); + } + + result.numbers.reverse(); + + while result.numbers.first().unwrap_or(&1).is_zero() { + result.numbers.remove(0); + } + + result + } +} + +assign_trait!(SubAssign, sub_assign, sub); + +impl Mul for BigInt +where + T: Into, +{ + type Output = Self; + fn mul(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + //X * 0 edgecase + if self == 0 || right == 0 { + return BigInt::default(); + } + + if self == 1 { + return right; + } + if right == 1 { + return self; + } + + if self == -1 { + return -right; + } + if right == -1 { + return -self; + } + + let mut result = BigInt::default(); + let mut sub_total; + let mut new_digit; + let mut carry; + + for (position, &left) in self.numbers.iter().rev().enumerate() { + // *0 edgecase + if left == 0 { + continue; + } + + sub_total = BigInt { + positive: true, + numbers: vec![], + }; + + carry = 0; + + //right digit loop + for &right in right.numbers.iter().rev() { + new_digit = left * right; + new_digit += carry; + sub_total.numbers.push(new_digit % 10); + carry = new_digit / 10; + } + + if !carry.is_zero() { + sub_total.numbers.push(carry); + } + + sub_total.numbers.reverse(); + + //zero offset + sub_total.numbers.extend(vec![0; position]); + + result += sub_total; + } + + result.positive = self.positive == right.positive; + result + } +} + +assign_trait!(MulAssign, mul_assign, mul); + +impl Div for BigInt +where + T: Into, +{ + type Output = Self; + fn div(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + if right == 0 { + panic!("division by zero!"); + } + if self == 0 { + return BigInt::default(); + } + if right == 1 { + return self; + } + if self == 1 { + if right == 1 { + return 1.into(); + } + return BigInt::default(); + } + + BigInt::divide_with_remainder(self, right).0 + } +} + +assign_trait!(DivAssign, div_assign, div); + +impl Rem for BigInt +where + T: Into, +{ + type Output = Self; + fn rem(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + if right == 0 { + panic!("division by zero!"); + } + if self == 0 || right == 1 { + return 0.into(); + } + + BigInt::divide_with_remainder(self, right).1 + } +} + +assign_trait!(RemAssign, rem_assign, rem); + +impl Pow for BigInt +where + T: Into, +{ + type Output = Self; + + fn pow(self, rhs: T) -> Self::Output { + let mut right: BigInt = rhs.into(); + + if self == 0 || self == 1 || right == 1 { + return self; + } + if right == 0 { + return 1.into(); + } + if !right.positive { + if self == 1 { + return 1.into(); + } + return 0.into(); + } + + let mut result: BigInt = 1.into(); + + while right != 0 { + result *= self.clone(); + + right -= 1; + } + + result + } +} + +impl BitAnd for BigInt +where + T: Into, +{ + type Output = Self; + fn bitand(self, rhs: T) -> Self::Output { + BigInt::binary_operation(self, rhs, |left, right| left & right) + } +} + +assign_trait!(BitAndAssign, bitand_assign, bitand); + +impl BitOr for BigInt +where + T: Into, +{ + type Output = Self; + fn bitor(self, rhs: T) -> Self::Output { + BigInt::binary_operation(self, rhs, |left, right| left | right) + } +} + +assign_trait!(BitOrAssign, bitor_assign, bitor); + +impl BitXor for BigInt +where + T: Into, +{ + type Output = Self; + fn bitxor(self, rhs: T) -> Self::Output { + BigInt::binary_operation(self, rhs, |left, right| left ^ right) + } +} + +assign_trait!(BitXorAssign, bitxor_assign, bitxor); + +impl Shl for BigInt +where + T: Into, +{ + type Output = Self; + fn shl(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + if right == 0 { + return self; + } + + let base: BigInt = 2.into(); + + self * base.pow(right) + } +} + +assign_trait!(ShlAssign, shl_assign, shl); + +impl Shr for BigInt +where + T: Into, +{ + type Output = Self; + fn shr(self, rhs: T) -> Self::Output { + let right: BigInt = rhs.into(); + + if right == 0 { + return self; + } + + let base: BigInt = 2.into(); + + self / base.pow(right) + } +} + +assign_trait!(ShrAssign, shr_assign, shr); + +impl BigInt { + pub fn new() -> BigInt { + BigInt::default() + } + + pub fn to_words(&self) -> String { + let prefix = if self.positive { vec![] } else { vec!["minus"] }; + + prefix + .into_iter() + .chain( + self.numbers + .iter() + .map(|&number| BigInt::number_to_word(number)), + ) + .collect::>() + .join(" ") + } + + fn word_to_number(word: &str) -> Result { + match word { + "zero" => Ok(0), + "one" => Ok(1), + "two" => Ok(2), + "three" => Ok(3), + "four" => Ok(4), + "five" => Ok(5), + "six" => Ok(6), + "seven" => Ok(7), + "eight" => Ok(8), + "nine" => Ok(9), + _ => Err(BigIntError::NaN), + } + } + + fn number_to_word(number: u8) -> &'static str { + match number { + 0 => "zero", + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four", + 5 => "five", + 6 => "six", + 7 => "seven", + 8 => "eight", + 9 => "nine", + _ => unreachable!(), + } + } + + fn parse_word_digits(string_of_numbers: &str) -> Result { + let mut parsed: Vec = string_of_numbers + .split_whitespace() + .map(str::to_lowercase) + .collect(); + + let positive; + + if matches!(parsed.first().map(String::as_str), Some("-" | "minus")) { + positive = false; + parsed.remove(0); + } else { + positive = true; + } + + let numbers: Result, _> = parsed + .iter() + .map(String::as_str) + .map(BigInt::word_to_number) + .collect(); + let numbers = numbers?; + + //additional check + if numbers.is_empty() { + return Err(BigIntError::NaN); + } + + Ok(BigInt { positive, numbers }) + } + + fn is_even(&self) -> bool { + (*self.numbers.last().unwrap() % 2).is_zero() + } + + fn to_binary(&self) -> (bool, Vec) { + if *self == 0 { + return (true, vec![false]); + } + + let mut final_vec = vec![]; + + let mut number = self.clone(); + + let positive = number.positive; + number.positive = true; + + while number != 0 { + if number.is_even() { + final_vec.push(false); + } else { + final_vec.push(true); + } + number /= 2; + } + + final_vec.reverse(); + + (positive, final_vec) + } + + fn from_binary(positive: bool, binary: Vec) -> BigInt { + if binary.is_empty() { + return BigInt::default(); + } + + let mut result = BigInt::default(); + + for (position, bit) in binary.iter().rev().enumerate() { + if *bit { + result += 2.pow(position); + } + } + + result.positive = positive; + + result + } + + fn number_to_hexa(number: BigInt) -> char { + let number: u8 = number.try_into().unwrap_or(0); + + match number { + 0 => '0', + 1 => '1', + 2 => '2', + 3 => '3', + 4 => '4', + 5 => '5', + 6 => '6', + 7 => '7', + 8 => '8', + 9 => '9', + 10 => 'A', + 11 => 'B', + 12 => 'C', + 13 => 'D', + 14 => 'E', + 15 => 'F', + _ => unreachable!(), + } + } + + fn to_hexa_vec(&self) -> Vec { + let mut final_vec = vec![]; + let mut number = self.clone(); + + number.positive = true; + + while number > 0 { + let divided = BigInt::divide_with_remainder(number, 16.into()); + final_vec.push(BigInt::number_to_hexa(divided.1)); + number = divided.0; + } + + final_vec.reverse(); + + final_vec + } + + fn create_hexa_string(&self, f: &mut fmt::Formatter<'_>, uppercase: bool) -> String { + let hexa = self.to_hexa_vec(); + let mut output = String::new(); + + if !self.positive { + output.push('-'); + } + if f.sign_plus() && self.positive { + output.push('+'); + } + + if f.alternate() { + output.push_str("0x"); + } + + for hex in hexa { + output.push(if uppercase { + hex.to_ascii_uppercase() + } else { + hex.to_ascii_lowercase() + }) + } + + BigInt::add_alignment(&mut output, f); + + output + } + + fn equalize_vectors_length(left: Vec, right: Vec) -> (Vec, Vec) { + let (mut longer, mut shorter) = { + if left.len() > right.len() { + (left, right) + } else { + (right, left) + } + }; + + longer.reverse(); + shorter.reverse(); + + shorter.extend(vec![0; longer.len() - shorter.len()]); + + (shorter, longer) + } + + fn binary_operation(self, rhs: T, bit_operation: F) -> BigInt + where + F: Fn(bool, bool) -> bool, + T: Into, + { + let right: BigInt = rhs.into(); + + let (left_positive, mut left) = self.to_binary(); + let (right_positive, mut right) = right.to_binary(); + + left.reverse(); + right.reverse(); + + let (longer, mut shorter) = if left.len() > right.len() { + (left, right) + } else { + (right, left) + }; + + shorter.extend(vec![false; longer.len() - shorter.len()]); + + let binary_set = longer.iter().zip(shorter.iter()); + + let result: Vec = binary_set + .rev() + .map(|(left, right)| bit_operation(*left, *right)) + .collect(); + + BigInt::from_binary(bit_operation(left_positive, right_positive), result) + } + + fn divide_with_remainder(mut left: BigInt, mut right: BigInt) -> (BigInt, BigInt) { + let mut result = BigInt { + positive: left.positive == right.positive, + numbers: vec![], + }; + + let mut partial_sum = BigInt { + positive: true, + numbers: vec![], + }; + + left.positive = true; + right.positive = true; + + let mut new_digit; + + for digit in left.numbers.iter() { + partial_sum.numbers.push(*digit); + new_digit = 0; + + while partial_sum >= right { + partial_sum -= right.clone(); + new_digit += 1; + } + + result.numbers.push(new_digit); + + if partial_sum.numbers == vec![0] { + partial_sum.numbers.clear(); + } + } + + while result.numbers.first().unwrap_or(&1).is_zero() { + result.numbers.remove(0); + } + + if result.numbers.is_empty() { + return (BigInt::default(), partial_sum); + } + + if partial_sum.numbers.is_empty() { + partial_sum = BigInt::default(); + } + + partial_sum.positive = result.positive; + + (result, partial_sum) + } + + fn add_alignment(output: &mut String, f: &mut fmt::Formatter<'_>) { + let alignment = (f.width().unwrap_or(output.len()) - output.len()) as i32; + + if alignment > 0 { + match f.align() { + Some(Alignment::Left) => { + output.push_str(f.fill().to_string().repeat(alignment as usize).as_str()) + } + Some(Alignment::Center) => { + output.insert_str( + 0, + f.fill() + .to_string() + .repeat((alignment / 2) as usize) + .as_str(), + ); + output.push_str( + f.fill() + .to_string() + .repeat((alignment / 2 + (alignment % 2)) as usize) + .as_str(), + ); + } + Some(Alignment::Right) => { + output.insert_str(0, f.fill().to_string().repeat(alignment as usize).as_str()) + } + _ => output.insert_str(0, f.fill().to_string().repeat(alignment as usize).as_str()), + } + } + } + + fn create_new_digit(position: usize, number: &u8) -> u64 { + let number = *number as u64; + + if number == 0 { + return match position { + 0 => 0, + _ => 10.pow(position), + } as u64; + } + number * 10_u64.pow(position as u32) + } +} + +#[cfg(test)] +mod tests; diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..67a2914 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,1148 @@ +use std::str::FromStr; + +use num_traits::Pow; + +use crate::BigInt; +use crate::BigIntError; + +#[test] +fn default() { + let def = BigInt::default(); + assert!(def.positive); + assert_eq!(def.numbers, [0].to_vec()); +} + +#[test] +fn new() { + let new = BigInt::new(); + assert!(new.positive); + assert_eq!(new.numbers, [0].to_vec()); +} + +#[test] +fn from() { + let x = BigInt::from(20); + assert!(x.positive); + assert_eq!(x.numbers, [2, 0].to_vec()); + let x = BigInt::from(-20); + assert!(!x.positive); + assert_eq!(x.numbers, [2, 0].to_vec()); + let x = BigInt::from(-320020000981234567890_i128); + assert!(!x.positive); + assert_eq!( + x.numbers, + [3, 2, 0, 0, 2, 0, 0, 0, 0, 9, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0].to_vec() + ); + let x = BigInt::from(0); + assert!(x.positive); + assert_eq!(x.numbers, [0].to_vec()); + let x = BigInt::from(-0); + assert!(x.positive); + assert_eq!(x.numbers, [0].to_vec()); +} + +#[test] +fn from_string_numbers() { + let x = BigInt::from_str("20").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [2, 0].to_vec()); + let x = BigInt::from_str("666").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [6, 6, 6].to_vec()); + let x = BigInt::from_str("-20").unwrap(); + assert!(!x.positive); + assert_eq!(x.numbers, [2, 0].to_vec()); + let x = BigInt::from_str("-320020000981234567890").unwrap(); + assert!(!x.positive); + assert_eq!( + x.numbers, + [3, 2, 0, 0, 2, 0, 0, 0, 0, 9, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0].to_vec() + ); + let x = BigInt::from_str("-0").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [0].to_vec()); + let x = BigInt::from_str("0sw"); + assert!(x.is_err()); + let x = BigInt::from_str("0 2020000"); + assert!(x.is_err()); + let x = BigInt::from_str("--200"); + assert!(x.is_err()); + let x = BigInt::from_str("+2000303"); + assert!(x.is_err()); + let x = BigInt::from_str("minus20003002"); + assert!(x.is_err()); +} + +#[test] +fn from_string_words_from_str_digits() { + let x = BigInt::from_str("two zero ").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [2, 0].to_vec()); + let x = BigInt::from_str("minus two four").unwrap(); + assert!(!x.positive); + assert_eq!(x.numbers, [2, 4].to_vec()); + let x = BigInt::from_str("two five five zero zero two one").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [2, 5, 5, 0, 0, 2, 1].to_vec()); + let x = BigInt::from_str("minus two zero zero zero zero zero one").unwrap(); + assert!(!x.positive); + assert_eq!(x.numbers, [2, 0, 0, 0, 0, 0, 1].to_vec()); + let x = BigInt::from_str("zero").unwrap(); + assert!(x.positive); + assert_eq!(x.numbers, [0].to_vec()); + let x = BigInt::from_str("onse"); + assert!(x.is_err()); + let x = BigInt::from_str(" "); + assert!(x.is_err()); + let x = BigInt::from_str("twenty thousand thousand"); + assert!(x.is_err()); + let x: Result = BigInt::from_str("twenty thousand hundred"); + assert!(x.is_err()); + let x = BigInt::from_str("- five four").unwrap(); + assert!(!x.positive); + assert_eq!(x.numbers, [5, 4].to_vec()); +} + +#[test] +fn try_into() { + let x = BigInt::from(666); + assert_eq!(666_i128, x.try_into().unwrap()); + let x = BigInt::from(666); + assert_eq!(666_u128, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(-123_i128, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(123_u128, x.try_into().unwrap()); + let x = BigInt::from(0); + assert_eq!(0_i128, x.try_into().unwrap()); + let x = BigInt::from(0); + assert_eq!(0_u128, x.try_into().unwrap()); + let x = BigInt::from(10); + assert_eq!(10_i128, x.try_into().unwrap()); + let x = BigInt::from(10); + assert_eq!(10_u128, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(-123_i8, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(123_u8, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(-123_i16, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(123_u32, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(-123_i64, x.try_into().unwrap()); + let x = BigInt::from(-123); + assert_eq!(123_u64, x.try_into().unwrap()); +} + +#[test] +#[should_panic] +fn try_into_panic_i128() { + let x = BigInt::from_str("999999999999999999999999999999999999999999999999999999999").unwrap(); + assert_eq!(666_i128, x.try_into().unwrap()); +} + +#[test] +#[should_panic] +fn try_into_panic_u128() { + let x = BigInt::from_str("999999999999999999999999999999999999999999999999999999999").unwrap(); + assert_eq!(666_u128, x.try_into().unwrap()); +} + +#[test] +fn display() { + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:0^10}"), "Number is: 0001003000"); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:0^11}"), "Number is: 00010030000"); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:0>10}"), "Number is: 0000001003"); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:0<10}"), "Number is: 1003000000"); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x}"), "Number is: 1003"); + let x = BigInt::from(0); + assert_eq!(format!("Number is: {x}"), "Number is: 0"); + let x = BigInt::from(-100); + assert_eq!(format!("Number is: {x}"), "Number is: -100"); + let x = BigInt::from(-0); + assert_eq!(format!("Number is: {x}"), "Number is: 0"); + let x = BigInt::from(-1); + assert_eq!(format!("Number is: {x}"), "Number is: -1"); + let x = BigInt::from(320020000981234567890_i128); + assert_eq!( + format!("Number is: {x}"), + "Number is: 320020000981234567890" + ); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:->10}"), "Number is: ------1003"); + let x = BigInt::from(1003); + assert_eq!(format!("Number is: {x:9}"), "Number is: 1003"); + let x = BigInt::from(0); + assert_eq!(format!("Number is: {x:2}"), "Number is: 0"); + let x = BigInt::from(-100); + assert_eq!(format!("Number is: {x}"), "Number is: -100"); + let x = BigInt::from(-0); + assert_eq!(format!("Number is: {x}"), "Number is: 0"); + let x = BigInt::from(-100); + assert_eq!(format!("Number is: {x:X>5}"), "Number is: X-100"); + let x = BigInt::from(-0); + assert_eq!(format!("Number is: {x:+}"), "Number is: +0"); +} + +#[test] +fn to_words() { + let x = BigInt::from(20); + assert_eq!(x.to_words(), "two zero"); + let x = BigInt::from(-24); + assert_eq!(x.to_words(), "minus two four"); + let x = BigInt::from(2550021); + assert_eq!(x.to_words(), "two five five zero zero two one"); + let x = BigInt::from(-2000000000001_i128); + assert_eq!( + x.to_words(), + "minus two zero zero zero zero zero zero zero zero zero zero zero one" + ); +} + +#[test] +fn not() { + let mut x = BigInt::from(1); + assert!(x.positive); + assert_eq!(x.to_string(), "1"); + x = -x; + assert!(!x.positive); + assert_eq!(x.to_string(), "-1"); + x = -x; + assert!(x.positive); + assert_eq!(x.to_string(), "1"); + x = BigInt::from(-22); + assert!(!x.positive); + assert_eq!(x.to_string(), "-22"); + x = -x; + assert!(x.positive); + assert_eq!(x.to_string(), "22"); +} + +#[test] +fn equal() { + let x = BigInt::from(10); + let y = BigInt::from(10); + assert!(x == y); + let x = BigInt::from(101010); + let y = BigInt::from(101010); + assert!(x == y); + let x = BigInt::from(101010); + let y = BigInt::from(101210); + assert!(!(x == y)); + let x = BigInt::from(101010); + let y = BigInt::from(1); + assert!(!(x == y)); + let x = BigInt::from(0); + let y = BigInt::from(0); + assert!(x == y); + let x = BigInt::from(10); + let y = BigInt::from(-10); + assert!(x != y); + let x = BigInt::from(11); + let y = BigInt::from(10); + assert!(x != y); + let x = BigInt::from(-0); + let y = BigInt::from(0); + assert!(x == y); +} + +#[test] +fn equal_int() { + let x = BigInt::from(10); + assert!(x == 10); + let x = BigInt::from(101010); + assert!(x == 101010); + let x = BigInt::from(101010); + assert!(!(x == 101210)); + let x = BigInt::from(101010); + assert!(!(x == 1)); + let x = BigInt::from(0); + assert!(x == 0); + let x = BigInt::from(10); + assert!(x != -10); + let x = BigInt::from(11); + assert!(x != 10); + let x = BigInt::from(-0); + assert!(x == 0); +} + +#[test] +fn equal_str() { + let x = BigInt::from(10); + assert!(x == "10"); + let x = BigInt::from(101010); + assert!(x == "101010"); + let x = BigInt::from(101010); + assert!(!(x == "101210")); + let x = BigInt::from(101010); + assert!(!(x == "1")); + let x = BigInt::from(0); + assert!(x == "0"); + let x = BigInt::from(10); + assert!(x != "-10"); + let x = BigInt::from(11); + assert!(x != "10"); + let x = BigInt::from(-0); + assert!(x == "0"); +} + +#[test] +fn greater() { + let x: BigInt = BigInt::from(15); + let y = BigInt::from(10); + assert!(x > y); + let x: BigInt = BigInt::from(8); + let y = BigInt::from(7); + assert!(x > y); + let x = BigInt::from(10); + let y = BigInt::from(10); + assert!(x <= y); + let x = BigInt::from(10); + let y = BigInt::from(10); + assert!(x >= y); + let x = BigInt::from(101010); + let y = BigInt::from(101010); + assert!(x >= y); + let x = BigInt::from(0); + let y = BigInt::from(0); + assert!(x >= y); + let x = BigInt::from(10); + let y = BigInt::from(-10); + assert!(x > y); + let x = BigInt::from(11); + let y = BigInt::from(10); + assert!(x > y); +} + +#[test] +fn lesser() { + let x: BigInt = BigInt::from(0); + let y = BigInt::from(10); + assert!(x < y); + let x: BigInt = BigInt::from(8); + let y = BigInt::from(9); + assert!(x < y); + let x = BigInt::from(10); + let y = BigInt::from(10); + assert!(x >= y); + let x = BigInt::from(10); + let y = BigInt::from(10); + assert!(x <= y); + let x = BigInt::from(99999999999_i64); + let y = BigInt::from(99999999999_i128); + assert!(x <= y); + let x = BigInt::from(0); + let y = BigInt::from(0); + assert!(x <= y); + let x = BigInt::from(-10); + let y = BigInt::from(10); + assert!(x < y); + let x = BigInt::from(11); + let y = BigInt::from(99999999999_u64); + assert!(x < y); + let x = BigInt::from(10000010); + let y = BigInt::from(20000000); + assert!(x < y); +} + +#[test] +fn add() { + let mut x: BigInt = BigInt::from(1000); + let y = BigInt::from(10); + let z = x.clone() + y.clone(); + x += y; + assert_eq!(z, 1010); + assert_eq!(x, z); + + let mut x: BigInt = BigInt::from(10); + let y = BigInt::from(10); + let z = x.clone() + y.clone(); + x += y; + assert_eq!(z, 20); + assert_eq!(x, z); + + let mut x = BigInt::from(101010); + let y = BigInt::from(101010); + let z = x.clone() + y.clone(); + x += y; + assert_eq!(z, 202020); + assert_eq!(x, z); + + let mut x = BigInt::from(0); + let y = BigInt::from(0); + let z = x.clone() + y.clone(); + x += y; + assert_eq!(z, 0); + assert_eq!(x, z); + + let mut x = BigInt::from(10); + let y = BigInt::from(-10); + let z = x.clone() + y.clone(); + x += y.clone(); + assert_eq!(z, 0); + assert_ne!(x, y); + + let mut x = BigInt::from(11); + let y = BigInt::from(10); + let z = x.clone() + y.clone(); + x += y.clone(); + assert_eq!(z, 21); + assert_ne!(x, y); + + let mut x = BigInt::from(-0); + let y = BigInt::from(0); + let z = x.clone() + y.clone(); + x += y.clone(); + assert_eq!(z, 0); + assert_eq!(x, z); + + let mut x = BigInt::from(6); + let y = BigInt::from(4); + let z = x.clone() + y.clone(); + x += y.clone(); + assert_eq!(z, 10); + assert_eq!(x, z); + + let mut x = BigInt::from(-15); + let y = BigInt::from(-4); + let z = x.clone() + y.clone(); + x += y.clone(); + assert_eq!(z, -19); + assert_eq!(x, z); +} + +#[test] +fn sub() { + let mut x: BigInt = BigInt::from(10); + let y = BigInt::from(10); + let z = x.clone() - y.clone(); + x -= y; + assert_eq!(z, 0); + assert_eq!(x, z); + + let mut x = BigInt::from(101010); + let y = BigInt::from(10); + let z = x.clone() - y.clone(); + x -= y; + assert_eq!(z, 101000); + assert_eq!(x, z); + + let mut x = BigInt::from(0); + let y = BigInt::from(0); + let z = x.clone() - y.clone(); + x -= y; + assert_eq!(z, 0); + assert_eq!(x, z); + + let mut x = BigInt::from(10); + let y = BigInt::from(-10); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, 20); + assert_ne!(x, y); + + let mut x = BigInt::from(-10); + let y = BigInt::from(10); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, -20); + assert_ne!(x, y); + + let mut x = BigInt::from(11); + let y = BigInt::from(10); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, 1); + assert_ne!(x, y); + + let mut x = BigInt::from(-0); + let y = BigInt::from(0); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, 0); + assert_eq!(x, z); + + let mut x = BigInt::from(6); + let y = BigInt::from(4); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, 2); + assert_eq!(x, z); + + let mut x = BigInt::from(4); + let y = BigInt::from(15); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, -11); + assert_eq!(x, z); + + let mut x = BigInt::from(-15); + let y = BigInt::from(-4); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, -11); + assert_eq!(x, z); + + let mut x = BigInt::from(987654); + let y = BigInt::from(987653); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, 1); + assert_eq!(x, z); + + let mut x = BigInt::from(1); + let y = BigInt::from(1000); + let z = x.clone() - y.clone(); + x -= y.clone(); + assert_eq!(z, -999); + assert_eq!(x, z); +} + +#[test] +fn mul() { + let mut x: BigInt = BigInt::from(10); + let y = BigInt::from(10); + let z: BigInt = x.clone() * y.clone(); + x *= y; + assert_eq!(z, 100); + assert_eq!(z, x); + + let mut x = BigInt::from(101); + let y = BigInt::from(101); + let z = x.clone() * y.clone(); + x *= y; + assert_eq!(z, 10201); + assert_eq!(z, x); + + let mut x = BigInt::from(0); + let y = BigInt::from(0); + let z: BigInt = x.clone() * y.clone(); + x *= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(20100000100_u64); + let y = BigInt::from(0); + let z: BigInt = x.clone() * y.clone(); + x *= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(10); + let y = BigInt::from(-10); + let z: BigInt = x.clone() * y.clone(); + x *= y.clone(); + assert_eq!(z, -100); + assert_ne!(x, y); + + let mut x = BigInt::from(11); + let y = BigInt::from(10); + let z: BigInt = x.clone() * y.clone(); + x *= y.clone(); + assert_eq!(z, 110); + assert_ne!(x, y); + + let mut x = BigInt::from(-0); + let y = BigInt::from(0); + let z: BigInt = x.clone() * y.clone(); + x *= y.clone(); + assert_eq!(z, 0); + assert_eq!(x, y); + + let mut x = BigInt::from(6); + let y = BigInt::from(4); + let z: BigInt = x.clone() * y.clone(); + x *= y.clone(); + assert_eq!(z, 24); + assert_eq!(x, z); + + let mut x = BigInt::from(-15); + let y = BigInt::from(-4); + let z: BigInt = x.clone() * y.clone(); + x *= y.clone(); + assert_eq!(z, 60); + assert_eq!(x, z); +} + +#[test] +fn div() { + let mut x: BigInt = BigInt::from(10000000); + let y = BigInt::from(10); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 1000000); + assert_eq!(z, x); + + let mut x = BigInt::from(101); + let y = BigInt::from(101); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 1); + assert_eq!(z, x); + + let mut x = BigInt::from(9999_u128); + let y = BigInt::from(2); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 4999_u128); + assert_eq!(z, x); + + let mut x = BigInt::from_str("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999").unwrap(); + let y = BigInt::from(2); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!( + z, + "499999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + ); + assert_eq!(z, x); + + let mut x = BigInt::from(0); + let y = BigInt::from(2); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(1); + let y = BigInt::from(2); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(1); + let y = BigInt::from(1); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 1); + assert_eq!(z, x); + + let mut x = BigInt::from(0); + let y = BigInt::from(666); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(0); + let y = BigInt::from(100); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x = BigInt::from(20100000100_u64); + let y = BigInt::from(20000000); + let z = x.clone() / y.clone(); + x /= y; + assert_eq!(z, 1005); + assert_eq!(z, x); + + let mut x = BigInt::from(10); + let y = BigInt::from(-10); + let z = x.clone() / y.clone(); + x /= y.clone(); + assert_eq!(z, -1); + assert_ne!(x, y); + + let mut x = BigInt::from(110); + let y = BigInt::from(10); + let z = x.clone() / y.clone(); + x /= y.clone(); + assert_eq!(z, 11); + assert_ne!(x, y); + + let mut x = BigInt::from(6); + let y = BigInt::from(2); + let z = x.clone() / y.clone(); + x /= y.clone(); + assert_eq!(z, 3); + assert_eq!(x, z); + + let mut x = BigInt::from(-15); + let y = BigInt::from(-5); + let z = x.clone() / y.clone(); + x /= y.clone(); + assert_eq!(z, 3); + assert_eq!(x, z); +} + +#[test] +#[should_panic] +fn div_by_zero() { + let mut x = BigInt::from(10); + let y = BigInt::from(0); + x /= y; +} + +#[test] +fn remainder() { + let mut x: BigInt = BigInt::from(10000); + let y = BigInt::from(10); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x: BigInt = BigInt::from(10); + let y = BigInt::from(7); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 3); + assert_eq!(z, x); + + let mut x: BigInt = BigInt::from(10000); + let y = BigInt::from(10); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x: BigInt = BigInt::from(-104); + let y = BigInt::from(10); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, -4); + assert_eq!(z, x); + + let mut x: BigInt = BigInt::from(24); + let y = BigInt::from(3); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 0); + assert_eq!(z, x); + + let mut x: BigInt = BigInt::from(33); + let y = BigInt::from(7); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 5); + assert_eq!(z, x); +} + +#[test] +fn power_of() { + let x: BigInt = BigInt::from(2); + let y = BigInt::from(2); + let z = x.pow(y); + assert_eq!(z, 4); + + let x: BigInt = BigInt::from(2); + let y = BigInt::from(1); + let z = x.pow(y); + assert_eq!(z, 2); + + let x: BigInt = BigInt::from(1); + let y = BigInt::from(1000000); + let z = x.pow(y); + assert_eq!(z, 1); + + let x: BigInt = BigInt::from(3); + let y = BigInt::from(3); + let z = x.pow(y); + assert_eq!(z, 27); + + let x: BigInt = BigInt::from(-3); + let y = BigInt::from(3); + let z = x.pow(y); + assert_eq!(z, -27); + + let x: BigInt = BigInt::from(-3); + let y = BigInt::from(2); + let z = x.pow(y); + assert_eq!(z, 9); + + let x: BigInt = BigInt::from(2); + let y = BigInt::from(-1); + let z = x.pow(y); + assert_eq!(z, 0); + + let x: BigInt = BigInt::from(1); + let y = BigInt::from(-10); + let z = x.pow(y); + assert_eq!(z, 1); + + let x: BigInt = BigInt::from(5); + let y = BigInt::from(-10); + let z = x.pow(y); + assert_eq!(z, 0); +} + +#[test] +#[should_panic] +fn rem_of_zero() { + let mut x: BigInt = BigInt::from(10); + let y = BigInt::from(0); + let z = x.clone() % y.clone(); + x %= y; + assert_eq!(z, 0); + assert_eq!(z, x); +} + +#[test] +fn binary() { + let x = BigInt::from(11); + assert_eq!(format!("{x:#10b}"), " 0b1011"); + let x = BigInt::from(4); + assert_eq!(format!("{x:#b}"), "0b100"); + let x = BigInt::from(4); + assert_eq!(format!("{x:b}"), "100"); + let x = BigInt::from(4); + assert_eq!(format!("{x:0>10b}"), "0000000100"); + let x = BigInt::from(10); + assert_eq!(format!("{x:#10b}"), " 0b1010"); + let x = BigInt::from(10); + assert_eq!(format!("{x:x>#010b}"), "xxxx0b1010"); + let x = BigInt::from(172); + assert_eq!(format!("{x:b}"), "10101100"); + let x = BigInt::from(-17220003931_i64); + assert_eq!(format!("{x:#b}"), "-0b10000000010011001000110100001011011"); +} + +#[test] +fn binary_transformation() { + let x: BigInt = BigInt::from(10); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); + + let x: BigInt = BigInt::from(-42); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); + + let x: BigInt = BigInt::from(-0); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); + + let x: BigInt = BigInt::from(0); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); + + let x: BigInt = BigInt::from(-9999); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); + + let x: BigInt = BigInt::from(666); + let (positive, binary) = x.to_binary(); + assert_eq!(x, BigInt::from_binary(positive, binary)); +} + +#[test] +fn bit_and() { + let mut x = BigInt::from(4); //100 + let y = BigInt::from(12); //1100 + let z = x.clone() & y.clone(); //0100 + x &= y; + assert_eq!(x, z); + assert_eq!(z, 4); + + let mut x = BigInt::from(10); //1010 + let y = BigInt::from(13); //1101 + let z = x.clone() & y.clone(); //1000 + x &= y; + assert_eq!(x, z); + assert_eq!(z, 8); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(223); //11011111 + let z = x.clone() & y.clone(); //10001100 + x &= y; + assert_eq!(x, z); + assert_eq!(z, 140); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(1); //1 + let z = x.clone() & y.clone(); //0 + x &= y; + assert_eq!(x, z); + assert_eq!(z, 0); + + let mut x = BigInt::from(173); //10101101 + let y = BigInt::from(1); //1 + let z = x.clone() & y.clone(); //1 + x &= y; + assert_eq!(x, z); + assert_eq!(z, 1); +} + +#[test] +fn bit_or() { + let mut x = BigInt::from(4); //100 + let y = BigInt::from(12); //1100 + let z = x.clone() | y.clone(); //1100 + x |= y; + assert_eq!(x, z); + assert_eq!(z, 12); + + let mut x = BigInt::from(10); //1010 + let y = BigInt::from(13); //1101 + let z = x.clone() | y.clone(); //1111 + x |= y; + assert_eq!(x, z); + assert_eq!(z, 15); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(223); //11011111 + let z = x.clone() | y.clone(); //11111111 + x |= y; + assert_eq!(x, z); + assert_eq!(z, 255); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(1); //1 + let z = x.clone() | y.clone(); //10101101 + x |= y; + assert_eq!(x, z); + assert_eq!(z, 173); + + let mut x = BigInt::from(173); //10101101 + let y = BigInt::from(1); //1 + let z = x.clone() | y.clone(); //10101101 + x |= y; + assert_eq!(x, z); + assert_eq!(z, 173); +} + +#[test] +fn bit_xor() { + let mut x = BigInt::from(4); //100 + let y = BigInt::from(12); //1100 + let z = x.clone() ^ y.clone(); //1000 + x ^= y; + assert_eq!(x, z); + assert_eq!(z, -8); + + let mut x = BigInt::from(10); //1010 + let y = BigInt::from(13); //1101 + let z = x.clone() ^ y.clone(); //0111 + x ^= y; + assert_eq!(x, z); + assert_eq!(z, -7); + + let mut x = BigInt::from(-172); //10101100 + let y = BigInt::from(-223); //11011111 + let z = x.clone() ^ y.clone(); //01110011 + x ^= y; + assert_eq!(x, z); + assert_eq!(z, -115); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(-1); //1 + let z = x.clone() ^ y.clone(); //10101101 + x ^= y; + assert_eq!(x, z); + assert_eq!(z, 173); + + let mut x = BigInt::from(-173); //10101101 + let y = BigInt::from(1); //1 + let z = x.clone() ^ y.clone(); //10101100 + x ^= y; + assert_eq!(x, z); + assert_eq!(z, 172); +} + +#[test] +fn bit_shift_left() { + let mut x = BigInt::from(4); //100 + let y = BigInt::from(2); + let z = x.clone() << y.clone(); //10000 + x <<= y; + assert_eq!(x, z); + assert_eq!(z, 16); + + let mut x = BigInt::from(10); //1010 + let y = BigInt::from(1); + let z = x.clone() << y.clone(); //10100 + x <<= y; + assert_eq!(x, z); + assert_eq!(z, 20); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(0); + let z = x.clone() << y.clone(); + x <<= y; + assert_eq!(x, z); + assert_eq!(z, 172); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(10); + let z = x.clone() << y.clone(); //101011000000000000 + x <<= y; + assert_eq!(x, z); + assert_eq!(z, 176128); + + let mut x = BigInt::from(173); //10101101 + let y = BigInt::from(1); + let z = x.clone() << y.clone(); //101011010 + x <<= y; + assert_eq!(x, z); + assert_eq!(z, 346); +} + +#[test] +fn bit_shift_right() { + let mut x = BigInt::from(4); //100 + let y = BigInt::from(2); + let z = x.clone() >> y.clone(); //1 + x >>= y; + assert_eq!(x, z); + assert_eq!(z, 1); + + let mut x = BigInt::from(10); //1010 + let y = BigInt::from(1); + let z = x.clone() >> y.clone(); //101 + x >>= y; + assert_eq!(x, z); + assert_eq!(z, 5); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(0); + let z = x.clone() >> y.clone(); //10101100 + x >>= y; + assert_eq!(x, z); + assert_eq!(z, 172); + + let mut x = BigInt::from(172); //10101100 + let y = BigInt::from(10); + let z = x.clone() >> y.clone(); //0 + x >>= y; + assert_eq!(x, z); + assert_eq!(z, 0); + + let mut x = BigInt::from(173); //10101101 + let y = BigInt::from(1); + let z = x.clone() >> y.clone(); //1010110 + x >>= y; + assert_eq!(x, z); + assert_eq!(z, 86); +} + +#[test] +fn hexadecimal() { + let x = BigInt::from(4); + assert_eq!(format!("{x:X}"), "4"); + let x = BigInt::from(16); + assert_eq!(format!("{x:#X}"), "0x10"); + let x = BigInt::from(-4); + assert_eq!(format!("{x:X}"), "-4"); + let x = BigInt::from(-16); + assert_eq!(format!("{x:#X}"), "-0x10"); + + let x = BigInt::from(10); + assert_eq!(format!("{x:#X}"), "0xA"); + let x = BigInt::from(172); + assert_eq!(format!("{x:X}"), "AC"); + let x = BigInt::from(17220003931_u128); + assert_eq!(format!("{x:#X}"), "0x40264685B"); + + let x = BigInt::from(4); + assert_eq!(format!("{x:x}"), "4"); + let x = BigInt::from(16); + assert_eq!(format!("{x:#x}"), "0x10"); + let x = BigInt::from(10); + assert_eq!(format!("{x:#x}"), "0xa"); + let x = BigInt::from(172); + assert_eq!(format!("{x:x}"), "ac"); + let x = BigInt::from(17220003931_u128); + assert_eq!(format!("{x:#x}"), "0x40264685b"); + + let x = BigInt::from(11); + assert_eq!(format!("{x:#10X}"), " 0xB"); + let x = BigInt::from(4); + assert_eq!(format!("{x:#x}"), "0x4"); + let x = BigInt::from(4); + assert_eq!(format!("{x:X}"), "4"); + let x = BigInt::from(4); + assert_eq!(format!("{x:0>10x}"), "0000000004"); + let x = BigInt::from(10); + assert_eq!(format!("{x:#10x}"), " 0xa"); + let x = BigInt::from(10); + assert_eq!(format!("{x:x>#010X}"), "xxxxxxx0xA"); + let x = BigInt::from(172); + assert_eq!(format!("{x:X}"), "AC"); + let x = BigInt::from(-17220003931_i64); + assert_eq!(format!("{x:#x}"), "-0x40264685b"); +} + +#[test] +fn progtest_tests() { + let mut a = BigInt::from(10); + a += BigInt::from(20); + assert_eq!(a, 30); + a *= BigInt::from(5); + assert_eq!(a, 150); + let mut b = a.clone() + BigInt::from(3); + assert_eq!(b, 153); + b = a.clone() * BigInt::from(7); + assert_eq!(b, 1050); + assert_eq!(a, 150); + assert_eq!(format!("{a:X}"), "96"); + + a = BigInt::from(10); + a += BigInt::from(-20); + assert_eq!(a, -10); + a *= BigInt::from(5); + assert_eq!(a, -50); + b = a.clone() + BigInt::from(73); + assert_eq!(b, 23); + b = a.clone() * BigInt::from(-7); + assert_eq!(b, 350); + assert_eq!(a, -50); + assert_eq!(format!("{a:X}"), "-32"); + + a = BigInt::from(12345678901234567890_i128); + a += BigInt::from(-99999999999999999999_i128); + assert_eq!(a, -87654321098765432109_i128); + a *= BigInt::from(54321987654321987654_i128); + assert_eq!(a, "-4761556948575111126880627366067073182286"); + a *= BigInt::from(0); + assert_eq!(a, 0); + a = BigInt::from(10); + b = a.clone() + 400; + assert_eq!(b, "410"); + b = a.clone() * BigInt::from_str("15").unwrap_or_default(); + assert_eq!(b, "150"); + assert_eq!(a, "10"); + assert_eq!(format!("{a:X}"), "A"); + + b = BigInt::from_str("1234").unwrap_or_default(); + assert_eq!(format!("{b}"), "1234"); + assert!(BigInt::from_str(" 12 34").is_err()); + assert!(BigInt::from_str("999z").is_err()); + assert!(BigInt::from_str("abcd").is_err()); + assert!(BigInt::from_str("-xyz").is_err()); + assert!(BigInt::from_str(":").is_err()); + assert!(BigInt::from_str("%").is_err()); + assert!(BigInt::from_str("- 758").is_err()); + a = BigInt::from(42); + assert_eq!(a, 42); + + a = BigInt::from(73786976294838206464_i128); + assert_eq!(a, 73786976294838206464_u128); + assert_eq!(format!("{a:X}"), "40000000000000000"); + assert!(a < "1361129467683753853853498429727072845824"); + assert!(a <= "1361129467683753853853498429727072845824"); + assert!(a != "1361129467683753853853498429727072845824"); + assert!(a <= 73786976294838206464_u128); + assert!(a >= 73786976294838206464_u128); + assert!(a == 73786976294838206464_u128); + assert!(!(a != 73786976294838206464_i128)); + assert!(a <= 73786976294838206464_u128); + assert!(a >= 73786976294838206464_u128); + a = BigInt::from_str("2147483648").unwrap_or(BigInt::new()); + assert!(a > -2147483648_i128); + assert!(a >= -2147483648_i128); + assert!(!(a == -2147483648_i128)); + assert!(a != -2147483648_i128); + a = BigInt::from_str("-12345678").unwrap_or(BigInt::new()); + assert!(a > -87654321); + assert!(a >= -87654321); + assert!(!(a == -87654321)); + assert!(a != -87654321); +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs new file mode 100644 index 0000000..242aad0 --- /dev/null +++ b/tests/integration_tests.rs @@ -0,0 +1,129 @@ +use rust_big_int::BigInt; +use std::str::FromStr; + +#[test] +fn catalan_number() { + let mut calculated_numbers: Vec = vec![1.into()]; + + for _i in 1..100 { + let number_pairs = calculated_numbers + .iter() + .zip(calculated_numbers.iter().rev()); + + let result: BigInt = number_pairs.fold(BigInt::default(), |result, (x, y)| { + x.clone() * y.clone() + result + }); + + calculated_numbers.push(result); + } + + let catalan_numbers: Vec = vec![ + BigInt::from_str("1").unwrap(), + BigInt::from_str("1").unwrap(), + BigInt::from_str("2").unwrap(), + BigInt::from_str("5").unwrap(), + BigInt::from_str("14").unwrap(), + BigInt::from_str("42").unwrap(), + BigInt::from_str("132").unwrap(), + BigInt::from_str("429").unwrap(), + BigInt::from_str("1430").unwrap(), + BigInt::from_str("4862").unwrap(), + BigInt::from_str("16796").unwrap(), + BigInt::from_str("58786").unwrap(), + BigInt::from_str("208012").unwrap(), + BigInt::from_str("742900").unwrap(), + BigInt::from_str("2674440").unwrap(), + BigInt::from_str("9694845").unwrap(), + BigInt::from_str("35357670").unwrap(), + BigInt::from_str("129644790").unwrap(), + BigInt::from_str("477638700").unwrap(), + BigInt::from_str("1767263190").unwrap(), + BigInt::from_str("6564120420").unwrap(), + BigInt::from_str("24466267020").unwrap(), + BigInt::from_str("91482563640").unwrap(), + BigInt::from_str("343059613650").unwrap(), + BigInt::from_str("1289904147324").unwrap(), + BigInt::from_str("4861946401452").unwrap(), + BigInt::from_str("18367353072152").unwrap(), + BigInt::from_str("69533550916004").unwrap(), + BigInt::from_str("263747951750360").unwrap(), + BigInt::from_str("1002242216651368").unwrap(), + BigInt::from_str("3814986502092304").unwrap(), + BigInt::from_str("14544636039226909").unwrap(), + BigInt::from_str("55534064877048198").unwrap(), + BigInt::from_str("212336130412243110").unwrap(), + BigInt::from_str("812944042149730764").unwrap(), + BigInt::from_str("3116285494907301262").unwrap(), + BigInt::from_str("11959798385860453492").unwrap(), + BigInt::from_str("45950804324621742364").unwrap(), + BigInt::from_str("176733862787006701400").unwrap(), + BigInt::from_str("680425371729975800390").unwrap(), + BigInt::from_str("2622127042276492108820").unwrap(), + BigInt::from_str("10113918591637898134020").unwrap(), + BigInt::from_str("39044429911904443959240").unwrap(), + BigInt::from_str("150853479205085351660700").unwrap(), + BigInt::from_str("583300119592996693088040").unwrap(), + BigInt::from_str("2257117854077248073253720").unwrap(), + BigInt::from_str("8740328711533173390046320").unwrap(), + BigInt::from_str("33868773757191046886429490").unwrap(), + BigInt::from_str("131327898242169365477991900").unwrap(), + BigInt::from_str("509552245179617138054608572").unwrap(), + BigInt::from_str("1978261657756160653623774456").unwrap(), + BigInt::from_str("7684785670514316385230816156").unwrap(), + BigInt::from_str("29869166945772625950142417512").unwrap(), + BigInt::from_str("116157871455782434250553845880").unwrap(), + BigInt::from_str("451959718027953471447609509424").unwrap(), + BigInt::from_str("1759414616608818870992479875972").unwrap(), + BigInt::from_str("6852456927844873497549658464312").unwrap(), + BigInt::from_str("26700952856774851904245220912664").unwrap(), + BigInt::from_str("104088460289122304033498318812080").unwrap(), + BigInt::from_str("405944995127576985730643443367112").unwrap(), + BigInt::from_str("1583850964596120042686772779038896").unwrap(), + BigInt::from_str("6182127958584855650487080847216336").unwrap(), + BigInt::from_str("24139737743045626825711458546273312").unwrap(), + BigInt::from_str("94295850558771979787935384946380125").unwrap(), + BigInt::from_str("368479169875816659479009042713546950").unwrap(), + BigInt::from_str("1440418573150919668872489894243865350").unwrap(), + BigInt::from_str("5632681584560312734993915705849145100").unwrap(), + BigInt::from_str("22033725021956517463358552614056949950").unwrap(), + BigInt::from_str("86218923998960285726185640663701108500").unwrap(), + BigInt::from_str("337485502510215975556783793455058624700").unwrap(), + BigInt::from_str("1321422108420282270489942177190229544600").unwrap(), + BigInt::from_str("5175569924646105559418940193995065716350").unwrap(), + BigInt::from_str("20276890389709399862928998568254641025700").unwrap(), + BigInt::from_str("79463489365077377841208237632349268884500").unwrap(), + BigInt::from_str("311496878311103321137536291518809134027240").unwrap(), + BigInt::from_str("1221395654430378811828760722007962130791020").unwrap(), + BigInt::from_str("4790408930363303911328386208394864461024520").unwrap(), + BigInt::from_str("18793142726809884575211361279087545193250040").unwrap(), + BigInt::from_str("73745243611532458459690151854647329239335600").unwrap(), + BigInt::from_str("289450081175264899454283846029490767264392230").unwrap(), + BigInt::from_str("1136359577947336271931632877004667456667613940").unwrap(), + BigInt::from_str("4462290049988320482463241297506133183499654740").unwrap(), + BigInt::from_str("17526585015616776834735140517915655636396234280").unwrap(), + BigInt::from_str("68854441132780194707888052034668647142985206100").unwrap(), + BigInt::from_str("270557451039395118028642463289168566420671280440").unwrap(), + BigInt::from_str("1063353702922273835973036658043476458723103404520").unwrap(), + BigInt::from_str("4180080073556524734514695828170907458428751314320").unwrap(), + BigInt::from_str("16435314834665426797069144960762886143367590394940").unwrap(), + BigInt::from_str("64633260585762914370496637486146181462681535261000").unwrap(), + BigInt::from_str("254224158304000796523953440778841647086547372026600").unwrap(), + BigInt::from_str("1000134600800354781929399250536541864362461089950800").unwrap(), + BigInt::from_str("3935312233584004685417853572763349509774031680023800").unwrap(), + BigInt::from_str("15487357822491889407128326963778343232013931127835600").unwrap(), + BigInt::from_str("60960876535340415751462563580829648891969728907438000").unwrap(), + BigInt::from_str("239993345518077005168915776623476723006280827488229600").unwrap(), + BigInt::from_str("944973797977428207852605870454939596837230758234904050").unwrap(), + BigInt::from_str("3721443204405954385563870541379246659709506697378694300").unwrap(), + BigInt::from_str("14657929356129575437016877846657032761712954950899755100").unwrap(), + BigInt::from_str("57743358069601357782187700608042856334020731624756611000").unwrap(), + BigInt::from_str("227508830794229349661819540395688853956041682601541047340").unwrap(), + BigInt::from_str("896519947090131496687170070074100632420837521538745909320").unwrap(), + ]; + + let result_check = calculated_numbers.iter().zip(catalan_numbers.iter()); + + for result in result_check { + assert_eq!(result.0, result.1); + } +}