talc/talc-lang/src/number/ratio.rs

74 lines
1.4 KiB
Rust
Raw Normal View History

2024-12-21 00:55:45 -05:00
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 {
fn div_euclid(&self, n: &Self) -> Self;
fn rem_euclid(&self, n: &Self) -> Self;
fn to_f64_uc(&self) -> f64;
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> {
match Rational64::approximate_float(x) {
Some(r) => {
let r = Ratio::new((*r.numer()).into(), (*r.denom()).into());
Some(r)
}
None => {
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)
}
}
}
}
}