Skip to content

Commit

Permalink
Create module and traits for all integers and make math module generic
Browse files Browse the repository at this point in the history
  • Loading branch information
maneatingape committed Sep 3, 2023
1 parent 26de88b commit a0c80f6
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 66 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ pub mod util {
pub mod ansi;
pub mod grid;
pub mod hash;
pub mod integer;
pub mod iter;
pub mod math;
pub mod md5;
pub mod numeric;
pub mod parse;
pub mod point;
pub mod slice;
Expand Down
53 changes: 53 additions & 0 deletions src/util/integer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::cmp::{PartialEq, PartialOrd};
use std::ops::{Add, BitAnd, Div, Mul, Neg, Rem, Shr, Sub};

pub trait Integer<T>:
Copy
+ From<u8>
+ PartialEq
+ PartialOrd
+ Add<Output = T>
+ BitAnd<Output = T>
+ Div<Output = T>
+ Mul<Output = T>
+ Rem<Output = T>
+ Shr<Output = T>
+ Sub<Output = T>
{
const ZERO: T;
const ONE: T;
const TEN: T;
}

macro_rules! Integer {
($($t:ty)*) => ($(
impl Integer<$t> for $t {
const ZERO: $t = 0;
const ONE: $t = 1;
const TEN: $t = 10;
}

)*)
}

Integer!(u8 u16 u32 u64 usize i16 i32 i64);

pub trait Unsigned<T>: Integer<T> {}

macro_rules! unsigned {
($($t:ty)*) => ($(
impl Unsigned<$t> for $t {}
)*)
}

unsigned!(u8 u16 u32 u64 usize);

pub trait Signed<T>: Integer<T> + Neg<Output = T> {}

macro_rules! signed {
($($t:ty)*) => ($(
impl Signed<$t> for $t {}
)*)
}

signed!(i16 i32 i64);
48 changes: 25 additions & 23 deletions src/util/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
//! * Greatest common divisor
//! * Modular exponentation
//! * Modular inverse
pub trait MathOps {
fn gcd(&self, b: u64) -> u64;
fn mod_pow(&self, e: u64, m: u64) -> u64;
fn mod_inv(&self, m: u64) -> u64;
use crate::util::integer::*;

pub trait MathOps<T: Integer<T>> {
fn gcd(self, b: T) -> T;
fn mod_pow(self, e: T, m: T) -> T;
fn mod_inv(self, m: T) -> T;
}

impl MathOps for u64 {
impl<T: Integer<T>> MathOps<T> for T {
/// Greatest common divisor of 2 numbers using the
/// [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm).
fn gcd(&self, mut b: u64) -> u64 {
let mut a = *self;
fn gcd(self, mut b: T) -> T {
let mut a = self;

while b != 0 {
while b != T::ZERO {
(a, b) = (b, a % b);
}

Expand All @@ -24,38 +26,38 @@ impl MathOps for u64 {

/// Calculates bᵉ mod m efficiently using
/// [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring).
fn mod_pow(&self, mut e: u64, m: u64) -> u64 {
let mut b = *self;
let mut c = 1;
fn mod_pow(self, mut e: T, m: T) -> T {
let mut b = self;
let mut c = T::ONE;

while e > 0 {
if e & 1 == 1 {
while e > T::ZERO {
if e & T::ONE == T::ONE {
c = (c * b) % m;
}
b = (b * b) % m;
e >>= 1;
e = e >> T::ONE;
}

c
}

/// [Modular multiplicative inverse](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse)
/// calculated using the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm).
fn mod_inv(&self, m: u64) -> u64 {
let mut t = 0;
let mut newt = 1;
let mut r = m as i64;
let mut newr = *self as i64;
fn mod_inv(self, m: T) -> T {
let mut t = T::ZERO;
let mut newt = T::ONE;
let mut r = m;
let mut newr = self;

while newr != 0 {
while newr != T::ZERO {
let quotient = r / newr;
(t, newt) = (newt, t - quotient * newt);
(r, newr) = (newr, r - quotient * newr);
}

if t < 0 {
t += m as i64;
if t < T::ZERO {
t = t + m;
}
t as u64
t
}
}
39 changes: 0 additions & 39 deletions src/util/numeric.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/util/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//!
//! [`iter_unsigned`]: ParseOps::iter_unsigned
//! [`iter_signed`]: ParseOps::iter_signed
use crate::util::numeric::*;
use crate::util::integer::*;
use std::marker::PhantomData;
use std::str::Bytes;

Expand Down
2 changes: 1 addition & 1 deletion src/year2019/day10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub fn parse(input: &str) -> Input {
let mut delta = points[j] - points[i];

// Key insight is that points on the same line are integer multiples of each other.
let factor = (delta.x.unsigned_abs() as u64).gcd(delta.y.unsigned_abs() as u64) as i32;
let factor = delta.x.gcd(delta.y).abs();
delta.x /= factor;
delta.y /= factor;

Expand Down
2 changes: 1 addition & 1 deletion src/year2022/day22.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn parse_grid(input: &str) -> Grid {
}

let start = tiles.iter().position(|&t| t == Tile::Open).unwrap() as i32;
let block = (width as u64).gcd(height as u64) as i32;
let block = width.gcd(height) as i32;
Grid { width, height, tiles, start, block }
}

Expand Down

0 comments on commit a0c80f6

Please sign in to comment.