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"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
alloc = []
|
||||
std = ["alloc"]
|
||||
|
||||
[dependencies]
|
||||
|
13
justfile
13
justfile
@ -13,6 +13,14 @@ clean:
|
||||
rm -f cobertura.xml
|
||||
rm -f coverage.html
|
||||
|
||||
# Check code syntax
|
||||
check:
|
||||
cargo check
|
||||
|
||||
# Generate API docs
|
||||
docs:
|
||||
cargo doc
|
||||
|
||||
# Check code style
|
||||
lint:
|
||||
cargo clippy
|
||||
@ -21,6 +29,11 @@ lint:
|
||||
fmt:
|
||||
cargo +nightly fmt
|
||||
|
||||
# Automatically fix some code syntax/style issues
|
||||
fix:
|
||||
cargo fix --allow-dirty --allow-staged
|
||||
just fmt
|
||||
|
||||
# Run the normal tests
|
||||
test:
|
||||
cargo test
|
||||
|
196
src/bigint.rs
196
src/bigint.rs
@ -1,4 +1,9 @@
|
||||
//! \[WIP\] Arbitrarily large integers
|
||||
mod compare;
|
||||
mod from;
|
||||
pub use compare::*;
|
||||
pub use from::*;
|
||||
|
||||
use crate::num::FracOp;
|
||||
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
|
||||
#[macro_export]
|
||||
macro_rules! big_int {
|
||||
macro_rules! bint {
|
||||
($w:literal) => {
|
||||
$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 {
|
||||
/// 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(not(tarpaulin_include))]
|
||||
mod tests {
|
||||
@ -657,11 +492,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_macro() {
|
||||
let a = big_int!(75);
|
||||
let a = bint!(75);
|
||||
let b = BigInt::new(75);
|
||||
assert_eq!(a, b);
|
||||
|
||||
let a = big_int!(-75);
|
||||
let a = bint!(-75);
|
||||
let b = BigInt::new(-75);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@ -733,13 +568,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_sub() {
|
||||
let a = BigInt::new(usize::MAX);
|
||||
let b = BigInt::new(core::u16::MAX);
|
||||
let b = BigInt::new(u16::MAX);
|
||||
|
||||
let diff = a - b;
|
||||
assert_eq!(
|
||||
diff.clone().inner[0],
|
||||
usize::MAX - core::u16::MAX as usize
|
||||
);
|
||||
assert_eq!(diff.clone().inner[0], usize::MAX - u16::MAX as usize);
|
||||
assert_eq!(diff.inner.len(), 1);
|
||||
|
||||
let a = BigInt::new(5);
|
||||
@ -912,10 +744,10 @@ mod tests {
|
||||
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));
|
||||
assert!(bint!(-32) < bint!(3));
|
||||
assert!(bint!(3) > bint!(-32));
|
||||
assert!(bint!(152) > bint!(132));
|
||||
assert_eq!(bint!(123), bint!(123));
|
||||
}
|
||||
|
||||
#[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