73 lines
1.4 KiB
Rust
73 lines
1.4 KiB
Rust
use num::Rational64;
|
|
|
|
use super::Int;
|
|
use crate::prelude::*;
|
|
|
|
pub type Ratio = num::BigRational;
|
|
|
|
impl From<Int> for Ratio {
|
|
fn from(value: Int) -> Self {
|
|
Ratio::from_integer(value.into())
|
|
}
|
|
}
|
|
|
|
impl From<&Int> for Ratio {
|
|
fn from(value: &Int) -> Self {
|
|
Ratio::from_integer(value.to_owned().into())
|
|
}
|
|
}
|
|
|
|
pub trait RatioExt: Sized {
|
|
#[must_use]
|
|
fn div_euclid(&self, n: &Self) -> Self;
|
|
#[must_use]
|
|
fn rem_euclid(&self, n: &Self) -> Self;
|
|
fn to_f64_uc(&self) -> f64;
|
|
#[must_use]
|
|
fn approximate_float(x: f64) -> Option<Self>;
|
|
}
|
|
|
|
impl RatioExt for Ratio {
|
|
#[inline]
|
|
fn div_euclid(&self, n: &Self) -> Ratio {
|
|
let (n_abs, n_sgn) = (n.abs(), n.signum());
|
|
(self / n_abs).floor() * n_sgn
|
|
}
|
|
|
|
#[inline]
|
|
fn rem_euclid(&self, n: &Self) -> Ratio {
|
|
ToPrimitive::to_f64(self);
|
|
let n_abs = n.abs();
|
|
self - (self / &n_abs).floor() * &n_abs
|
|
}
|
|
|
|
#[inline]
|
|
fn to_f64_uc(&self) -> f64 {
|
|
if let Some(f) = self.to_f64() {
|
|
f
|
|
} else if self.is_negative() {
|
|
f64::NEG_INFINITY
|
|
} else {
|
|
f64::INFINITY
|
|
}
|
|
}
|
|
|
|
fn approximate_float(x: f64) -> Option<Self> {
|
|
if let Some(r) = Rational64::approximate_float(x) {
|
|
let r = Ratio::new((*r.numer()).into(), (*r.denom()).into());
|
|
Some(r)
|
|
} else {
|
|
let mut y = x;
|
|
if y.abs() < 1.0 {
|
|
y = 1.0 / y;
|
|
}
|
|
let i = Int::from_f64(y)?;
|
|
let r = Ratio::from_integer(i.into());
|
|
if x.abs() < 1.0 {
|
|
Some(r.recip())
|
|
} else {
|
|
Some(r)
|
|
}
|
|
}
|
|
}
|
|
}
|