aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2024-05-29 23:06:24 -0700
committerRose Hogenson <rosehogenson@posteo.net>2024-05-29 23:06:24 -0700
commit74f594d1ecd57973f2976067589a71fdfcedecbe (patch)
treed683af61d5bd172d26ba02fc23049ab40f2b2503
parent545e25efbf022ee76775b9d97bb1267edf0b03bf (diff)
downloadqc-74f594d1ecd57973f2976067589a71fdfcedecbe.tar.zst
Get rid of BigInt.
Too much trouble, tbh. Who needs more than 64 bits anyway?
-rw-r--r--Cargo.lock74
-rw-r--r--Cargo.toml1
-rw-r--r--src/eval.rs178
-rw-r--r--src/main.rs48
-rw-r--r--src/parser.rs3
5 files changed, 77 insertions, 227 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 714d97c..29d2c67 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -469,79 +469,6 @@ dependencies = [
]
[[package]]
-name = "num"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
-dependencies = [
- "num-bigint",
- "num-complex",
- "num-integer",
- "num-iter",
- "num-rational",
- "num-traits",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-iter"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
-dependencies = [
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
name = "pango"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -614,7 +541,6 @@ dependencies = [
"async-channel",
"gdk4",
"gtk4",
- "num",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 9d3d9f1..7f4b3fb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,4 +10,3 @@ license = "GPL3"
async-channel = "2.3.1"
gdk4 = "0.8.2"
gtk4 = "0.8.2"
-num = "0.4.3"
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<T>(m: &Mutex<Option<T>>, msg: T) {
- let mut guard = m.lock().unwrap();
- *guard = Some(msg);
-}
-
-fn get_mail<T>(m: &Mutex<Option<T>>) -> Option<T> {
- 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 {