use crate::{BigInt, gcd_bi};
mod arith;
mod comp;
mod convert;
pub mod e;
pub mod funcs;
pub mod ln2;
pub mod pi;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Ratio {
denom: BigInt,
numer: BigInt
}
impl Ratio {
pub fn from_raw(denom: Vec<u32>, denom_neg: bool, numer: Vec<u32>, numer_neg: bool) -> Self {
Ratio { denom: BigInt::from_raw(denom, denom_neg), numer: BigInt::from_raw(numer, numer_neg) }
}
pub fn into_raw(self) -> (Vec<u32>, bool, Vec<u32>, bool) {
let (denom, numer) = (self.denom, self.numer);
let (denom, denom_neg) = denom.into_raw();
let (numer, numer_neg) = numer.into_raw();
(denom, denom_neg, numer, numer_neg)
}
pub fn zero() -> Self {
Ratio {
denom: BigInt::one(),
numer: BigInt::zero()
}
}
pub fn one() -> Self {
Ratio {
denom: BigInt::one(),
numer: BigInt::one()
}
}
pub fn is_neg(&self) -> bool {
self.numer.is_neg()
}
pub fn is_one(&self) -> bool {
self.denom.is_one() && self.numer.is_one()
}
pub fn is_zero(&self) -> bool {
self.denom.is_one() && self.numer.is_zero()
}
pub fn is_integer(&self) -> bool {
self.denom.is_one()
}
#[cfg(test)]
pub fn is_valid(&self) -> bool {
self.denom.is_valid() && self.numer.is_valid() && !self.denom.is_neg() && (!self.numer.is_zero() || self.denom.is_one()) && gcd_bi(&self.denom, &self.numer).is_one()
}
fn fit(&mut self) {
if self.denom.is_neg() {
self.denom.neg_mut();
self.numer.neg_mut();
}
let r = gcd_bi(&self.denom, &self.numer);
if !r.is_one() {
self.denom.div_bi_mut(&r);
self.numer.div_bi_mut(&r);
}
#[cfg(test)] assert!(self.is_valid());
}
pub fn shrink(&mut self, limit: usize) -> Result<usize, usize> {
if limit < 3 {
return Err(0);
}
let numer_shrink = self.numer.len().max(limit) - limit;
let denom_shrink = self.denom.len().max(limit) - limit;
let shrink = numer_shrink.max(denom_shrink);
if shrink == 0 {
Ok(0)
}
else if shrink + 2 < self.numer.len().min(self.denom.len()) {
self.numer.shift_right_mut(shrink);
self.denom.shift_right_mut(shrink);
self.fit();
Ok(shrink)
}
else if self.numer.len() + 4 < self.denom.len() {
let shrink = self.numer.len();
self.denom.div_bi_mut(&self.numer);
if self.denom.is_neg() {
self.denom.abs_mut();
self.numer = BigInt::one().neg();
}
else {
self.numer = BigInt::one();
}
if self.denom.len() > limit {
Err(shrink - 1)
}
else {
Ok(shrink - 1)
}
}
else if self.denom.len() + 4 < self.numer.len() {
let shrink = self.denom.len();
self.numer.div_bi_mut(&self.denom);
self.denom = BigInt::one();
if self.numer.len() > limit {
Err(shrink - 1)
}
else {
Ok(shrink - 1)
}
}
else {
Err(0)
}
}
}
impl Default for Ratio {
fn default() -> Self { Ratio::zero() }
}