Split type conversion and comparision trait implementations from main BigInt module
All checks were successful
timw4mail/rusty-numbers/pipeline/head This commit looks good
All checks were successful
timw4mail/rusty-numbers/pipeline/head This commit looks good
This commit is contained in:
parent
1e7588cf52
commit
83c5abb697
@ -5,10 +5,9 @@ authors = ["Timothy J. Warren <tim@timshome.page>"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
alloc = []
|
alloc = []
|
||||||
std = ["alloc"]
|
std = ["alloc"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
13
justfile
13
justfile
@ -13,6 +13,14 @@ clean:
|
|||||||
rm -f cobertura.xml
|
rm -f cobertura.xml
|
||||||
rm -f coverage.html
|
rm -f coverage.html
|
||||||
|
|
||||||
|
# Check code syntax
|
||||||
|
check:
|
||||||
|
cargo check
|
||||||
|
|
||||||
|
# Generate API docs
|
||||||
|
docs:
|
||||||
|
cargo doc
|
||||||
|
|
||||||
# Check code style
|
# Check code style
|
||||||
lint:
|
lint:
|
||||||
cargo clippy
|
cargo clippy
|
||||||
@ -21,6 +29,11 @@ lint:
|
|||||||
fmt:
|
fmt:
|
||||||
cargo +nightly fmt
|
cargo +nightly fmt
|
||||||
|
|
||||||
|
# Automatically fix some code syntax/style issues
|
||||||
|
fix:
|
||||||
|
cargo fix --allow-dirty --allow-staged
|
||||||
|
just fmt
|
||||||
|
|
||||||
# Run the normal tests
|
# Run the normal tests
|
||||||
test:
|
test:
|
||||||
cargo test
|
cargo test
|
||||||
|
196
src/bigint.rs
196
src/bigint.rs
@ -1,4 +1,9 @@
|
|||||||
//! \[WIP\] Arbitrarily large integers
|
//! \[WIP\] Arbitrarily large integers
|
||||||
|
mod compare;
|
||||||
|
mod from;
|
||||||
|
pub use compare::*;
|
||||||
|
pub use from::*;
|
||||||
|
|
||||||
use crate::num::FracOp;
|
use crate::num::FracOp;
|
||||||
use crate::num::Sign::{self, Negative, Positive};
|
use crate::num::Sign::{self, Negative, Positive};
|
||||||
|
|
||||||
@ -26,7 +31,7 @@ pub struct BigInt {
|
|||||||
|
|
||||||
/// Create a [`BigInt`](bigint/struct.BigInt.html) type with signed or unsigned number literals
|
/// Create a [`BigInt`](bigint/struct.BigInt.html) type with signed or unsigned number literals
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! big_int {
|
macro_rules! bint {
|
||||||
($w:literal) => {
|
($w:literal) => {
|
||||||
$crate::bigint::BigInt::new($w)
|
$crate::bigint::BigInt::new($w)
|
||||||
};
|
};
|
||||||
@ -44,27 +49,6 @@ impl Default for BigInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for BigInt {
|
|
||||||
fn from(n: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: vec![n],
|
|
||||||
sign: Sign::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for BigInt {
|
|
||||||
fn from(s: &str) -> Self {
|
|
||||||
Self::from_str(s, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for BigInt {
|
|
||||||
fn from(s: String) -> Self {
|
|
||||||
Self::from_str(&s, 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BigInt {
|
impl BigInt {
|
||||||
/// Create a new Bigint, of value 0
|
/// Create a new Bigint, of value 0
|
||||||
///
|
///
|
||||||
@ -492,155 +476,6 @@ impl PartialOrd for BigInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::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 {
|
|
||||||
let target_radix: $s = (usize::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![rem as usize];
|
|
||||||
|
|
||||||
loop {
|
|
||||||
rem = quotient % target_radix;
|
|
||||||
quotient /= target_radix;
|
|
||||||
|
|
||||||
inner.push(rem as usize);
|
|
||||||
|
|
||||||
if (quotient == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInt {
|
|
||||||
inner,
|
|
||||||
sign,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$u> for BigInt {
|
|
||||||
/// Create a `BigInt` from an unsigned integer primitive
|
|
||||||
fn from(n: $u) -> Self {
|
|
||||||
let target_radix: $u = (usize::MAX as $u) + 1;
|
|
||||||
|
|
||||||
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![rem as usize];
|
|
||||||
|
|
||||||
loop {
|
|
||||||
rem = quotient % target_radix;
|
|
||||||
quotient /= target_radix;
|
|
||||||
|
|
||||||
inner.push(rem as usize);
|
|
||||||
|
|
||||||
if (quotient == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInt {
|
|
||||||
inner,
|
|
||||||
sign: Sign::Positive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_ord_literal {
|
|
||||||
($($prim: ty),+) => {
|
|
||||||
$(
|
|
||||||
impl PartialEq<$prim> for BigInt {
|
|
||||||
#[must_use]
|
|
||||||
fn eq(&self, other: &$prim) -> bool {
|
|
||||||
self == &BigInt::new(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<BigInt> for $prim {
|
|
||||||
#[must_use]
|
|
||||||
fn eq(&self, other: &BigInt) -> bool {
|
|
||||||
&BigInt::new(*self) == other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<$prim> for BigInt {
|
|
||||||
#[must_use]
|
|
||||||
fn partial_cmp(&self, other: &$prim) -> Option<Ordering> {
|
|
||||||
self.partial_cmp(&BigInt::new(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<BigInt> for $prim {
|
|
||||||
#[must_use]
|
|
||||||
fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
|
|
||||||
(&BigInt::new(*self)).partial_cmp(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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));
|
|
||||||
|
|
||||||
// Implement PartialEq and PartialOrd to compare against BigInt values
|
|
||||||
impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -657,11 +492,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_macro() {
|
fn test_macro() {
|
||||||
let a = big_int!(75);
|
let a = bint!(75);
|
||||||
let b = BigInt::new(75);
|
let b = BigInt::new(75);
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
|
|
||||||
let a = big_int!(-75);
|
let a = bint!(-75);
|
||||||
let b = BigInt::new(-75);
|
let b = BigInt::new(-75);
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
}
|
}
|
||||||
@ -733,13 +568,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_sub() {
|
fn test_sub() {
|
||||||
let a = BigInt::new(usize::MAX);
|
let a = BigInt::new(usize::MAX);
|
||||||
let b = BigInt::new(core::u16::MAX);
|
let b = BigInt::new(u16::MAX);
|
||||||
|
|
||||||
let diff = a - b;
|
let diff = a - b;
|
||||||
assert_eq!(
|
assert_eq!(diff.clone().inner[0], usize::MAX - u16::MAX as usize);
|
||||||
diff.clone().inner[0],
|
|
||||||
usize::MAX - core::u16::MAX as usize
|
|
||||||
);
|
|
||||||
assert_eq!(diff.inner.len(), 1);
|
assert_eq!(diff.inner.len(), 1);
|
||||||
|
|
||||||
let a = BigInt::new(5);
|
let a = BigInt::new(5);
|
||||||
@ -912,10 +744,10 @@ mod tests {
|
|||||||
assert_eq!(c.partial_cmp(&b), Some(Ordering::Less));
|
assert_eq!(c.partial_cmp(&b), Some(Ordering::Less));
|
||||||
assert_eq!(b.partial_cmp(&c), Some(Ordering::Greater));
|
assert_eq!(b.partial_cmp(&c), Some(Ordering::Greater));
|
||||||
|
|
||||||
assert!(big_int!(-32) < big_int!(3));
|
assert!(bint!(-32) < bint!(3));
|
||||||
assert!(big_int!(3) > big_int!(-32));
|
assert!(bint!(3) > bint!(-32));
|
||||||
assert!(big_int!(152) > big_int!(132));
|
assert!(bint!(152) > bint!(132));
|
||||||
assert_eq!(big_int!(123), big_int!(123));
|
assert_eq!(bint!(123), bint!(123));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
47
src/bigint/compare.rs
Normal file
47
src/bigint/compare.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
extern crate alloc;
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
use alloc::string::*;
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
use alloc::vec::*;
|
||||||
|
use core::cmp::{Ordering, PartialEq, PartialOrd};
|
||||||
|
use core::prelude::v1::*;
|
||||||
|
|
||||||
|
use super::BigInt;
|
||||||
|
|
||||||
|
macro_rules! impl_ord_literal {
|
||||||
|
($($prim: ty),+) => {
|
||||||
|
$(
|
||||||
|
impl PartialEq<$prim> for BigInt {
|
||||||
|
#[must_use]
|
||||||
|
fn eq(&self, other: &$prim) -> bool {
|
||||||
|
self == &BigInt::new(*other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<BigInt> for $prim {
|
||||||
|
#[must_use]
|
||||||
|
fn eq(&self, other: &BigInt) -> bool {
|
||||||
|
&BigInt::new(*self) == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd<$prim> for BigInt {
|
||||||
|
#[must_use]
|
||||||
|
fn partial_cmp(&self, other: &$prim) -> Option<Ordering> {
|
||||||
|
self.partial_cmp(&BigInt::new(*other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd<BigInt> for $prim {
|
||||||
|
#[must_use]
|
||||||
|
fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
|
||||||
|
(&BigInt::new(*self)).partial_cmp(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement PartialEq and PartialOrd to compare against BigInt values
|
||||||
|
impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
|
172
src/bigint/from.rs
Normal file
172
src/bigint/from.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
use crate::num::Sign::{self};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
extern crate alloc;
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
use alloc::string::*;
|
||||||
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
use alloc::vec::*;
|
||||||
|
use core::convert::TryInto;
|
||||||
|
use core::prelude::v1::*;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
use super::BigInt;
|
||||||
|
|
||||||
|
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::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 {
|
||||||
|
let target_radix: $s = (usize::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![rem as usize];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
rem = quotient % target_radix;
|
||||||
|
quotient /= target_radix;
|
||||||
|
|
||||||
|
inner.push(rem as usize);
|
||||||
|
|
||||||
|
if (quotient == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInt {
|
||||||
|
inner,
|
||||||
|
sign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$u> for BigInt {
|
||||||
|
/// Create a `BigInt` from an unsigned integer primitive
|
||||||
|
fn from(n: $u) -> Self {
|
||||||
|
let target_radix: $u = (usize::MAX as $u) + 1;
|
||||||
|
|
||||||
|
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![rem as usize];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
rem = quotient % target_radix;
|
||||||
|
quotient /= target_radix;
|
||||||
|
|
||||||
|
inner.push(rem as usize);
|
||||||
|
|
||||||
|
if (quotient == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInt {
|
||||||
|
inner,
|
||||||
|
sign: Sign::Positive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "16")]
|
||||||
|
impl_from_larger!((i32, u32), (i64, u64), (i128, u128));
|
||||||
|
#[cfg(target_pointer_width = "16")]
|
||||||
|
impl_from_smaller!((i8, u8), (i16, u16));
|
||||||
|
|
||||||
|
#[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));
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "128")]
|
||||||
|
impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64), (i128, u128));
|
||||||
|
|
||||||
|
impl From<usize> for BigInt {
|
||||||
|
fn from(n: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: vec![n],
|
||||||
|
sign: Sign::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<isize> for BigInt {
|
||||||
|
fn from(n: isize) -> Self {
|
||||||
|
let sign = if n < 0 {
|
||||||
|
Sign::Negative
|
||||||
|
} else {
|
||||||
|
Sign::Positive
|
||||||
|
};
|
||||||
|
let n = n.abs();
|
||||||
|
let raw: usize = isize::try_into(n).expect("Unable to convert isize value into usize.");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: vec![raw],
|
||||||
|
sign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for BigInt {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Self::from_str(s, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for BigInt {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self::from_str(&s, 10)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user