Split type conversion and comparision trait implementations from main BigInt module
timw4mail/rusty-numbers/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2022-02-16 11:14:45 -05:00
parent 1e7588cf52
commit 83c5abb697
5 changed files with 248 additions and 185 deletions

View File

@ -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]

View File

@ -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

View File

@ -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
View 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
View 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)
}
}