From 74f594d1ecd57973f2976067589a71fdfcedecbe Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Wed, 29 May 2024 23:06:24 -0700 Subject: Get rid of BigInt. Too much trouble, tbh. Who needs more than 64 bits anyway? --- src/eval.rs | 178 ++++++++++++++++++++++++---------------------------------- src/main.rs | 48 ++-------------- src/parser.rs | 3 +- 3 files changed, 77 insertions(+), 152 deletions(-) (limited to 'src') diff --git a/src/eval.rs b/src/eval.rs index 1045b17..c11614d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,13 +1,12 @@ -use num::pow::Pow; -use num::{BigInt, FromPrimitive, Integer, Signed, ToPrimitive}; use std::fmt::{Display, Formatter}; +#[derive(Clone, Copy)] pub enum Num { - Int(BigInt), + Int(i64), Float(f64), } -pub fn int(i: BigInt) -> Num { +pub fn int(i: i64) -> Num { Num::Int(i) } @@ -15,43 +14,45 @@ 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 { + fn as_float(self) -> f64 { match self { - Num::Int(i) => float_from_int(i), - Num::Float(f) => *f, + Num::Int(i) => i as f64, + Num::Float(f) => f, } } pub fn pow(self, other: Num) -> Num { match (self, other) { + (_, Num::Int(0)) => return int(1), + (Num::Int(-1), Num::Int(i2)) => { + if i2 % 2 == 0 { + return int(1); + } else { + return int(-1); + } + } + (Num::Int(0), _) => return int(0), + (Num::Int(1), _) => return int(1), (Num::Int(i1), Num::Int(i2)) => { - if i2 < BigInt::ZERO { - return float(float_from_int(&i1).powf(float_from_int(&i2))); + if let Ok(u) = u32::try_from(i2) { + if let Some(p) = i1.checked_pow(u) { + return int(p); + } } - let (_, u2) = i2.into_parts(); - int(i1.pow(u2)) } - (n1, n2) => float(n1.as_float().powf(n2.as_float())), + _ => (), } + float(self.as_float().powf(other.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()), + 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 { @@ -59,57 +60,48 @@ impl Num { } 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)) + 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 i64) } pub fn modulo(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1.mod_floor(&i2)), - (n1, n2) => { - let n1 = n1.as_float(); - let n2 = n2.as_float(); - let r = n1 % n2; - if r < 0. { - return float(r + n2); + 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); } - float(r) + 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 { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 + i2), - (n1, n2) => float(n1.as_float() + n2.as_float()), + 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 { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 - i2), - (n1, n2) => Num::Float(n1.as_float() - n2.as_float()), + 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 { @@ -126,15 +118,23 @@ impl Num { 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()); + 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); } - int(s) } - n => float(n.as_float().sqrt()), + _ => (), } + float(self.as_float().sqrt()) } pub fn log(self) -> Num { @@ -152,36 +152,21 @@ impl Num { 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) - } + Num::Float(f) => int(f.floor() as i64), } } 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) - } + Num::Float(f) => int(f.ceil() as i64), } } 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) - } + Num::Float(f) => int(f.round_ties_even() as i64), } } @@ -193,31 +178,12 @@ impl Num { } } -fn log10(n: &BigInt) -> u64 { - ((n.bits() - 1) as f64 / std::f64::consts::LOG2_10) as u64 -} - impl Display for Num { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - Num::Int(n) => { - if n.bits() < 100 { - return write!(f, "{n}"); - } - let len = log10(n) + 1; - let rounded = i64::try_from(n / BigInt::from(10).pow(len - 8)).unwrap(); - let rounded_str = format!("{rounded}"); - write!( - f, - "{}.{}e{}", - &rounded_str[..1], - &rounded_str[1..], - len - 8 + rounded_str.len() as u64 - 1 - ) - } + Num::Int(n) => write!(f, "{n}"), Num::Float(n) => { - let n = *n; - if !(-1e30..=1e30).contains(&n) { + if !(-1e30..=1e30).contains(n) { return write!(f, "{n:.7e}"); } let mut buf = format!("{n:.7}"); diff --git a/src/main.rs b/src/main.rs index 9fe62b3..8976e17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,17 +8,6 @@ use gtk4::prelude::{ ApplicationExt, ApplicationExtManual, EditableExt, GridExt, GtkWindowExt, WidgetExt, }; use gtk4::{glib, Application, ApplicationWindow, Entry, EventControllerKey, Grid}; -use std::sync::{Arc, Mutex}; - -fn send_mail(m: &Mutex>, msg: T) { - let mut guard = m.lock().unwrap(); - *guard = Some(msg); -} - -fn get_mail(m: &Mutex>) -> Option { - let mut guard = m.lock().unwrap(); - std::mem::take(&mut guard) -} fn main() -> ExitCode { let app = Application::builder() @@ -40,51 +29,22 @@ fn main() -> ExitCode { let output = Entry::builder().editable(false).build(); grid.attach(&output, 0, 1, 1, 1); - let (ping_send, ping_recv) = async_channel::bounded(1); - let mailbox = Arc::new(Mutex::new(None)); - let key_controller = EventControllerKey::new(); key_controller.connect_key_released( - clone!(@weak window, @weak input, @strong mailbox => move |_, k, _, modifiers| { + clone!(@weak window, @weak input, @weak output => move |_, k, _, modifiers| { if k == Key::Escape || k == Key::Return || k == Key::bracketleft && modifiers.contains(ModifierType::CONTROL_MASK) { window.destroy(); } - send_mail(mailbox.as_ref(), format!("{}", input.text())); - let _ = ping_send.try_send(()); + if let Some(n) = parser::parse(&input.text()) { + output.set_text(&format!("{n}")); + } }), ); window.add_controller(key_controller); - glib::spawn_future_local(async move { - let mut prev_input = String::from(""); - loop { - if ping_recv.recv().await.is_err() { - break; - } - let Some(input) = get_mail(mailbox.as_ref()) else { - continue; - }; - if input == prev_input { - continue; - } - prev_input = input.clone(); - let (output_send, output_recv) = async_channel::bounded(1); - let thread_handle = gtk4::gio::spawn_blocking(move || { - if let Some(result) = parser::parse(&input) { - output_send.send_blocking(format!("{result}")).unwrap(); - } - }); - let _ = thread_handle.await; - let Ok(result) = output_recv.try_recv() else { - continue; - }; - output.set_text(&result); - } - }); - window.present(); }); diff --git a/src/parser.rs b/src/parser.rs index 2b33e0f..c0f3a9b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,6 @@ use crate::eval; use crate::eval::Num; use crate::lexer::Lexer; -use num::BigInt; use std::str::FromStr; enum Op { @@ -58,7 +57,7 @@ impl<'a> Parser<'a> { } return Some(eval::float(f)); } - let Ok(i) = BigInt::from_str(t) else { + let Ok(i) = i64::from_str(t) else { return None; }; if negative { -- cgit v1.3.1