use std::fmt::{Display, Formatter}; #[derive(Clone, Copy)] pub enum Num { Int(i128), Float(f64), } pub fn int(i: i128) -> Num { Num::Int(i) } pub fn float(f: f64) -> Num { Num::Float(f) } impl Num { fn as_float(self) -> f64 { match self { Num::Int(i) => i as f64, Num::Float(f) => f, } } fn powi(self, p: u64) -> Num { if p == 0 { return int(1); } if p == 1 { return self; } if p % 2 == 0 { return self.mul(self).powi(p / 2); } self.mul(self).powi(p / 2).mul(self) } pub fn pow(self, other: Num) -> Num { match other { Num::Int(i) => { if let Ok(u) = u64::try_from(i) { return self.powi(u); } if let Ok(i_32) = i32::try_from(i) { return float(self.as_float().powi(i_32)); } float(1.).div(self).powi(-i as u64) } Num::Float(f) => float(self.as_float().powf(f)), } } pub fn mul(self, other: Num) -> Num { if let (Num::Int(i1), Num::Int(i2)) = (self, other) { if let Some(p) = i1.checked_mul(i2) { return int(p); } } float(self.as_float() * other.as_float()) } pub fn div(self, other: Num) -> Num { float(self.as_float() / other.as_float()) } pub fn int_div(self, other: Num) -> Num { if let (Num::Int(i1), Num::Int(i2)) = (self, other) { if let Some(q) = i1.checked_div(i2) { return int(q); } } int((self.as_float() / other.as_float()) as i128) } pub fn modulo(self, other: Num) -> Num { if let (Num::Int(i1), Num::Int(i2)) = (self, other) { if let Some(r) = i1.checked_rem(i2) { if i2 > 0 && r < 0 || i2 < 0 && r > 0 { return int(r + i2); } return int(r); } } let n1 = self.as_float(); let n2 = other.as_float(); let r = n1 % n2; if n2 > 0. && r < 0. || n2 < 0. && r > 0. { return float(r + n2); } float(r) } pub fn add(self, other: Num) -> Num { if let (Num::Int(i1), Num::Int(i2)) = (self, other) { if let Some(s) = i1.checked_add(i2) { return int(s); } } float(self.as_float() + other.as_float()) } pub fn sub(self, other: Num) -> Num { if let (Num::Int(i1), Num::Int(i2)) = (self, other) { if let Some(d) = i1.checked_sub(i2) { return int(d); } } float(self.as_float() - other.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 asin(self) -> Num { float(self.as_float().asin()) } pub fn acos(self) -> Num { float(self.as_float().acos()) } pub fn atan(self) -> Num { float(self.as_float().atan()) } pub fn sqrt(self) -> Num { match self { Num::Int(i) if i >= 0 => { if i <= 1 { return int(i); } let mut x0 = i / 2; let mut x1 = (x0 + i / x0) / 2; while x1 < x0 { x0 = x1; x1 = (x0 + i / x0) / 2; } if x0 * x0 == i { return int(x0); } } _ => (), } float(self.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) => int(f.floor() as i128), } } pub fn ceil(self) -> Num { match self { Num::Int(i) => int(i), Num::Float(f) => int(f.ceil() as i128), } } pub fn round(self) -> Num { match self { Num::Int(i) => int(i), Num::Float(f) => int(f.round_ties_even() as i128), } } pub fn abs(self) -> Num { match self { Num::Int(i) => int(i.abs()), Num::Float(f) => float(f.abs()), } } } 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) => { if !(-1e30..=1e30).contains(n) { return write!(f, "{n:.7e}"); } let mut buf = format!("{n:.7}"); while let Some(b'0') = buf.as_bytes().get(buf.len() - 1) { buf.truncate(buf.len() - 1); } write!(f, "{buf}") } } } }