Implement more From trait mappings, add more docs
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
101a37b6bc
commit
193a66b19d
202
src/bigint.rs
202
src/bigint.rs
@ -1,57 +1,23 @@
|
|||||||
|
#![allow(unused_variables)]
|
||||||
//! \[WIP\] Arbitrarily large integers
|
//! \[WIP\] Arbitrarily large integers
|
||||||
//!
|
|
||||||
//! Traits to implement:
|
|
||||||
//! * Neg
|
|
||||||
//! * Rem
|
|
||||||
//! * RemAssign
|
|
||||||
//! * Sub
|
|
||||||
//! * SubAssign
|
|
||||||
use crate::num::*;
|
use crate::num::*;
|
||||||
use core::ops::{
|
use core::ops::{
|
||||||
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign,
|
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
use core::usize;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct BigInt {
|
pub struct BigInt {
|
||||||
inner: Vec<usize>,
|
inner: Vec<usize>,
|
||||||
sign: Sign,
|
sign: Sign,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_from_smaller {
|
|
||||||
($($Type: ty),* ) => {
|
|
||||||
$(
|
|
||||||
impl From<$Type> for BigInt {
|
|
||||||
fn from(n: $Type) -> Self {
|
|
||||||
let mut new = Self::default();
|
|
||||||
new.inner[0] = n as usize;
|
|
||||||
|
|
||||||
new
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "16")]
|
|
||||||
impl_from_smaller!(u8, u16);
|
|
||||||
#[cfg(target_pointer_width = "16")]
|
|
||||||
static BITS:usize = 16;
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
impl_from_smaller!(u8, u16, u32);
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
static BITS:usize = 32;
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
impl_from_smaller!(u8, u16, u32, u64);
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
static BITS:usize = 64;
|
|
||||||
|
|
||||||
impl Default for BigInt {
|
impl Default for BigInt {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: vec![0],
|
inner: vec![0],
|
||||||
sign: Sign::Positive,
|
sign: Sign::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +26,7 @@ impl From<usize> for BigInt {
|
|||||||
fn from(n: usize) -> Self {
|
fn from(n: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: vec![n],
|
inner: vec![n],
|
||||||
sign: Sign::Positive,
|
sign: Sign::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,14 +44,52 @@ impl From<String> for BigInt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BigInt {
|
impl BigInt {
|
||||||
|
/// Create a new Bigint, of value 0
|
||||||
|
///
|
||||||
|
/// The various `From` implementations are more useful in most cases
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shrink_to_fit(&mut self) {
|
fn new_empty() -> Self {
|
||||||
todo!();
|
Self {
|
||||||
|
inner: Vec::new(),
|
||||||
|
sign: Sign::Positive,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove digits that are zero from the internal representation.
|
||||||
|
///
|
||||||
|
/// Similar to 007 -> 7 in base 10
|
||||||
|
pub fn trim_zeros(&mut self) {
|
||||||
|
let current_len = self.inner.len();
|
||||||
|
if current_len < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut trailing_zeros = 0usize;
|
||||||
|
for val in self.inner.iter().rev() {
|
||||||
|
if *val != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing_zeros += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_len = current_len - trailing_zeros;
|
||||||
|
|
||||||
|
self.inner.truncate(new_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove unused digits, and shrink the internal vector
|
||||||
|
pub fn shrink_to_fit(&mut self) {
|
||||||
|
self.trim_zeros();
|
||||||
|
self.inner.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a `&str` or a `String` representing a number in the specified radix to a Bigint.
|
||||||
|
///
|
||||||
|
/// For radix 10, use the `from` associated function instead.
|
||||||
pub fn from_str_radix<T: ToString>(s: T, radix: usize) -> BigInt {
|
pub fn from_str_radix<T: ToString>(s: T, radix: usize) -> BigInt {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -96,7 +100,7 @@ impl Add for BigInt {
|
|||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
// @TODO: handle signs
|
// @TODO: handle signs
|
||||||
let mut out = BigInt::default();
|
let mut out = BigInt::new_empty();
|
||||||
|
|
||||||
let u_digits = self.inner.len();
|
let u_digits = self.inner.len();
|
||||||
let v_digits = rhs.inner.len();
|
let v_digits = rhs.inner.len();
|
||||||
@ -114,22 +118,14 @@ impl Add for BigInt {
|
|||||||
|
|
||||||
let (res, overflowed) = a.overflowing_add(b);
|
let (res, overflowed) = a.overflowing_add(b);
|
||||||
if overflowed {
|
if overflowed {
|
||||||
if i == 0 {
|
out.inner.push(res + carry);
|
||||||
out.inner[i] = res + carry;
|
|
||||||
} else {
|
|
||||||
out.inner.push(res + carry);
|
|
||||||
}
|
|
||||||
carry = 1;
|
carry = 1;
|
||||||
} else {
|
} else if res < core::usize::MAX {
|
||||||
if res < core::usize::MAX {
|
out.inner.push(res + carry);
|
||||||
out.inner.push(res + carry);
|
|
||||||
carry = 0;
|
|
||||||
} else {
|
|
||||||
out.inner.push(0usize);
|
|
||||||
carry = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
carry = 0;
|
carry = 0;
|
||||||
|
} else {
|
||||||
|
out.inner.push(0usize);
|
||||||
|
carry = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +137,7 @@ impl Sub for BigInt {
|
|||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +145,7 @@ impl Mul for BigInt {
|
|||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +153,7 @@ impl Div for BigInt {
|
|||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn div(self, rhs: Self) -> Self::Output {
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +161,7 @@ impl Rem for BigInt {
|
|||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn rem(self, rhs: Self) -> Self::Output {
|
fn rem(self, rhs: Self) -> Self::Output {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +198,7 @@ impl RemAssign for BigInt {
|
|||||||
impl Neg for BigInt {
|
impl Neg for BigInt {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
/// Flip the sign of the current `BigInt` value
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
let mut output = self.clone();
|
let mut output = self.clone();
|
||||||
output.sign = !output.sign;
|
output.sign = !output.sign;
|
||||||
@ -213,6 +210,7 @@ impl Neg for BigInt {
|
|||||||
impl Not for BigInt {
|
impl Not for BigInt {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
/// Do a bitwise negation of every digit's value
|
||||||
fn not(self) -> Self::Output {
|
fn not(self) -> Self::Output {
|
||||||
let mut flipped: Vec<usize> = Vec::with_capacity(self.inner.len());
|
let mut flipped: Vec<usize> = Vec::with_capacity(self.inner.len());
|
||||||
|
|
||||||
@ -228,6 +226,79 @@ impl Not 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::new_empty();
|
||||||
|
new.inner.push(n as usize);
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_larger {
|
||||||
|
($(($s: ty, $u: ty)),* ) => {
|
||||||
|
$(
|
||||||
|
impl From<$s> for BigInt {
|
||||||
|
/// Create a `BigInt` from a signed integer primitive
|
||||||
|
fn from(n: $s) -> Self {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$u> for BigInt {
|
||||||
|
/// Create a `BigInt` from an unsigned integer primitive
|
||||||
|
fn from(n: $u) -> Self {
|
||||||
|
use core::usize::MAX;
|
||||||
|
|
||||||
|
let base_usize_value = n / MAX as $u;
|
||||||
|
let rem = n % MAX as $u;
|
||||||
|
|
||||||
|
if base_usize_value == 0 {
|
||||||
|
Self::from(rem as usize)
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 = "32")]
|
||||||
|
static BITS:usize = 32;
|
||||||
|
|
||||||
|
#[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 = "64")]
|
||||||
|
static BITS:usize = 64;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -285,4 +356,13 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(a.inner[1], 1usize, "most significant place should be 1");
|
assert_eq!(a.inner[1], 1usize, "most significant place should be 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from() {
|
||||||
|
// Signed numbers
|
||||||
|
assert_eq!(-BigInt::from(2), BigInt::from(-2));
|
||||||
|
|
||||||
|
// Larger than usize
|
||||||
|
assert_eq!(BigInt::from(45u128), BigInt::from(45usize));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user