Some refactoring based on linting suggestions

This commit is contained in:
Timothy Warren 2021-12-08 09:57:27 -05:00
parent 4ac159c603
commit d77a136e5c
5 changed files with 81 additions and 62 deletions

4
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "rusty-numbers" name = "rusty-numbers"
version = "0.1.0" version = "0.2.0"

View File

@ -1,8 +1,8 @@
[package] [package]
name = "rusty-numbers" name = "rusty-numbers"
version = "0.1.0" version = "0.2.0"
authors = ["Timothy J. Warren <tim@timshomepage.net>"] authors = ["Timothy J. Warren <tim@timshomepage.net>"]
edition = "2018" 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

View File

@ -1,7 +1,7 @@
#![allow(unused_variables)] #![allow(unused_variables)]
//! \[WIP\] Arbitrarily large integers //! \[WIP\] Arbitrarily large integers
use crate::num::FracOp; use crate::num::FracOp;
use crate::num::Sign::{self, Positive, Negative}; use crate::num::Sign::{self, Negative, Positive};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc; extern crate alloc;
@ -84,6 +84,7 @@ impl BigInt {
} }
/// Create a new BigInt, with the specified inner capacity /// Create a new BigInt, with the specified inner capacity
#[must_use]
pub fn with_capacity(size: usize) -> Self { pub fn with_capacity(size: usize) -> Self {
Self { Self {
inner: Vec::with_capacity(size), inner: Vec::with_capacity(size),
@ -250,6 +251,7 @@ impl BigInt {
impl Add for BigInt { impl Add for BigInt {
type Output = Self; type Output = Self;
#[must_use]
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
// If the sign of one input differs, // If the sign of one input differs,
// subtraction is equivalent // subtraction is equivalent
@ -297,6 +299,7 @@ impl Add for BigInt {
impl Sub for BigInt { impl Sub for BigInt {
type Output = Self; type Output = Self;
#[must_use]
fn sub(self, rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output {
let digits = Self::get_ceil_digit_count(&self, &rhs); let digits = Self::get_ceil_digit_count(&self, &rhs);
let mut out = BigInt::with_capacity(digits); let mut out = BigInt::with_capacity(digits);
@ -344,6 +347,7 @@ impl Sub for BigInt {
impl Mul for BigInt { impl Mul for BigInt {
type Output = Self; type Output = Self;
#[must_use]
fn mul(self, rhs: Self) -> Self::Output { fn mul(self, rhs: Self) -> Self::Output {
let input_digits = Self::get_ceil_digit_count(&self, &rhs); let input_digits = Self::get_ceil_digit_count(&self, &rhs);
@ -357,6 +361,7 @@ impl Mul for BigInt {
impl Div for BigInt { impl Div for BigInt {
type Output = Self; type Output = Self;
#[must_use]
fn div(self, rhs: Self) -> Self::Output { fn div(self, rhs: Self) -> Self::Output {
todo!() todo!()
} }
@ -365,6 +370,7 @@ impl Div for BigInt {
impl Rem for BigInt { impl Rem for BigInt {
type Output = Self; type Output = Self;
#[must_use]
fn rem(self, rhs: Self) -> Self::Output { fn rem(self, rhs: Self) -> Self::Output {
todo!() todo!()
} }
@ -409,6 +415,7 @@ impl Neg for BigInt {
type Output = Self; type Output = Self;
/// Flip the sign of the current `BigInt` value /// Flip the sign of the current `BigInt` value
#[must_use]
fn neg(mut self) -> Self::Output { fn neg(mut self) -> Self::Output {
self.sign = !self.sign; self.sign = !self.sign;
@ -524,8 +531,7 @@ macro_rules! impl_from_larger {
if quotient == 0 { if quotient == 0 {
Self::from(rem as usize) Self::from(rem as usize)
} else { } else {
let mut inner: Vec<usize> = Vec::new(); let mut inner: Vec<usize> = vec![rem as usize];
inner.push(rem as usize);
loop { loop {
rem = quotient % target_radix; rem = quotient % target_radix;
@ -558,8 +564,7 @@ macro_rules! impl_from_larger {
if quotient == 0 { if quotient == 0 {
Self::from(rem as usize) Self::from(rem as usize)
} else { } else {
let mut inner: Vec<usize> = Vec::new(); let mut inner: Vec<usize> = vec![rem as usize];
inner.push(rem as usize);
loop { loop {
rem = quotient % target_radix; rem = quotient % target_radix;
@ -587,24 +592,28 @@ macro_rules! impl_ord_literal {
($($prim: ty),+) => { ($($prim: ty),+) => {
$( $(
impl PartialEq<$prim> for BigInt { impl PartialEq<$prim> for BigInt {
#[must_use]
fn eq(&self, other: &$prim) -> bool { fn eq(&self, other: &$prim) -> bool {
self == &BigInt::from(*other) self == &BigInt::from(*other)
} }
} }
impl PartialEq<BigInt> for $prim { impl PartialEq<BigInt> for $prim {
#[must_use]
fn eq(&self, other: &BigInt) -> bool { fn eq(&self, other: &BigInt) -> bool {
&BigInt::from(*self) == other &BigInt::from(*self) == other
} }
} }
impl PartialOrd<$prim> for BigInt { impl PartialOrd<$prim> for BigInt {
#[must_use]
fn partial_cmp(&self, other: &$prim) -> Option<Ordering> { fn partial_cmp(&self, other: &$prim) -> Option<Ordering> {
self.partial_cmp(&BigInt::from(*other)) self.partial_cmp(&BigInt::from(*other))
} }
} }
impl PartialOrd<BigInt> for $prim { impl PartialOrd<BigInt> for $prim {
#[must_use]
fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> { fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
(&BigInt::from(*self)).partial_cmp(other) (&BigInt::from(*self)).partial_cmp(other)
} }
@ -763,7 +772,7 @@ mod tests {
a -= b; a -= b;
assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]); assert_eq!(a.inner, vec![usize::MAX, usize::MAX]);
} }
#[test] #[test]
@ -936,7 +945,7 @@ mod tests {
#[should_panic] #[should_panic]
fn test_from_str_large() { fn test_from_str_large() {
let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"; let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321";
BigInt::from(str); let _ = BigInt::from(str);
} }
#[test] #[test]
@ -950,7 +959,7 @@ mod tests {
#[should_panic] #[should_panic]
fn test_from_string_large() { fn test_from_string_large() {
let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"); let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321");
BigInt::from(str); let _ = BigInt::from(str);
} }
#[test] #[test]

View File

@ -16,4 +16,3 @@ extern crate std;
pub mod bigint; pub mod bigint;
pub mod num; pub mod num;
pub mod rational; pub mod rational;

View File

@ -1,7 +1,7 @@
//! # Rational Numbers (fractions) //! # Rational Numbers (fractions)
use crate::num::Sign::*; use crate::num::Sign::{Negative, Positive};
use crate::num::*; use crate::num::{FracOp, Int, Sign, Unsigned};
use core::cmp::{Ord, Ordering, PartialOrd}; use core::cmp::{Ord, Ordering, PartialOrd};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@ -25,8 +25,8 @@ use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAss
/// ``` /// ```
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Frac<T: Unsigned = usize> { pub struct Frac<T: Unsigned = usize> {
numer: T, numerator: T,
denom: T, denominator: T,
sign: Sign, sign: Sign,
} }
@ -66,12 +66,18 @@ impl<T: Unsigned> Frac<T> {
/// ///
/// Generally, you will probably prefer to use the [frac!](../macro.frac.html) macro /// Generally, you will probably prefer to use the [frac!](../macro.frac.html) macro
/// instead, as that is easier for mixed fractions and whole numbers /// instead, as that is easier for mixed fractions and whole numbers
///
/// # Panics
/// if `d` is 0, this constructor will panic
pub fn new<N: Int<Un = T>>(n: N, d: N) -> Frac<T> { pub fn new<N: Int<Un = T>>(n: N, d: N) -> Frac<T> {
Self::new_unreduced(n, d).reduce() Self::new_unreduced(n, d).reduce()
} }
/// Create a new rational number from signed or unsigned arguments /// Create a new rational number from signed or unsigned arguments
/// where the resulting fraction is not reduced /// where the resulting fraction is not reduced
///
/// # Panics
/// if `d` is 0, this constructor will panic
pub fn new_unreduced<N: Int<Un = T>>(n: N, d: N) -> Frac<T> { pub fn new_unreduced<N: Int<Un = T>>(n: N, d: N) -> Frac<T> {
if d.is_zero() { if d.is_zero() {
panic!("Fraction can not have a zero denominator"); panic!("Fraction can not have a zero denominator");
@ -88,21 +94,24 @@ impl<T: Unsigned> Frac<T> {
} }
// Convert the possibly signed arguments to unsigned values // Convert the possibly signed arguments to unsigned values
let numer = n.to_unsigned(); let numerator = n.to_unsigned();
let denom = d.to_unsigned(); let denominator = d.to_unsigned();
Frac { numer, denom, sign } Frac { numerator, denominator, sign }
} }
/// Create a new rational from all the raw parts /// Create a new rational from all the raw parts
///
/// # Panics
/// if `d` is 0, this constructor will panic
fn raw(n: T, d: T, s: Sign) -> Frac<T> { fn raw(n: T, d: T, s: Sign) -> Frac<T> {
if d.is_zero() { if d.is_zero() {
panic!("Fraction can not have a zero denominator"); panic!("Fraction can not have a zero denominator");
} }
Frac { Frac {
numer: n, numerator: n,
denom: d, denominator: d,
sign: s, sign: s,
} }
.reduce() .reduce()
@ -129,9 +138,9 @@ impl<T: Unsigned> Frac<T> {
/// Convert the fraction to its simplest form /// Convert the fraction to its simplest form
pub fn reduce(mut self) -> Self { pub fn reduce(mut self) -> Self {
let gcd = T::gcd(self.numer, self.denom); let gcd = T::gcd(self.numerator, self.denominator);
self.numer /= gcd; self.numerator /= gcd;
self.denom /= gcd; self.denominator /= gcd;
self self
} }
@ -153,28 +162,28 @@ impl<T: Unsigned> Ord for Frac<T> {
}; };
} }
if self.denom == other.denom { if self.denominator == other.denominator {
return self.numer.cmp(&other.numer); return self.numerator.cmp(&other.numerator);
} }
let mut a = self.reduce(); let mut a = self.reduce();
let mut b = other.reduce(); let mut b = other.reduce();
if a.denom == b.denom { if a.denominator == b.denominator {
return a.numer.cmp(&b.numer); return a.numerator.cmp(&b.numerator);
} }
let lcm = T::lcm(self.denom, other.denom); let lcm = T::lcm(self.denominator, other.denominator);
let x = lcm / self.denom; let x = lcm / self.denominator;
let y = lcm / other.denom; let y = lcm / other.denominator;
a.numer *= x; a.numerator *= x;
a.denom *= x; a.denominator *= x;
b.numer *= y; b.numerator *= y;
b.denom *= y; b.denominator *= y;
a.numer.cmp(&b.numer) a.numerator.cmp(&b.numerator)
} }
} }
@ -182,17 +191,17 @@ impl<T: Unsigned> Mul for Frac<T> {
type Output = Self; type Output = Self;
fn mul(self, rhs: Self) -> Self { fn mul(self, rhs: Self) -> Self {
let numer = self.numer * rhs.numer; let numerator = self.numerator * rhs.numerator;
let denom = self.denom * rhs.denom; let denominator = self.denominator * rhs.denominator;
let sign = Self::get_sign(self, rhs, FracOp::Other); let sign = Self::get_sign(self, rhs, FracOp::Other);
Self::raw(numer, denom, sign) Self::raw(numerator, denominator, sign)
} }
} }
impl<T: Unsigned> MulAssign for Frac<T> { impl<T: Unsigned> MulAssign for Frac<T> {
fn mul_assign(&mut self, rhs: Self) { fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs *self = *self * rhs;
} }
} }
@ -200,17 +209,17 @@ impl<T: Unsigned> Div for Frac<T> {
type Output = Self; type Output = Self;
fn div(self, rhs: Self) -> Self { fn div(self, rhs: Self) -> Self {
let numer = self.numer * rhs.denom; let numerator = self.numerator * rhs.denominator;
let denom = self.denom * rhs.numer; let denominator = self.denominator * rhs.numerator;
let sign = Self::get_sign(self, rhs, FracOp::Other); let sign = Self::get_sign(self, rhs, FracOp::Other);
Self::raw(numer, denom, sign) Self::raw(numerator, denominator, sign)
} }
} }
impl<T: Unsigned> DivAssign for Frac<T> { impl<T: Unsigned> DivAssign for Frac<T> {
fn div_assign(&mut self, rhs: Self) { fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs *self = *self / rhs;
} }
} }
@ -230,27 +239,27 @@ impl<T: Unsigned> Add for Frac<T> {
} }
// Find a common denominator if needed // Find a common denominator if needed
if a.denom != b.denom { if a.denominator != b.denominator {
// Let's just use the simplest method, rather than // Let's just use the simplest method, rather than
// worrying about reducing to the least common denominator // worrying about reducing to the least common denominator
let numer = (a.numer * b.denom) + (b.numer * a.denom); let numerator = (a.numerator * b.denominator) + (b.numerator * a.denominator);
let denom = a.denom * b.denom; let denominator = a.denominator * b.denominator;
let sign = Self::get_sign(a, b, FracOp::Addition); let sign = Self::get_sign(a, b, FracOp::Addition);
return Self::raw(numer, denom, sign); return Self::raw(numerator, denominator, sign);
} }
let numer = a.numer + b.numer; let numerator = a.numerator + b.numerator;
let denom = self.denom; let denominator = self.denominator;
let sign = Self::get_sign(a, b, FracOp::Addition); let sign = Self::get_sign(a, b, FracOp::Addition);
Self::raw(numer, denom, sign) Self::raw(numerator, denominator, sign)
} }
} }
impl<T: Unsigned> AddAssign for Frac<T> { impl<T: Unsigned> AddAssign for Frac<T> {
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs *self = *self + rhs;
} }
} }
@ -267,20 +276,20 @@ impl<T: Unsigned> Sub for Frac<T> {
return -(b + -a); return -(b + -a);
} }
if a.denom != b.denom { if a.denominator != b.denominator {
let (numer, overflowed) = (a.numer * b.denom).left_overflowing_sub(b.numer * a.denom); let (numerator, overflowed) = (a.numerator * b.denominator).left_overflowing_sub(b.numerator * a.denominator);
let denom = a.denom * b.denom; let denominator = a.denominator * b.denominator;
let sign = Self::get_sign(a, b, FracOp::Subtraction); let sign = Self::get_sign(a, b, FracOp::Subtraction);
let res = Self::raw(numer, denom, sign); let res = Self::raw(numerator, denominator, sign);
return if overflowed { -res } else { res }; return if overflowed { -res } else { res };
} }
let (numer, overflowed) = a.numer.left_overflowing_sub(b.numer); let (numerator, overflowed) = a.numerator.left_overflowing_sub(b.numerator);
let denom = a.denom; let denominator = a.denominator;
let sign = Self::get_sign(a, b, FracOp::Subtraction); let sign = Self::get_sign(a, b, FracOp::Subtraction);
let res = Self::raw(numer, denom, sign); let res = Self::raw(numerator, denominator, sign);
if overflowed { if overflowed {
-res -res
@ -292,7 +301,7 @@ impl<T: Unsigned> Sub for Frac<T> {
impl<T: Unsigned> SubAssign for Frac<T> { impl<T: Unsigned> SubAssign for Frac<T> {
fn sub_assign(&mut self, rhs: Self) { fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs *self = *self - rhs;
} }
} }
@ -314,13 +323,13 @@ mod tests {
#[test] #[test]
#[should_panic(expected = "Fraction can not have a zero denominator")] #[should_panic(expected = "Fraction can not have a zero denominator")]
fn zero_denom() { fn zero_denominator() {
Frac::raw(1u8, 0u8, Sign::default()); Frac::raw(1u8, 0u8, Sign::default());
} }
#[test] #[test]
#[should_panic(expected = "Fraction can not have a zero denominator")] #[should_panic(expected = "Fraction can not have a zero denominator")]
fn zero_denom_new() { fn zero_denominator_new() {
frac!(1 / 0); frac!(1 / 0);
} }