Add rust_decimal support
This commit is contained in:
parent
8346412f7a
commit
b8c2f24f6e
239
Cargo.lock
generated
239
Cargo.lock
generated
@ -102,6 +102,17 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
@ -361,12 +372,79 @@ dependencies = [
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
|
||||
dependencies = [
|
||||
"borsh-derive-internal",
|
||||
"borsh-schema-derive-internal",
|
||||
"proc-macro-crate 0.1.5",
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh-derive-internal"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh-schema-derive-internal"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13fe11640a23eb24562225322cd3e452b93a3d4091d62fab69c70542fcd17d1f"
|
||||
dependencies = [
|
||||
"bytecheck_derive",
|
||||
"ptr_meta",
|
||||
"simdutf8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck_derive"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e31225543cb46f81a7e224762764f4a6a0f097b1db0b175f69e8065efaa42de5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.13.0"
|
||||
@ -746,7 +824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6412a21e0bde7c0918f7fb44bbbb86b5e1f88e63c026a4e747cc7af02f76dfbe"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"ahash",
|
||||
"ahash 0.8.3",
|
||||
"epaint",
|
||||
"nohash-hasher",
|
||||
"ron",
|
||||
@ -836,7 +914,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12e78b5c58a1f7f621f9d546add2adce20636422c9b251e29f749e8a2f713c95"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"ahash",
|
||||
"ahash 0.8.3",
|
||||
"atomic_refcell",
|
||||
"bytemuck",
|
||||
"ecolor",
|
||||
@ -1102,6 +1180,9 @@ name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
@ -1158,6 +1239,12 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.20.0"
|
||||
@ -1436,6 +1523,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.11"
|
||||
@ -1451,7 +1547,7 @@ version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 1.3.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
@ -1671,6 +1767,15 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
|
||||
dependencies = [
|
||||
"toml 0.5.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.0"
|
||||
@ -1690,6 +1795,26 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
@ -1783,6 +1908,40 @@ version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21499ed91807f07ae081880aabb2ccc0235e9d88011867d984525e9a4c3cfa3e"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
"hashbrown",
|
||||
"ptr_meta",
|
||||
"rend",
|
||||
"rkyv_derive",
|
||||
"seahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.7.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1c672430eb41556291981f45ca900a0239ad007242d1cb4b4167af842db666"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.8.0"
|
||||
@ -1801,8 +1960,10 @@ dependencies = [
|
||||
"confy",
|
||||
"crossterm",
|
||||
"lazy_static",
|
||||
"rust_decimal",
|
||||
"rust_decimal_macros",
|
||||
"serde",
|
||||
"toml",
|
||||
"toml 0.4.10",
|
||||
"tui",
|
||||
]
|
||||
|
||||
@ -1820,6 +1981,34 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"borsh",
|
||||
"bytecheck",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal_macros"
|
||||
version = "1.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e773fd3da1ed42472fdf3cfdb4972948a555bc3d73f5e0bdb99d17e7b54c687"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"rust_decimal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.11"
|
||||
@ -1834,6 +2023,12 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -1868,6 +2063,12 @@ dependencies = [
|
||||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
@ -1900,6 +2101,17 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.10"
|
||||
@ -1963,6 +2175,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
@ -2158,6 +2376,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.1"
|
||||
@ -2835,7 +3062,7 @@ version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "414cd9f07964695e00bfef8e589d1752ea0480b8a619f2064cbaccb8a6c2ed59"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 1.3.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
@ -2873,7 +3100,7 @@ version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fd4aafc0dee96ae7242a24249ce9babf21e1562822f03df650d4e68c20e41ed"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 1.3.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
|
@ -24,6 +24,8 @@ serde = {version = "1.0", features = ["derive"]}
|
||||
# confy = "0.4.0"
|
||||
toml = "0.4.2"
|
||||
lazy_static = "1.4.0"
|
||||
rust_decimal = { version = "1.29.1", features=["maths"] }
|
||||
rust_decimal_macros = "1.29.1"
|
||||
|
||||
[dependencies.confy]
|
||||
# TODO: Update this to v0.5.0 when it finally comes out -- for now, use latest git master
|
||||
|
@ -179,11 +179,14 @@ impl eframe::App for TemplateApp {
|
||||
});
|
||||
|
||||
ui.label(
|
||||
self.calculator.stack.iter()
|
||||
self.calculator
|
||||
.stack
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"));
|
||||
.join("\n"),
|
||||
);
|
||||
|
||||
// ui.label(format!("Calc details: {:#?}", self.calculator.stack));
|
||||
ui.label(format!("Entry buffer: {}", self.calculator.get_l()));
|
||||
|
25
src/calc.rs
25
src/calc.rs
@ -1,9 +1,12 @@
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
pub mod entries;
|
||||
use crate::constants;
|
||||
use lazy_static::lazy_static;
|
||||
pub mod errors;
|
||||
pub mod operations;
|
||||
pub mod types;
|
||||
use crate::calc::entries::CalculatorEntry;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use confy::{load, store};
|
||||
use entries::{Entry, Matrix, Number, Vector};
|
||||
@ -197,7 +200,7 @@ impl Default for Calculator {
|
||||
CalculatorConstant {
|
||||
help: String::from("Tau (2pi)"),
|
||||
value: Entry::Number(Number {
|
||||
value: std::f64::consts::TAU,
|
||||
value: constants::TAU,
|
||||
}),
|
||||
},
|
||||
),
|
||||
@ -206,7 +209,7 @@ impl Default for Calculator {
|
||||
CalculatorConstant {
|
||||
help: String::from("Euler's Number e"),
|
||||
value: Entry::Number(Number {
|
||||
value: std::f64::consts::E,
|
||||
value: constants::E,
|
||||
}),
|
||||
},
|
||||
),
|
||||
@ -215,7 +218,7 @@ impl Default for Calculator {
|
||||
CalculatorConstant {
|
||||
help: String::from("Pi"),
|
||||
value: Entry::Number(Number {
|
||||
value: std::f64::consts::PI,
|
||||
value: constants::PI,
|
||||
}),
|
||||
},
|
||||
),
|
||||
@ -479,7 +482,10 @@ impl Calculator {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let f = self.l.parse::<f64>().or(Err(CalculatorError::ParseError))?;
|
||||
let f = self
|
||||
.l
|
||||
.parse::<Decimal>()
|
||||
.or(Err(CalculatorError::ParseError))?;
|
||||
self.push(Entry::Number(Number { value: f }))?;
|
||||
self.l.clear();
|
||||
Ok(true)
|
||||
@ -520,14 +526,11 @@ impl Calculator {
|
||||
Entry::Matrix(_) | Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
|
||||
Entry::Number(Number { value }) => value,
|
||||
};
|
||||
// Ensure this can be cast to a usize
|
||||
if !f.is_finite() || f.is_sign_negative() {
|
||||
return Err(CalculatorError::ArithmeticError);
|
||||
}
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
let u = f as usize;
|
||||
|
||||
Ok((u, entry))
|
||||
match f.to_usize() {
|
||||
Some(u) => Ok((u, entry)),
|
||||
None => Err(CalculatorError::ArithmeticError),
|
||||
}
|
||||
}
|
||||
/// Pops a precision instead of an Entry. Precisions are of type usize
|
||||
pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
|
||||
|
@ -255,6 +255,8 @@ impl fmt::Display for Entry {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
fn valid_square_matrix() -> Entry {
|
||||
Entry::Matrix(Matrix {
|
||||
@ -266,25 +268,25 @@ mod tests {
|
||||
Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: 2.0_f64 },
|
||||
Number { value: -3.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number { value: dec!(2.0) },
|
||||
Number { value: dec!(-3.0) },
|
||||
],
|
||||
},
|
||||
Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 4.0_f64 },
|
||||
Number { value: -5.0_f64 },
|
||||
Number { value: 0.0_f64 },
|
||||
Number { value: dec!(4.0) },
|
||||
Number { value: dec!(-5.0) },
|
||||
Number { value: dec!(0.0) },
|
||||
],
|
||||
},
|
||||
Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: -7.0_f64 },
|
||||
Number { value: 8.0_f64 },
|
||||
Number { value: 9.0_f64 },
|
||||
Number { value: dec!(-7.0) },
|
||||
Number { value: dec!(8.0) },
|
||||
Number { value: dec!(9.0) },
|
||||
],
|
||||
},
|
||||
],
|
||||
@ -301,25 +303,25 @@ mod tests {
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: -1.0_f64 },
|
||||
Number { value: -2.0_f64 },
|
||||
Number { value: 3.0_f64 },
|
||||
Number { value: dec!(-1.0) },
|
||||
Number { value: dec!(-2.0) },
|
||||
Number { value: dec!(3.0) },
|
||||
],
|
||||
}),
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: -4.0_f64 },
|
||||
Number { value: 5.0_f64 },
|
||||
Number { value: -0.0_f64 },
|
||||
Number { value: dec!(-4.0) },
|
||||
Number { value: dec!(5.0) },
|
||||
Number { value: dec!(-0.0) },
|
||||
],
|
||||
}),
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 7.0_f64 },
|
||||
Number { value: -8.0_f64 },
|
||||
Number { value: -9.0_f64 },
|
||||
Number { value: dec!(7.0) },
|
||||
Number { value: dec!(-8.0) },
|
||||
Number { value: dec!(-9.0) },
|
||||
],
|
||||
}),
|
||||
]),
|
||||
@ -331,25 +333,25 @@ mod tests {
|
||||
// Entry::Vector(Vector {
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number { value: 1.0_f64 },
|
||||
// Number { value: 2.0_f64 },
|
||||
// Number { value: 3.0_f64 },
|
||||
// Number { value: dec!(1.0) },
|
||||
// Number { value: dec!(2.0) },
|
||||
// Number { value: dec!(3.0) },
|
||||
// ],
|
||||
// }),
|
||||
// Entry::Vector(Vector {
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number { value: 4.0_f64 },
|
||||
// Number { value: 5.0_f64 },
|
||||
// Number { value: 0.0_f64 },
|
||||
// Number { value: dec!(4.0) },
|
||||
// Number { value: dec!(5.0) },
|
||||
// Number { value: dec!(0.0) },
|
||||
// ],
|
||||
// }),
|
||||
// Entry::Vector(Vector {
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number { value: 7.0_f64 },
|
||||
// Number { value: 8.0_f64 },
|
||||
// Number { value: 9.0_f64 },
|
||||
// Number { value: dec!(7.0) },
|
||||
// Number { value: dec!(8.0) },
|
||||
// Number { value: dec!(9.0) },
|
||||
// ],
|
||||
// }),
|
||||
// ]),
|
||||
@ -358,23 +360,23 @@ mod tests {
|
||||
// Entry::Vector(Vector {
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number{value: 1.0_f64},
|
||||
// Number{value: 2.0_f64},
|
||||
// Number{value: -3.0_f64},
|
||||
// Number{value: dec!(1.0},)
|
||||
// Number{value: dec!(2.0},)
|
||||
// Number{value: dec!(-3.0},)
|
||||
// ]}),
|
||||
// Entry::Vector (Vector{
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number{value: 4.0_f64},
|
||||
// Number{value: -5.0_f64},
|
||||
// Number{value: 0.0_f64},
|
||||
// Number{value: dec!(4.0},)
|
||||
// Number{value: dec!(-5.0},)
|
||||
// Number{value: dec!(0.0},)
|
||||
// ]}),
|
||||
// Entry::Vector (Vector{
|
||||
// direction: VectorDirection::Column,
|
||||
// values: vec![
|
||||
// Number{value: -7.0_f64},
|
||||
// Number{value: 8.0_f64},
|
||||
// Number{value: 9.0_f64},
|
||||
// Number{value: dec!(-7.0},)
|
||||
// Number{value: dec!(8.0},)
|
||||
// Number{value: dec!(9.0},)
|
||||
// ])),
|
||||
(
|
||||
"transpose",
|
||||
@ -383,25 +385,25 @@ mod tests {
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: 4.0_f64 },
|
||||
Number { value: -7.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number { value: dec!(4.0) },
|
||||
Number { value: dec!(-7.0) },
|
||||
],
|
||||
}),
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 2.0_f64 },
|
||||
Number { value: -5.0_f64 },
|
||||
Number { value: 8.0_f64 },
|
||||
Number { value: dec!(2.0) },
|
||||
Number { value: dec!(-5.0) },
|
||||
Number { value: dec!(8.0) },
|
||||
],
|
||||
}),
|
||||
Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: -3.0_f64 },
|
||||
Number { value: 0.0_f64 },
|
||||
Number { value: 9.0_f64 },
|
||||
Number { value: dec!(-3.0) },
|
||||
Number { value: dec!(0.0) },
|
||||
Number { value: dec!(9.0) },
|
||||
],
|
||||
}),
|
||||
]),
|
||||
@ -416,9 +418,9 @@ mod tests {
|
||||
vectors: vec![Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: 100.0_f64 },
|
||||
Number { value: 64.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number { value: dec!(100.0) },
|
||||
Number { value: dec!(64.0) },
|
||||
],
|
||||
}],
|
||||
})
|
||||
@ -426,9 +428,9 @@ mod tests {
|
||||
Matrix::from(&[Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: 10.0_f64 },
|
||||
Number { value: 8.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number { value: dec!(10.0) },
|
||||
Number { value: dec!(8.0) },
|
||||
],
|
||||
})]),
|
||||
),
|
||||
@ -443,10 +445,10 @@ mod tests {
|
||||
vectors: vec![Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: 100.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number { value: dec!(100.0) },
|
||||
Number {
|
||||
value: 100_000.0_f64,
|
||||
value: dec!(100_000.0),
|
||||
},
|
||||
],
|
||||
}],
|
||||
@ -455,9 +457,9 @@ mod tests {
|
||||
Matrix::from(&[Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 0.0_f64 },
|
||||
Number { value: 2.0_f64 },
|
||||
Number { value: 5.0_f64 },
|
||||
Number { value: dec!(0.0) },
|
||||
Number { value: dec!(2.0) },
|
||||
Number { value: dec!(5.0) },
|
||||
],
|
||||
})]),
|
||||
),
|
||||
@ -471,9 +473,9 @@ mod tests {
|
||||
vectors: vec![Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![
|
||||
Number { value: 1.0_f64 },
|
||||
Number { value: dec!(1.0) },
|
||||
Number {
|
||||
value: std::f64::consts::E,
|
||||
value: constants::E,
|
||||
},
|
||||
],
|
||||
}],
|
||||
@ -481,7 +483,7 @@ mod tests {
|
||||
.ln(),
|
||||
Matrix::from(&[Entry::Vector(Vector {
|
||||
direction: VectorDirection::Column,
|
||||
values: vec![Number { value: 0.0_f64 }, Number { value: 1.0_f64 }],
|
||||
values: vec![Number { value: dec!(0.0) }, Number { value: dec!(1.0) }],
|
||||
})]),
|
||||
),
|
||||
] {
|
||||
|
@ -1,34 +1,27 @@
|
||||
use super::{Entry, Matrix, Vector};
|
||||
use crate::calc::{
|
||||
use crate::{
|
||||
calc::{
|
||||
entries::CalculatorEntry,
|
||||
errors::{CalculatorError, CalculatorResult},
|
||||
types::{CalculatorAngleMode, CalculatorDisplayMode},
|
||||
},
|
||||
constants,
|
||||
};
|
||||
use rust_decimal::{Decimal, MathematicalOps};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Number {
|
||||
pub value: f64,
|
||||
pub value: Decimal,
|
||||
}
|
||||
|
||||
impl PartialEq for Number {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.value.is_nan() && other.value.is_nan()
|
||||
|| self.value.is_infinite() && other.value.is_infinite()
|
||||
{
|
||||
true
|
||||
} else if self.value.is_nan()
|
||||
|| self.value.is_infinite()
|
||||
|| other.value.is_infinite()
|
||||
|| other.value.is_nan()
|
||||
{
|
||||
false
|
||||
} else {
|
||||
(self.value - other.value).abs() < f64::EPSILON
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl PartialEq for Number {
|
||||
// fn eq(&self, other: &Self) -> bool {
|
||||
// (self.value - other.value).abs() < f64::EPSILON
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl CalculatorEntry for Number {
|
||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||
@ -46,7 +39,7 @@ impl CalculatorEntry for Number {
|
||||
}
|
||||
}
|
||||
fn is_valid(&self) -> bool {
|
||||
!self.value.is_nan() && !self.value.is_infinite()
|
||||
true
|
||||
}
|
||||
fn validate(self) -> CalculatorResult<Entry> {
|
||||
if self.is_valid() {
|
||||
@ -66,7 +59,9 @@ impl CalculatorEntry for Number {
|
||||
}
|
||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value.recip(),
|
||||
value: constants::ONE
|
||||
.checked_div(self.value)
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
@ -76,70 +71,103 @@ impl CalculatorEntry for Number {
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
|
||||
CalculatorAngleMode::Radians => self.value.sin(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).sin(),
|
||||
CalculatorAngleMode::Degrees => (self.value * constants::DEC_TO_RAD_MULTIPLIER)
|
||||
.checked_sin()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Radians => self
|
||||
.value
|
||||
.checked_sin()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Grads => (self.value * constants::GRAD_TO_RAD_MULTIPLIER)
|
||||
.checked_sin()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
|
||||
CalculatorAngleMode::Radians => self.value.cos(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).cos(),
|
||||
CalculatorAngleMode::Degrees => (self.value * constants::DEC_TO_RAD_MULTIPLIER)
|
||||
.checked_cos()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Radians => self
|
||||
.value
|
||||
.checked_cos()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Grads => (self.value * constants::GRAD_TO_RAD_MULTIPLIER)
|
||||
.checked_cos()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
|
||||
CalculatorAngleMode::Radians => self.value.tan(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).tan(),
|
||||
CalculatorAngleMode::Degrees => (self.value * constants::DEC_TO_RAD_MULTIPLIER)
|
||||
.checked_tan()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Radians => self
|
||||
.value
|
||||
.checked_tan()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
CalculatorAngleMode::Grads => (self.value * constants::GRAD_TO_RAD_MULTIPLIER)
|
||||
.checked_tan()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.asin(),
|
||||
CalculatorAngleMode::Grads => self.value.asin() * 200.0 / std::f64::consts::PI,
|
||||
},
|
||||
}))
|
||||
fn asin(&self, _angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
// TODO: Implement this
|
||||
Err(CalculatorError::NotYetImplemented)
|
||||
// Ok(Entry::Number(Self {
|
||||
// value: match angle_mode {
|
||||
// CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
||||
// CalculatorAngleMode::Radians => self.value.asin(),
|
||||
// CalculatorAngleMode::Grads => self.value.asin() * 200.0 / std::f64::consts::PI,
|
||||
// },
|
||||
// }))
|
||||
}
|
||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.acos(),
|
||||
CalculatorAngleMode::Grads => self.value.acos() * 200.0 / std::f64::consts::PI,
|
||||
},
|
||||
}))
|
||||
fn acos(&self, _angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
// TODO: Implement this
|
||||
Err(CalculatorError::NotYetImplemented)
|
||||
// Ok(Entry::Number(Self {
|
||||
// value: match angle_mode {
|
||||
// CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
|
||||
// CalculatorAngleMode::Radians => self.value.acos(),
|
||||
// CalculatorAngleMode::Grads => self.value.acos() * 200.0 / std::f64::consts::PI,
|
||||
// },
|
||||
// }))
|
||||
}
|
||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.atan(),
|
||||
CalculatorAngleMode::Grads => self.value.atan() * 200.0 / std::f64::consts::PI,
|
||||
},
|
||||
}))
|
||||
fn atan(&self, _angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
// TODO: Implement this
|
||||
Err(CalculatorError::NotYetImplemented)
|
||||
// Ok(Entry::Number(Self {
|
||||
// value: match angle_mode {
|
||||
// CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
|
||||
// CalculatorAngleMode::Radians => self.value.atan(),
|
||||
// CalculatorAngleMode::Grads => self.value.atan() * 200.0 / std::f64::consts::PI,
|
||||
// },
|
||||
// }))
|
||||
}
|
||||
fn sqrt(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.sqrt(),
|
||||
value: self.value.sqrt().ok_or(CalculatorError::ArithmeticError)?,
|
||||
}))
|
||||
}
|
||||
fn log(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.log10(),
|
||||
value: self
|
||||
.value
|
||||
.checked_log10()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
}))
|
||||
}
|
||||
fn ln(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.ln(),
|
||||
value: self
|
||||
.value
|
||||
.checked_ln()
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -187,8 +215,20 @@ impl CalculatorEntry for Number {
|
||||
match arg {
|
||||
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::int_divide),
|
||||
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::int_divide),
|
||||
Entry::Number(number) => Self {
|
||||
value: self.value.div_euclid(number.value),
|
||||
Entry::Number(number) => {
|
||||
let q = (self.value / number.value).trunc();
|
||||
Self {
|
||||
// Implementation based on https://doc.rust-lang.org/src/std/f64.rs.html#263-269
|
||||
value: if self.value % number.value < constants::ZERO {
|
||||
if number.value > constants::ZERO {
|
||||
q - constants::ONE
|
||||
} else {
|
||||
q + constants::ONE
|
||||
}
|
||||
} else {
|
||||
q
|
||||
},
|
||||
}
|
||||
}
|
||||
.validate(),
|
||||
}
|
||||
@ -208,7 +248,10 @@ impl CalculatorEntry for Number {
|
||||
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::pow),
|
||||
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::pow),
|
||||
Entry::Number(number) => Self {
|
||||
value: self.value.powf(number.value),
|
||||
value: self
|
||||
.value
|
||||
.checked_powd(number.value)
|
||||
.ok_or(CalculatorError::ArithmeticError)?,
|
||||
}
|
||||
.validate(),
|
||||
}
|
||||
@ -216,7 +259,9 @@ impl CalculatorEntry for Number {
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub const ZERO: Self = Self { value: 0.0_f64 };
|
||||
pub const ZERO: Self = Self {
|
||||
value: constants::ZERO,
|
||||
};
|
||||
|
||||
fn iterated_binary_vec(
|
||||
self,
|
||||
@ -266,7 +311,7 @@ impl fmt::Display for Number {
|
||||
}
|
||||
|
||||
// Based on https://stackoverflow.com/a/65266882
|
||||
fn scientific(f: f64, precision: usize) -> String {
|
||||
fn scientific(f: Decimal, precision: usize) -> String {
|
||||
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
||||
let exp = ret.split_off(ret.find('E').unwrap_or(0));
|
||||
let (exp_sign, exp) = exp
|
||||
@ -277,7 +322,7 @@ fn scientific(f: f64, precision: usize) -> String {
|
||||
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
|
||||
}
|
||||
|
||||
fn engineering(f: f64, precision: usize) -> String {
|
||||
fn engineering(f: Decimal, precision: usize) -> String {
|
||||
// Format the string so the first digit is always in the first column, and remove '.'. Requested precision + 2 to account for using 1, 2, or 3 digits for the whole portion of the string
|
||||
// 1,000 => 1000E3
|
||||
let all = format!(" {:.precision$E}", f, precision = precision)
|
||||
@ -328,7 +373,7 @@ fn engineering(f: f64, precision: usize) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn separated(f: f64, sep: char) -> String {
|
||||
fn separated(f: Decimal, sep: char) -> String {
|
||||
let mut ret = f.to_string();
|
||||
let start = if ret.starts_with('-') { 1 } else { 0 };
|
||||
let end = ret.find('.').unwrap_or_else(|| ret.len());
|
||||
|
@ -1,8 +1,11 @@
|
||||
use super::{Entry, Matrix, Number};
|
||||
use crate::calc::{
|
||||
use crate::{
|
||||
calc::{
|
||||
entries::CalculatorEntry,
|
||||
errors::{CalculatorError, CalculatorResult},
|
||||
types::{CalculatorAngleMode, CalculatorDisplayMode},
|
||||
},
|
||||
constants,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -74,11 +77,13 @@ impl CalculatorEntry for Vector {
|
||||
self.iterated_unary(Number::negate)
|
||||
}
|
||||
fn abs(&self) -> CalculatorResult<Entry> {
|
||||
let value: Entry = self
|
||||
.values
|
||||
let value: Entry =
|
||||
self.values
|
||||
.iter()
|
||||
.try_fold(Entry::Number(Number::ZERO), |acc, n2| {
|
||||
acc.add(&n2.pow(&Entry::Number(Number { value: 2.0_f64 }))?)
|
||||
acc.add(&n2.pow(&Entry::Number(Number {
|
||||
value: constants::TWO,
|
||||
}))?)
|
||||
})?;
|
||||
value.sqrt()
|
||||
}
|
||||
|
26
src/constants.rs
Normal file
26
src/constants.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
pub const ZERO: Decimal = Decimal::ZERO;
|
||||
pub const ONE: Decimal = Decimal::ONE;
|
||||
pub const TWO: Decimal = Decimal::TWO;
|
||||
|
||||
pub const PI: Decimal = Decimal::PI;
|
||||
pub const E: Decimal = Decimal::E;
|
||||
pub const TAU: Decimal = Decimal::TWO_PI;
|
||||
|
||||
pub const RAD_TO_DEC_MULTIPLIER: Decimal = dec!(57.295779513082320876798154814);
|
||||
pub const DEC_TO_RAD_MULTIPLIER: Decimal = dec!(0.0174532925199432957692369077);
|
||||
pub const GRAD_TO_RAD_MULTIPLIER: Decimal = dec!(0.0157079632679489661923132169);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_constants() {
|
||||
assert_eq!(RAD_TO_DEC_MULTIPLIER, dec!(180.0) / PI);
|
||||
assert_eq!(DEC_TO_RAD_MULTIPLIER, PI / dec!(180.0));
|
||||
assert_eq!(GRAD_TO_RAD_MULTIPLIER, PI / dec!(200.0));
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod calc;
|
||||
pub mod constants;
|
||||
pub mod event;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![allow(clippy::multiple_crate_versions)]
|
||||
|
||||
mod calc;
|
||||
mod constants;
|
||||
mod event;
|
||||
|
||||
const BORDER_SIZE: u16 = 2;
|
||||
|
Loading…
Reference in New Issue
Block a user