#![no_std]
#![feature(const_option)]
#![feature(generic_const_exprs)]
#![expect(incomplete_features)]
use core::num::NonZero;
use core::marker::PhantomData;
pub const fn gcd(x: i128, y: i128) -> i128
{
if x == 0 { return y; }
if y == 0 { return x; }
if x < 0 { return gcd(-x, y); }
if y < 0 { return gcd(x, -y); }
let mut a = x;
let mut b = y;
let mut r = a % b;
while r != 0
{
a = b;
b = r;
r = a % b;
}
b
}
#[derive(Clone,Copy)]
pub struct Ratio<const N: i128, const D: i128>;
impl<const N: i128, const D: i128> core::fmt::Display for Ratio<N,D>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
{
write!(f, "{N} / {D}")
}
}
impl<const N: i128, const D: i128> core::fmt::Debug for Ratio<N,D>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
{
<Self as core::fmt::Display>::fmt(self, f)
}
}
pub trait StaticRatio
{
const NUMERATOR: i128;
const DENOMINATOR: NonZero<i128>;
}
pub trait StaticArithmetic : StaticRatio
{
type OpResult where [(); {Self::DENOMINATOR.get()} as usize]:, [(); {Self::NUMERATOR} as usize]:;
}
pub trait Reducible
{
const GCD_VALUE: i128;
const R_NUMERATOR: i128;
const R_DENOMINATOR: i128;
const IS_IRREDUCIBLE: bool;
type Reduced where [(); {Self::R_DENOMINATOR} as usize]:, [(); {Self::R_NUMERATOR} as usize]:;
}
impl<const N: i128, const D: i128> Reducible for Ratio<N,D>
{
const GCD_VALUE: i128 = gcd(N, D);
const R_NUMERATOR: i128 = N.checked_div(Self::GCD_VALUE).unwrap();
const R_DENOMINATOR: i128 = D.checked_div(Self::GCD_VALUE).unwrap();
const IS_IRREDUCIBLE: bool = Self::GCD_VALUE == 1;
type Reduced = Ratio<{Self::R_NUMERATOR},{Self::R_DENOMINATOR}> where [(); {Self::R_NUMERATOR} as usize]:, [(); {Self::R_DENOMINATOR} as usize]:;
}
impl<T: StaticRatio> StaticArithmetic for T
{
type OpResult = Ratio<{T::NUMERATOR},{T::DENOMINATOR.get()}> where [(); {T::NUMERATOR} as usize]:, [(); {T::DENOMINATOR.get()} as usize]:;
}
impl<const N: i128, const D: i128> StaticRatio for Ratio<N,D>
{
const NUMERATOR: i128 = if D >= 0 { N } else { -N };
const DENOMINATOR: NonZero<i128> = NonZero::new(if D >= 0 { D } else { -D }).unwrap();
}
#[derive(Clone,Copy)]
pub struct RationalSum<X, Y>
{
_a: PhantomData<X>,
_b: PhantomData<Y>,
}
impl<X: StaticRatio, Y: StaticRatio> StaticRatio for RationalSum<X,Y>
{
const NUMERATOR: i128 = X::NUMERATOR.checked_mul(Y::DENOMINATOR.get()).unwrap().checked_add(X::DENOMINATOR.get().checked_mul(Y::NUMERATOR).unwrap()).unwrap();
const DENOMINATOR: NonZero<i128> = NonZero::new(X::DENOMINATOR.get().checked_mul(Y::DENOMINATOR.get()).unwrap()).unwrap();
}
#[derive(Clone,Copy)]
pub struct RationalDiff<X, Y>
{
_a: PhantomData<X>,
_b: PhantomData<Y>,
}
impl<X: StaticRatio, Y: StaticRatio> StaticRatio for RationalDiff<X,Y>
{
const NUMERATOR: i128 = X::NUMERATOR.checked_mul(Y::DENOMINATOR.get()).unwrap().checked_sub(X::DENOMINATOR.get().checked_mul(Y::NUMERATOR).unwrap()).unwrap();
const DENOMINATOR: NonZero<i128> = NonZero::new(X::DENOMINATOR.get().checked_mul(Y::DENOMINATOR.get()).unwrap()).unwrap();
}
#[derive(Clone,Copy)]
pub struct RationalProduct<X, Y>
{
_a: PhantomData<X>,
_b: PhantomData<Y>,
}
impl<X: StaticRatio, Y: StaticRatio> StaticRatio for RationalProduct<X,Y>
{
const NUMERATOR: i128 = X::NUMERATOR.checked_mul(Y::NUMERATOR).unwrap();
const DENOMINATOR: NonZero<i128> = NonZero::new(X::DENOMINATOR.get().checked_mul(Y::DENOMINATOR.get()).unwrap()).unwrap();
}
#[derive(Clone,Copy)]
pub struct RationalDiv<X, Y>
{
_a: PhantomData<X>,
_b: PhantomData<Y>,
}
impl<X: StaticRatio, Y: StaticRatio> StaticRatio for RationalDiv<X,Y>
{
const NUMERATOR: i128 = X::NUMERATOR.checked_mul(Y::DENOMINATOR.get()).unwrap();
const DENOMINATOR: NonZero<i128> = NonZero::new(X::DENOMINATOR.get().checked_mul(Y::NUMERATOR).unwrap()).unwrap();
}
#[derive(Clone,Copy)]
pub struct RationalCmp<X, Y>
{
_a: PhantomData<X>,
_b: PhantomData<Y>,
}
impl<X: StaticRatio, Y: StaticRatio> RationalCmp<X,Y>
{
pub const EQUAL: bool = (X::NUMERATOR.checked_mul(Y::DENOMINATOR.get()).unwrap())==(Y::NUMERATOR.checked_mul(X::DENOMINATOR.get()).unwrap());
pub const NOT_EQUAL: bool = !(Self::EQUAL);
const ABS_D1: i128 = if X::DENOMINATOR.get() > 0 { X::DENOMINATOR.get() } else { -(X::DENOMINATOR.get()) };
const ABS_D2: i128 = if Y::DENOMINATOR.get() > 0 { Y::DENOMINATOR.get() } else { -(Y::DENOMINATOR.get()) };
const SIGN1: i128 = if X::DENOMINATOR.get() > 0 { 1 } else { -1 };
const SIGN2: i128 = if Y::DENOMINATOR.get() > 0 { 1 } else { -1 };
pub const LESSER: bool = Self::SIGN1.checked_mul(X::NUMERATOR.checked_mul(Self::ABS_D2).unwrap()).unwrap() < Self::SIGN2.checked_mul(Y::NUMERATOR.checked_mul(Self::ABS_D1).unwrap()).unwrap();
pub const GREATER: bool = !(Self::EQUAL) && !(Self::LESSER);
pub const GREATER_OR_EQUAL: bool = !(Self::LESSER);
pub const LESSER_OR_EQUAL: bool = Self::LESSER || Self::EQUAL;
}