From 2df47cf5e375c73917ebcd6690cd16199d57af83 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Tue, 28 May 2024 18:12:02 -0700 Subject: Use num crate. --- src/eval.rs | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 src/eval.rs (limited to 'src/eval.rs') diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000..d3b5ddc --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,196 @@ +use num::pow::Pow; +use num::{BigInt, FromPrimitive, Signed, ToPrimitive}; +use std::fmt::{Display, Formatter}; + +pub enum Num { + Int(BigInt), + Float(f64), +} + +pub fn int(i: BigInt) -> Num { + Num::Int(i) +} + +pub fn float(f: f64) -> Num { + Num::Float(f) +} + +fn float_from_int(i: &BigInt) -> f64 { + if let Some(f) = i.to_f64() { + return f; + } + if i > &BigInt::ZERO { + std::f64::INFINITY + } else { + std::f64::NEG_INFINITY + } +} + +impl Num { + fn as_float(&self) -> f64 { + match self { + Num::Int(i) => float_from_int(i), + Num::Float(f) => *f, + } + } + + pub fn pow(self, other: Num) -> Num { + match (self, other) { + (Num::Int(i1), Num::Int(i2)) => { + if i2 < BigInt::ZERO { + return float(float_from_int(&i1).powf(float_from_int(&i2))); + } + let (_, u2) = i2.into_parts(); + int(i1.pow(u2)) + } + (n1, n2) => float(n1.as_float().powf(n2.as_float())), + } + } + + pub fn mul(self, other: Num) -> Num { + match (self, other) { + (Num::Int(i1), Num::Int(i2)) => int(i1 * i2), + (n1, n2) => float(n1.as_float() * n2.as_float()), + } + } + + pub fn div(self, other: Num) -> Num { + float(self.as_float() / other.as_float()) + } + + pub fn int_div(self, other: Num) -> Num { + match (self, other) { + (Num::Int(i1), Num::Int(i2)) => int(i1 / i2), + (Num::Float(f1), Num::Float(f2)) => { + let r = f1 / f2; + if let Some(i) = BigInt::from_f64(r) { + return int(i); + } + float(r) + } + (Num::Int(i), Num::Float(f)) => { + if let Some(fi) = BigInt::from_f64(f) { + return int(i / fi); + } + float(float_from_int(&i) / f) + } + (Num::Float(f), Num::Int(i)) => { + if let Some(fi) = BigInt::from_f64(f) { + return int(fi / i); + } + float(f / float_from_int(&i)) + } + } + } + + pub fn add(self, other: Num) -> Num { + match (self, other) { + (Num::Int(i1), Num::Int(i2)) => int(i1 + i2), + (n1, n2) => float(n1.as_float() + n2.as_float()), + } + } + + pub fn sub(self, other: Num) -> Num { + match (self, other) { + (Num::Int(i1), Num::Int(i2)) => int(i1 - i2), + (n1, n2) => Num::Float(n1.as_float() - n2.as_float()), + } + } + + pub fn sin(self) -> Num { + float(self.as_float().sin()) + } + + pub fn cos(self) -> Num { + float(self.as_float().cos()) + } + + pub fn tan(self) -> Num { + float(self.as_float().tan()) + } + + pub fn sqrt(self) -> Num { + match self { + Num::Int(i) if i >= BigInt::ZERO => { + let s = i.sqrt(); + if i != &s * &s { + return float(float_from_int(&i).sqrt()); + } + int(s) + } + n => float(n.as_float().sqrt()), + } + } + + pub fn log(self) -> Num { + float(self.as_float().ln()) + } + + pub fn log10(self) -> Num { + float(self.as_float().log10()) + } + + pub fn log2(self) -> Num { + float(self.as_float().log2()) + } + + pub fn floor(self) -> Num { + match self { + Num::Int(i) => int(i), + Num::Float(f) => { + if let Some(i) = BigInt::from_f64(f.floor()) { + return int(i); + } + float(f) + } + } + } + + pub fn ceil(self) -> Num { + match self { + Num::Int(i) => int(i), + Num::Float(f) => { + if let Some(i) = BigInt::from_f64(f.ceil()) { + return int(i); + } + float(f) + } + } + } + + pub fn round(self) -> Num { + match self { + Num::Int(i) => int(i), + Num::Float(f) => { + if let Some(i) = BigInt::from_f64(f.round_ties_even()) { + return int(i); + } + float(f) + } + } + } + + pub fn abs(self) -> Num { + match self { + Num::Int(i) => int(i.abs()), + Num::Float(f) => float(f.abs()), + } + } +} + +fn format_float(f: f64) -> String { + let mut s = format!("{f:.7}"); + while let Some(b'0') = s.as_bytes().get(s.len() - 1) { + s.truncate(s.len() - 1); + } + s +} + +impl Display for Num { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + Num::Int(n) => write!(f, "{n}"), + Num::Float(n) => write!(f, "{}", format_float(*n)), + } + } +} -- cgit v1.3.1