Some refactoring based on linting suggestions
This commit is contained in:
parent
4ac159c603
commit
d77a136e5c
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1,5 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "rusty-numbers"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
|
@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "rusty-numbers"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
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
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![allow(unused_variables)]
|
||||
//! \[WIP\] Arbitrarily large integers
|
||||
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")))]
|
||||
extern crate alloc;
|
||||
@ -84,6 +84,7 @@ impl BigInt {
|
||||
}
|
||||
|
||||
/// Create a new BigInt, with the specified inner capacity
|
||||
#[must_use]
|
||||
pub fn with_capacity(size: usize) -> Self {
|
||||
Self {
|
||||
inner: Vec::with_capacity(size),
|
||||
@ -250,6 +251,7 @@ impl BigInt {
|
||||
impl Add for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
#[must_use]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
// If the sign of one input differs,
|
||||
// subtraction is equivalent
|
||||
@ -297,6 +299,7 @@ impl Add for BigInt {
|
||||
impl Sub for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
#[must_use]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
let digits = Self::get_ceil_digit_count(&self, &rhs);
|
||||
let mut out = BigInt::with_capacity(digits);
|
||||
@ -344,6 +347,7 @@ impl Sub for BigInt {
|
||||
impl Mul for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
#[must_use]
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
let input_digits = Self::get_ceil_digit_count(&self, &rhs);
|
||||
|
||||
@ -357,6 +361,7 @@ impl Mul for BigInt {
|
||||
impl Div for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
#[must_use]
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
@ -365,6 +370,7 @@ impl Div for BigInt {
|
||||
impl Rem for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
#[must_use]
|
||||
fn rem(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
@ -409,6 +415,7 @@ impl Neg for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
/// Flip the sign of the current `BigInt` value
|
||||
#[must_use]
|
||||
fn neg(mut self) -> Self::Output {
|
||||
self.sign = !self.sign;
|
||||
|
||||
@ -524,8 +531,7 @@ macro_rules! impl_from_larger {
|
||||
if quotient == 0 {
|
||||
Self::from(rem as usize)
|
||||
} else {
|
||||
let mut inner: Vec<usize> = Vec::new();
|
||||
inner.push(rem as usize);
|
||||
let mut inner: Vec<usize> = vec![rem as usize];
|
||||
|
||||
loop {
|
||||
rem = quotient % target_radix;
|
||||
@ -558,8 +564,7 @@ macro_rules! impl_from_larger {
|
||||
if quotient == 0 {
|
||||
Self::from(rem as usize)
|
||||
} else {
|
||||
let mut inner: Vec<usize> = Vec::new();
|
||||
inner.push(rem as usize);
|
||||
let mut inner: Vec<usize> = vec![rem as usize];
|
||||
|
||||
loop {
|
||||
rem = quotient % target_radix;
|
||||
@ -587,24 +592,28 @@ macro_rules! impl_ord_literal {
|
||||
($($prim: ty),+) => {
|
||||
$(
|
||||
impl PartialEq<$prim> for BigInt {
|
||||
#[must_use]
|
||||
fn eq(&self, other: &$prim) -> bool {
|
||||
self == &BigInt::from(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BigInt> for $prim {
|
||||
#[must_use]
|
||||
fn eq(&self, other: &BigInt) -> bool {
|
||||
&BigInt::from(*self) == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<$prim> for BigInt {
|
||||
#[must_use]
|
||||
fn partial_cmp(&self, other: &$prim) -> Option<Ordering> {
|
||||
self.partial_cmp(&BigInt::from(*other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<BigInt> for $prim {
|
||||
#[must_use]
|
||||
fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
|
||||
(&BigInt::from(*self)).partial_cmp(other)
|
||||
}
|
||||
@ -763,7 +772,7 @@ mod tests {
|
||||
|
||||
a -= b;
|
||||
|
||||
assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]);
|
||||
assert_eq!(a.inner, vec![usize::MAX, usize::MAX]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -936,7 +945,7 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn test_from_str_large() {
|
||||
let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321";
|
||||
BigInt::from(str);
|
||||
let _ = BigInt::from(str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -950,7 +959,7 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn test_from_string_large() {
|
||||
let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321");
|
||||
BigInt::from(str);
|
||||
let _ = BigInt::from(str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -16,4 +16,3 @@ extern crate std;
|
||||
pub mod bigint;
|
||||
pub mod num;
|
||||
pub mod rational;
|
||||
|
||||
|
109
src/rational.rs
109
src/rational.rs
@ -1,7 +1,7 @@
|
||||
//! # Rational Numbers (fractions)
|
||||
|
||||
use crate::num::Sign::*;
|
||||
use crate::num::*;
|
||||
use crate::num::Sign::{Negative, Positive};
|
||||
use crate::num::{FracOp, Int, Sign, Unsigned};
|
||||
use core::cmp::{Ord, Ordering, PartialOrd};
|
||||
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)]
|
||||
pub struct Frac<T: Unsigned = usize> {
|
||||
numer: T,
|
||||
denom: T,
|
||||
numerator: T,
|
||||
denominator: T,
|
||||
sign: Sign,
|
||||
}
|
||||
|
||||
@ -66,12 +66,18 @@ impl<T: Unsigned> Frac<T> {
|
||||
///
|
||||
/// Generally, you will probably prefer to use the [frac!](../macro.frac.html) macro
|
||||
/// 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> {
|
||||
Self::new_unreduced(n, d).reduce()
|
||||
}
|
||||
|
||||
/// Create a new rational number from signed or unsigned arguments
|
||||
/// 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> {
|
||||
if d.is_zero() {
|
||||
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
|
||||
let numer = n.to_unsigned();
|
||||
let denom = d.to_unsigned();
|
||||
let numerator = n.to_unsigned();
|
||||
let denominator = d.to_unsigned();
|
||||
|
||||
Frac { numer, denom, sign }
|
||||
Frac { numerator, denominator, sign }
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
if d.is_zero() {
|
||||
panic!("Fraction can not have a zero denominator");
|
||||
}
|
||||
|
||||
Frac {
|
||||
numer: n,
|
||||
denom: d,
|
||||
numerator: n,
|
||||
denominator: d,
|
||||
sign: s,
|
||||
}
|
||||
.reduce()
|
||||
@ -129,9 +138,9 @@ impl<T: Unsigned> Frac<T> {
|
||||
|
||||
/// Convert the fraction to its simplest form
|
||||
pub fn reduce(mut self) -> Self {
|
||||
let gcd = T::gcd(self.numer, self.denom);
|
||||
self.numer /= gcd;
|
||||
self.denom /= gcd;
|
||||
let gcd = T::gcd(self.numerator, self.denominator);
|
||||
self.numerator /= gcd;
|
||||
self.denominator /= gcd;
|
||||
|
||||
self
|
||||
}
|
||||
@ -153,28 +162,28 @@ impl<T: Unsigned> Ord for Frac<T> {
|
||||
};
|
||||
}
|
||||
|
||||
if self.denom == other.denom {
|
||||
return self.numer.cmp(&other.numer);
|
||||
if self.denominator == other.denominator {
|
||||
return self.numerator.cmp(&other.numerator);
|
||||
}
|
||||
|
||||
let mut a = self.reduce();
|
||||
let mut b = other.reduce();
|
||||
|
||||
if a.denom == b.denom {
|
||||
return a.numer.cmp(&b.numer);
|
||||
if a.denominator == b.denominator {
|
||||
return a.numerator.cmp(&b.numerator);
|
||||
}
|
||||
|
||||
let lcm = T::lcm(self.denom, other.denom);
|
||||
let x = lcm / self.denom;
|
||||
let y = lcm / other.denom;
|
||||
let lcm = T::lcm(self.denominator, other.denominator);
|
||||
let x = lcm / self.denominator;
|
||||
let y = lcm / other.denominator;
|
||||
|
||||
a.numer *= x;
|
||||
a.denom *= x;
|
||||
a.numerator *= x;
|
||||
a.denominator *= x;
|
||||
|
||||
b.numer *= y;
|
||||
b.denom *= y;
|
||||
b.numerator *= 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;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self {
|
||||
let numer = self.numer * rhs.numer;
|
||||
let denom = self.denom * rhs.denom;
|
||||
let numerator = self.numerator * rhs.numerator;
|
||||
let denominator = self.denominator * rhs.denominator;
|
||||
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> {
|
||||
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;
|
||||
|
||||
fn div(self, rhs: Self) -> Self {
|
||||
let numer = self.numer * rhs.denom;
|
||||
let denom = self.denom * rhs.numer;
|
||||
let numerator = self.numerator * rhs.denominator;
|
||||
let denominator = self.denominator * rhs.numerator;
|
||||
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> {
|
||||
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
|
||||
if a.denom != b.denom {
|
||||
if a.denominator != b.denominator {
|
||||
// Let's just use the simplest method, rather than
|
||||
// worrying about reducing to the least common denominator
|
||||
let numer = (a.numer * b.denom) + (b.numer * a.denom);
|
||||
let denom = a.denom * b.denom;
|
||||
let numerator = (a.numerator * b.denominator) + (b.numerator * a.denominator);
|
||||
let denominator = a.denominator * b.denominator;
|
||||
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 denom = self.denom;
|
||||
let numerator = a.numerator + b.numerator;
|
||||
let denominator = self.denominator;
|
||||
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> {
|
||||
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);
|
||||
}
|
||||
|
||||
if a.denom != b.denom {
|
||||
let (numer, overflowed) = (a.numer * b.denom).left_overflowing_sub(b.numer * a.denom);
|
||||
if a.denominator != b.denominator {
|
||||
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 res = Self::raw(numer, denom, sign);
|
||||
let res = Self::raw(numerator, denominator, sign);
|
||||
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 res = Self::raw(numer, denom, sign);
|
||||
let res = Self::raw(numerator, denominator, sign);
|
||||
|
||||
if overflowed {
|
||||
-res
|
||||
@ -292,7 +301,7 @@ impl<T: Unsigned> Sub for Frac<T> {
|
||||
|
||||
impl<T: Unsigned> SubAssign for Frac<T> {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = *self - rhs
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,13 +323,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Fraction can not have a zero denominator")]
|
||||
fn zero_denom() {
|
||||
fn zero_denominator() {
|
||||
Frac::raw(1u8, 0u8, Sign::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Fraction can not have a zero denominator")]
|
||||
fn zero_denom_new() {
|
||||
fn zero_denominator_new() {
|
||||
frac!(1 / 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user