aboutsummaryrefslogtreecommitdiffstats
path: root/src/eval.rs
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 /src/eval.rs
parentFix rounding. (diff)
downloadqc-74f594d1ecd57973f2976067589a71fdfcedecbe.tar.zst
Get rid of BigInt.
Too much trouble, tbh. Who needs more than 64 bits anyway?
Diffstat (limited to 'src/eval.rs')
-rw-r--r--src/eval.rs178
1 files changed, 72 insertions, 106 deletions
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}");