use std::cmp::Ordering;
use num_traits::{One, Zero};
use crate::{NonZero, NonZeroSign, Sign};
use crate::integer::big::ops::non_zero::mul_non_zero;
use crate::integer::big::ops::normalize::simplify_fraction_without_info;
use crate::integer::big::properties::cmp;
use crate::rational::big::{Big, NonZeroBig};
impl<const S: usize> Big<S> {
#[allow(unused)]
pub(crate) unsafe fn is_well_formed(&self) -> bool {
if !unsafe { self.numerator.is_well_formed() } {
return false;
}
if !unsafe { self.denominator.is_well_formed() } {
return false;
}
match self.sign {
Sign::Zero => {
self.numerator.is_zero() && self.denominator.is_one()
}
Sign::Positive | Sign::Negative => {
if self.numerator.is_zero() {
return false;
}
if !self.denominator.is_not_zero() {
return false;
}
let mut n_clone = self.numerator.clone();
let mut d_clone = self.denominator.clone();
unsafe {
simplify_fraction_without_info(n_clone.inner_mut(), d_clone.inner_mut());
}
n_clone == self.numerator && d_clone == self.denominator
}
}
}
}
impl<const S: usize> PartialEq for Big<S> {
#[inline]
fn eq(&self, other: &Self) -> bool {
match (self.sign, other.sign) {
(Sign::Positive, Sign::Negative) |
(Sign::Negative, Sign::Positive) => false,
(Sign::Zero, Sign::Zero) => true,
(Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
self.numerator == other.numerator && self.denominator == other.denominator
}
(Sign::Zero, Sign::Positive | Sign::Negative) |
(Sign::Positive | Sign::Negative, Sign::Zero) => false,
}
}
}
impl<const S: usize> Eq for Big<S> {}
impl<const S: usize> PartialEq for NonZeroBig<S> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.sign == other.sign && self.numerator == other.numerator && self.denominator == other.denominator
}
}
impl<const S: usize> Eq for NonZeroBig<S> {}
macro_rules! rational {
($name:ident, $sign:ident) => {
impl<const S: usize> PartialOrd for $name<S> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<const S: usize> Ord for $name<S> {
#[inline]
#[allow(unreachable_patterns)]
fn cmp(&self, other: &Self) -> Ordering {
match self.sign.cmp(&other.sign) {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => {}
}
if !self.sign.is_not_zero() {
return Ordering::Equal;
}
let left = self.numerator.len() + other.denominator.len();
let right = other.numerator.len() + self.denominator.len();
if left > right + 1 {
return match self.sign {
$sign::Positive => Ordering::Greater,
$sign::Negative => Ordering::Less,
_ => unreachable!("sign was checked to be nonzero"),
};
}
if right > left + 1 {
return match self.sign {
$sign::Positive => Ordering::Less,
$sign::Negative => Ordering::Greater,
_ => unreachable!("sign was checked to be nonzero"),
};
}
if self.numerator == other.numerator && self.denominator == other.denominator {
return Ordering::Equal;
}
let (ad, bc) = unsafe {
(
mul_non_zero::<S>(&self.numerator, &other.denominator),
mul_non_zero::<S>(&other.numerator, &self.denominator),
)
};
match (cmp(&ad, &bc), self.sign) {
(Ordering::Less, $sign::Positive) | (Ordering::Greater, $sign::Negative) => Ordering::Less,
(Ordering::Equal, _) => Ordering::Equal,
(Ordering::Greater, $sign::Positive) | (Ordering::Less, $sign::Negative) => Ordering::Greater,
_ => unreachable!("sign was checked to be nonzero"),
}
}
}
}
}
rational!(Big, Sign);
rational!(NonZeroBig, NonZeroSign);