mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-11-07 16:34:21 +01:00
Created a cargo feature for rug
, f64 will be used instead if it's disabled
This commit is contained in:
parent
e8c362c72e
commit
8014a61f1a
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -158,6 +158,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"rug",
|
||||
"special",
|
||||
"test-case",
|
||||
]
|
||||
|
||||
@ -328,6 +329,15 @@ version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
||||
|
||||
[[package]]
|
||||
name = "special"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24a65e074159b75dcf173a4733ab2188baac24967b5c8ec9ed87ae15fcbc7636"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.54"
|
||||
|
@ -11,7 +11,11 @@ keywords = ["math", "calculator", "evaluator"]
|
||||
categories = ["mathematics", "parser-implementations"]
|
||||
|
||||
[dependencies]
|
||||
rug = { version = "1.11.0", features = ["float"] }
|
||||
rug = { version = "1.11.0", features = ["float"], optional = true }
|
||||
test-case = "1.0.0"
|
||||
regex = "1"
|
||||
lazy_static = "1.4.0"
|
||||
special = "0.8.1"
|
||||
|
||||
[features]
|
||||
default = ["rug"]
|
@ -22,8 +22,12 @@ f(a, 2)
|
||||
use kalk::parser;
|
||||
let mut parser_context = parser::Context::new();
|
||||
let precision = 53;
|
||||
assert_eq!(parser::eval(&mut parser_context, "5*3", precision).unwrap().unwrap(), 15);
|
||||
let result = parser::eval(&mut parser_context, "5*3", precision).unwrap().unwrap();
|
||||
assert_eq!(result.to_f64(), 15f64);
|
||||
```
|
||||
|
||||
## Using f64 instead of rug::Float
|
||||
The cargo feature `rug` enables rug, and is used by default. If you disalbe this, kalk will use `f64` instead, making it more portable.
|
||||
|
||||
## Compiling
|
||||
Make sure you have `diffutils` `gcc` `make` and `m4` installed.
|
||||
|
@ -5,11 +5,11 @@ use crate::parser::CalcError;
|
||||
use crate::parser::DECL_UNIT;
|
||||
use crate::prelude;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use rug::Float;
|
||||
|
||||
pub struct Context<'a> {
|
||||
symbol_table: &'a mut SymbolTable,
|
||||
angle_unit: String,
|
||||
#[cfg(feature = "rug")]
|
||||
precision: u32,
|
||||
sum_n_value: Option<i128>,
|
||||
timeout: Option<u32>,
|
||||
@ -20,12 +20,13 @@ impl<'a> Context<'a> {
|
||||
pub fn new(
|
||||
symbol_table: &'a mut SymbolTable,
|
||||
angle_unit: &str,
|
||||
precision: u32,
|
||||
#[cfg(feature = "rug")] precision: u32,
|
||||
timeout: Option<u32>,
|
||||
) -> Self {
|
||||
Context {
|
||||
angle_unit: angle_unit.into(),
|
||||
symbol_table,
|
||||
#[cfg(feature = "rug")]
|
||||
precision,
|
||||
sum_n_value: None,
|
||||
timeout: timeout,
|
||||
@ -43,14 +44,11 @@ impl<'a> Context<'a> {
|
||||
String::from("ans"),
|
||||
Box::new(Expr::Unit(
|
||||
num.unit.clone(),
|
||||
Box::new(Expr::Literal(num.value.to_f64())),
|
||||
Box::new(Expr::Literal(num.to_f64())),
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
Stmt::VarDecl(
|
||||
String::from("ans"),
|
||||
Box::new(Expr::Literal(num.value.to_f64())),
|
||||
)
|
||||
Stmt::VarDecl(String::from("ans"), Box::new(Expr::Literal(num.to_f64())))
|
||||
});
|
||||
|
||||
if i == statements.len() - 1 {
|
||||
@ -165,10 +163,7 @@ fn eval_unary_expr(
|
||||
TokenKind::Minus => Ok(KalkNum::new(-num.value, &num.unit)),
|
||||
TokenKind::Percent => Ok(KalkNum::new(num.value * 0.01, unit)),
|
||||
TokenKind::Exclamation => Ok(KalkNum::new(
|
||||
Float::with_val(
|
||||
context.precision,
|
||||
prelude::special_funcs::factorial(num.value),
|
||||
),
|
||||
prelude::special_funcs::factorial(num.value),
|
||||
unit,
|
||||
)),
|
||||
_ => Err(CalcError::InvalidOperator),
|
||||
@ -234,11 +229,15 @@ fn eval_var_expr(
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn eval_literal_expr(context: &mut Context, value: f64, unit: &str) -> Result<KalkNum, CalcError> {
|
||||
Ok(KalkNum::new(
|
||||
Float::with_val(context.precision, value),
|
||||
unit.into(),
|
||||
))
|
||||
let mut num: KalkNum = value.into();
|
||||
num.unit = unit.into();
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
num.value.set_prec(context.precision);
|
||||
|
||||
Ok(num)
|
||||
}
|
||||
|
||||
fn eval_group_expr(context: &mut Context, expr: &Expr, unit: &str) -> Result<KalkNum, CalcError> {
|
||||
@ -286,16 +285,17 @@ fn eval_fn_call_expr(
|
||||
|
||||
let start = eval_expr(context, &expressions[0], "")?.to_f64() as i128;
|
||||
let end = eval_expr(context, &expressions[1], "")?.to_f64() as i128;
|
||||
let mut sum = Float::with_val(context.precision, 0);
|
||||
let mut sum = KalkNum::default();
|
||||
|
||||
for n in start..=end {
|
||||
context.sum_n_value = Some(n);
|
||||
sum += eval_expr(context, &expressions[2], "")?.value;
|
||||
sum.value += eval_expr(context, &expressions[2], "")?.value;
|
||||
}
|
||||
|
||||
context.sum_n_value = None;
|
||||
sum.unit = unit.into();
|
||||
|
||||
return Ok(KalkNum::new(sum, unit.into()));
|
||||
return Ok(sum);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -334,8 +334,6 @@ mod tests {
|
||||
use crate::test_helpers::*;
|
||||
use test_case::test_case;
|
||||
|
||||
const PRECISION: u32 = 53;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEG_RAD_UNIT: Stmt = unit_decl(
|
||||
"deg",
|
||||
@ -367,8 +365,7 @@ mod tests {
|
||||
.insert(DEG_RAD_UNIT.clone())
|
||||
.insert(RAD_DEG_UNIT.clone());
|
||||
|
||||
let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None);
|
||||
context.interpret(vec![stmt])
|
||||
context(&mut symbol_table, "rad").interpret(vec![stmt])
|
||||
}
|
||||
|
||||
fn interpret(stmt: Stmt) -> Result<Option<KalkNum>, CalcError> {
|
||||
@ -379,6 +376,16 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: &str) -> Context<'a> {
|
||||
Context::new(symbol_table, angle_unit, 63, None)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rug"))]
|
||||
fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: &str) -> Context<'a> {
|
||||
Context::new(symbol_table, angle_unit, None)
|
||||
}
|
||||
|
||||
fn cmp(x: KalkNum, y: f64) -> bool {
|
||||
println!("{} = {}", x.to_f64(), y);
|
||||
(x.to_f64() - y).abs() < 0.0001
|
||||
@ -443,8 +450,8 @@ mod tests {
|
||||
deg_symbol_table
|
||||
.insert(DEG_RAD_UNIT.clone())
|
||||
.insert(RAD_DEG_UNIT.clone());
|
||||
let mut rad_context = Context::new(&mut rad_symbol_table, "rad", PRECISION, None);
|
||||
let mut deg_context = Context::new(&mut deg_symbol_table, "deg", PRECISION, None);
|
||||
let mut rad_context = context(&mut rad_symbol_table, "rad");
|
||||
let mut deg_context = context(&mut deg_symbol_table, "deg");
|
||||
|
||||
assert!(cmp(
|
||||
rad_context
|
||||
@ -467,7 +474,7 @@ mod tests {
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
symbol_table.insert(var_decl("x", literal(1f64)));
|
||||
|
||||
let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None);
|
||||
let mut context = context(&mut symbol_table, "rad");
|
||||
assert_eq!(
|
||||
context.interpret(vec![stmt]).unwrap().unwrap().to_f64(),
|
||||
1f64
|
||||
@ -488,7 +495,7 @@ mod tests {
|
||||
fn test_var_decl() {
|
||||
let stmt = var_decl("x", literal(1f64));
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
Context::new(&mut symbol_table, "rad", PRECISION, None)
|
||||
context(&mut symbol_table, "rad")
|
||||
.interpret(vec![stmt])
|
||||
.unwrap();
|
||||
|
||||
@ -507,7 +514,7 @@ mod tests {
|
||||
binary(var("x"), TokenKind::Plus, literal(2f64)),
|
||||
));
|
||||
|
||||
let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None);
|
||||
let mut context = context(&mut symbol_table, "rad");
|
||||
assert_eq!(
|
||||
context.interpret(vec![stmt]).unwrap().unwrap().to_f64(),
|
||||
3f64
|
||||
|
9
kalk/src/kalk_num/mod.rs
Normal file
9
kalk/src/kalk_num/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[cfg(feature = "rug")]
|
||||
pub mod with_rug;
|
||||
#[cfg(feature = "rug")]
|
||||
pub use with_rug::*;
|
||||
|
||||
#[cfg(not(feature = "rug"))]
|
||||
pub mod regular;
|
||||
#[cfg(not(feature = "rug"))]
|
||||
pub use regular::*;
|
184
kalk/src/kalk_num/regular.rs
Normal file
184
kalk/src/kalk_num/regular.rs
Normal file
@ -0,0 +1,184 @@
|
||||
use crate::ast::Expr;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Default)]
|
||||
pub struct KalkNum {
|
||||
pub(crate) value: f64,
|
||||
pub(crate) unit: String,
|
||||
}
|
||||
|
||||
pub struct ScientificNotation {
|
||||
pub negative: bool,
|
||||
pub digits: String,
|
||||
pub exponent: i32,
|
||||
}
|
||||
|
||||
impl ScientificNotation {
|
||||
pub fn to_string(&self) -> String {
|
||||
let sign = if self.negative { "-" } else { "" };
|
||||
let mut digits_and_mul = if self.digits == "1" {
|
||||
String::new()
|
||||
} else {
|
||||
format!("{}*", &self.digits)
|
||||
};
|
||||
|
||||
if self.digits.len() > 1 {
|
||||
digits_and_mul.insert(1usize, '.');
|
||||
}
|
||||
|
||||
format!("{}{}10^{}", sign, digits_and_mul, self.exponent - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl KalkNum {
|
||||
pub fn new(value: f64, unit: &str) -> Self {
|
||||
Self {
|
||||
value,
|
||||
unit: unit.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_f64(&self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
pub fn to_string_big(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
pub fn is_too_big(&self) -> bool {
|
||||
self.value.is_infinite()
|
||||
}
|
||||
|
||||
pub fn to_string_with_unit(&self) -> String {
|
||||
format!("{} {}", self.to_string(), self.unit)
|
||||
}
|
||||
|
||||
pub fn get_unit(&self) -> &str {
|
||||
&self.unit
|
||||
}
|
||||
|
||||
pub fn has_unit(&self) -> bool {
|
||||
self.unit.len() > 0
|
||||
}
|
||||
|
||||
pub fn to_scientific_notation(&self) -> ScientificNotation {
|
||||
ScientificNotation {
|
||||
negative: self.value < 0f64,
|
||||
digits: self.value.to_string().replace(".", ""),
|
||||
exponent: self.value.log(10f64) as i32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_unit(
|
||||
&self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
to_unit: &str,
|
||||
) -> Option<KalkNum> {
|
||||
let result = crate::interpreter::convert_unit(
|
||||
context,
|
||||
&Expr::Literal(self.value),
|
||||
&self.unit,
|
||||
to_unit,
|
||||
);
|
||||
|
||||
if let Ok(num) = result {
|
||||
Some(num)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value + right.value, &right.unit)
|
||||
}
|
||||
|
||||
pub fn sub(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value - right.value, &right.unit)
|
||||
}
|
||||
|
||||
pub fn mul(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value * right.value, &right.unit)
|
||||
}
|
||||
|
||||
pub fn div(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value / right.value, &right.unit)
|
||||
}
|
||||
|
||||
pub fn rem(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value % right.value, &right.unit)
|
||||
}
|
||||
|
||||
pub fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
KalkNum::new(self.value.powf(right.value), &right.unit)
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_unit(
|
||||
context: &mut crate::interpreter::Context,
|
||||
left: &KalkNum,
|
||||
right: KalkNum,
|
||||
) -> Option<KalkNum> {
|
||||
if left.has_unit() && right.has_unit() {
|
||||
right.convert_to_unit(context, &left.unit)
|
||||
} else {
|
||||
Some(KalkNum::new(right.value, &left.unit))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for ScientificNotation {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for KalkNum {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for KalkNum {
|
||||
fn into(self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for KalkNum {
|
||||
fn from(x: f64) -> Self {
|
||||
KalkNum::new(x, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for KalkNum {
|
||||
fn from(x: f32) -> Self {
|
||||
KalkNum::new(x as f64, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i128> for KalkNum {
|
||||
fn from(x: i128) -> Self {
|
||||
KalkNum::new(x as f64, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for KalkNum {
|
||||
fn from(x: i64) -> Self {
|
||||
KalkNum::new(x as f64, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for KalkNum {
|
||||
fn from(x: i32) -> Self {
|
||||
KalkNum::new(x as f64, "")
|
||||
}
|
||||
}
|
@ -2,6 +2,12 @@ use crate::ast::Expr;
|
||||
use rug::ops::Pow;
|
||||
use rug::Float;
|
||||
|
||||
impl Default for KalkNum {
|
||||
fn default() -> Self {
|
||||
KalkNum::new(Float::with_val(63, 0), "")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct KalkNum {
|
||||
pub(crate) value: Float,
|
@ -11,14 +11,6 @@ pub const DECL_UNIT: &'static str = ".u";
|
||||
pub const DEFAULT_ANGLE_UNIT: &'static str = "rad";
|
||||
|
||||
/// Struct containing the current state of the parser. It stores user-defined functions and variables.
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use kalk::parser;
|
||||
/// let mut parser_context = parser::Context::new();
|
||||
/// let precision = 53;
|
||||
/// let result = parser::eval(&mut parser_context, "5*3", precision).unwrap().unwrap();
|
||||
/// assert_eq!(result.to_f64(), 15f64);
|
||||
/// ```
|
||||
pub struct Context {
|
||||
tokens: Vec<Token>,
|
||||
pos: usize,
|
||||
@ -100,7 +92,7 @@ pub enum CalcError {
|
||||
pub fn eval(
|
||||
context: &mut Context,
|
||||
input: &str,
|
||||
precision: u32,
|
||||
#[cfg(feature = "rug")] precision: u32,
|
||||
) -> Result<Option<KalkNum>, CalcError> {
|
||||
context.contains_equal_sign = input.contains("=");
|
||||
let statements = parse(context, input)?;
|
||||
@ -108,6 +100,7 @@ pub fn eval(
|
||||
let mut interpreter = interpreter::Context::new(
|
||||
&mut context.symbol_table,
|
||||
&context.angle_unit,
|
||||
#[cfg(feature = "rug")]
|
||||
precision,
|
||||
context.timeout,
|
||||
);
|
||||
|
113
kalk/src/prelude/mod.rs
Normal file
113
kalk/src/prelude/mod.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::HashMap;
|
||||
use FuncType::*;
|
||||
|
||||
pub const INIT: &'static str = "unit deg = (rad*180)/pi";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CONSTANTS: HashMap<&'static str, f64> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(
|
||||
"pi",
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923,
|
||||
);
|
||||
m.insert(
|
||||
"π",
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923,
|
||||
);
|
||||
m.insert(
|
||||
"e",
|
||||
2.7182818284590452353602874713526624977572470936999595749669676277,
|
||||
);
|
||||
m.insert(
|
||||
"tau",
|
||||
6.2831853071795864769252867665590057683943387987502116419498891846,
|
||||
);
|
||||
m.insert(
|
||||
"τ",
|
||||
6.2831853071795864769252867665590057683943387987502116419498891846,
|
||||
);
|
||||
m.insert(
|
||||
"phi",
|
||||
1.6180339887498948482045868343656381177203091798057628621354486227,
|
||||
);
|
||||
m.insert(
|
||||
"ϕ",
|
||||
1.6180339887498948482045868343656381177203091798057628621354486227,
|
||||
);
|
||||
m
|
||||
};
|
||||
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("cos", (UnaryFuncInfo(cos, Trig), ""));
|
||||
m.insert("cosec", (UnaryFuncInfo(cosec, Trig), ""));
|
||||
m.insert("cosech", (UnaryFuncInfo(cosech, Trig), ""));
|
||||
m.insert("cosh", (UnaryFuncInfo(cosh, Trig), ""));
|
||||
m.insert("cot", (UnaryFuncInfo(cot, Trig), ""));
|
||||
m.insert("coth", (UnaryFuncInfo(coth, Trig), ""));
|
||||
m.insert("sec", (UnaryFuncInfo(sec, Trig), ""));
|
||||
m.insert("sech", (UnaryFuncInfo(sech, Trig), ""));
|
||||
m.insert("sin", (UnaryFuncInfo(sin, Trig), ""));
|
||||
m.insert("sinh", (UnaryFuncInfo(sinh, Trig), ""));
|
||||
m.insert("tan", (UnaryFuncInfo(tan, Trig), ""));
|
||||
m.insert("tanh", (UnaryFuncInfo(tanh, Trig), ""));
|
||||
|
||||
m.insert("acos", (UnaryFuncInfo(acos, InverseTrig), "rad"));
|
||||
m.insert("acosec", (UnaryFuncInfo(acosec, InverseTrig), "rad"));
|
||||
m.insert("acosech", (UnaryFuncInfo(acosech, InverseTrig), "rad"));
|
||||
m.insert("acosh", (UnaryFuncInfo(acosh, InverseTrig), "rad"));
|
||||
m.insert("acot", (UnaryFuncInfo(acot, InverseTrig), "rad"));
|
||||
m.insert("acoth", (UnaryFuncInfo(acoth, InverseTrig), "rad"));
|
||||
m.insert("asec", (UnaryFuncInfo(asec, InverseTrig), "rad"));
|
||||
m.insert("asech", (UnaryFuncInfo(asech, InverseTrig), "rad"));
|
||||
m.insert("asin", (UnaryFuncInfo(asin, InverseTrig), "rad"));
|
||||
m.insert("asinh", (UnaryFuncInfo(asinh, InverseTrig), "rad"));
|
||||
m.insert("atan", (UnaryFuncInfo(atan, InverseTrig), "rad"));
|
||||
m.insert("atanh", (UnaryFuncInfo(atanh, InverseTrig), "rad"));
|
||||
|
||||
m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
|
||||
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
|
||||
m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
|
||||
m.insert("exp", (UnaryFuncInfo(exp, Other), ""));
|
||||
m.insert("floor", (UnaryFuncInfo(floor, Other), ""));
|
||||
m.insert("frac", (UnaryFuncInfo(frac, Other), ""));
|
||||
m.insert("gamma", (UnaryFuncInfo(gamma, Other), ""));
|
||||
m.insert("Γ", (UnaryFuncInfo(gamma, Other), ""));
|
||||
m.insert("log", (UnaryFuncInfo(log, Other), ""));
|
||||
m.insert("ln", (UnaryFuncInfo(ln, Other), ""));
|
||||
m.insert("round", (UnaryFuncInfo(round, Other), ""));
|
||||
m.insert("sqrt", (UnaryFuncInfo(sqrt, Other), ""));
|
||||
m.insert("√", (UnaryFuncInfo(sqrt, Other), ""));
|
||||
m.insert("trunc", (UnaryFuncInfo(trunc, Other), ""));
|
||||
m
|
||||
};
|
||||
pub static ref BINARY_FUNCS: HashMap<&'static str, (BinaryFuncInfo, &'static str)> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("max", (BinaryFuncInfo(max, Other), ""));
|
||||
m.insert("min", (BinaryFuncInfo(min, Other), ""));
|
||||
m.insert("hyp", (BinaryFuncInfo(hyp, Other), ""));
|
||||
m.insert("log", (BinaryFuncInfo(logx, Other), ""));
|
||||
m.insert("root", (BinaryFuncInfo(nth_root, Other), ""));
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
enum FuncType {
|
||||
Trig,
|
||||
InverseTrig,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
pub mod with_rug;
|
||||
#[cfg(feature = "rug")]
|
||||
pub use with_rug::funcs::*;
|
||||
#[cfg(feature = "rug")]
|
||||
pub use with_rug::*;
|
||||
|
||||
#[cfg(not(feature = "rug"))]
|
||||
pub mod regular;
|
||||
#[cfg(not(feature = "rug"))]
|
||||
pub use regular::funcs::*;
|
||||
#[cfg(not(feature = "rug"))]
|
||||
pub use regular::*;
|
267
kalk/src/prelude/regular.rs
Normal file
267
kalk/src/prelude/regular.rs
Normal file
@ -0,0 +1,267 @@
|
||||
use super::*;
|
||||
use crate::ast::Expr;
|
||||
use crate::interpreter;
|
||||
|
||||
// Unary functions
|
||||
pub struct UnaryFuncInfo(pub(super) fn(f64) -> f64, pub(super) FuncType);
|
||||
|
||||
pub struct BinaryFuncInfo(pub(super) fn(f64, f64) -> f64, pub(super) FuncType);
|
||||
|
||||
impl UnaryFuncInfo {
|
||||
fn call(&self, context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
||||
let func = self.0;
|
||||
match self.1 {
|
||||
FuncType::Trig => func(from_angle_unit(context, x, angle_unit)),
|
||||
FuncType::InverseTrig => to_angle_unit(context, func(x), angle_unit),
|
||||
FuncType::Other => func(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryFuncInfo {
|
||||
fn call(&self, context: &mut interpreter::Context, x: f64, y: f64, angle_unit: &str) -> f64 {
|
||||
let func = self.0;
|
||||
match self.1 {
|
||||
FuncType::Trig => func(
|
||||
from_angle_unit(context, x, angle_unit),
|
||||
from_angle_unit(context, y, angle_unit),
|
||||
),
|
||||
FuncType::InverseTrig => to_angle_unit(context, func(x, y), angle_unit),
|
||||
FuncType::Other => func(x, y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_prelude_func(identifier: &str) -> bool {
|
||||
identifier == "sum"
|
||||
|| identifier == "Σ"
|
||||
|| UNARY_FUNCS.contains_key(identifier)
|
||||
|| BINARY_FUNCS.contains_key(identifier)
|
||||
}
|
||||
|
||||
pub fn call_unary_func(
|
||||
context: &mut interpreter::Context,
|
||||
name: &str,
|
||||
x: f64,
|
||||
angle_unit: &str,
|
||||
) -> Option<(f64, String)> {
|
||||
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
|
||||
Some((
|
||||
func_info.call(context, x, &angle_unit),
|
||||
func_unit.to_string(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_binary_func(
|
||||
context: &mut interpreter::Context,
|
||||
name: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
angle_unit: &str,
|
||||
) -> Option<(f64, String)> {
|
||||
if let Some((func_info, func_unit)) = BINARY_FUNCS.get(name) {
|
||||
Some((
|
||||
func_info.call(context, x, y, angle_unit),
|
||||
func_unit.to_string(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn to_angle_unit(context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
||||
match angle_unit {
|
||||
"rad" => x,
|
||||
_ => {
|
||||
interpreter::convert_unit(context, &Expr::Literal(x), "rad", angle_unit)
|
||||
.unwrap()
|
||||
.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_angle_unit(context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
||||
match angle_unit {
|
||||
"rad" => x,
|
||||
_ => {
|
||||
interpreter::convert_unit(context, &Expr::Literal(x), angle_unit, "rad")
|
||||
.unwrap()
|
||||
.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod special_funcs {
|
||||
pub fn factorial(x: f64) -> f64 {
|
||||
special::Gamma::gamma(x + 1f64)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) mod funcs {
|
||||
pub fn abs(x: f64) -> f64 {
|
||||
x.abs()
|
||||
}
|
||||
|
||||
pub fn acos(x: f64) -> f64 {
|
||||
x.acos()
|
||||
}
|
||||
|
||||
pub fn acosh(x: f64) -> f64 {
|
||||
x.acosh()
|
||||
}
|
||||
|
||||
pub fn acot(x: f64) -> f64 {
|
||||
(1f64 / x).atan()
|
||||
}
|
||||
|
||||
pub fn acoth(x: f64) -> f64 {
|
||||
(1f64 / x).atanh()
|
||||
}
|
||||
|
||||
pub fn acosec(x: f64) -> f64 {
|
||||
(1f64 / x).asin()
|
||||
}
|
||||
|
||||
pub fn acosech(x: f64) -> f64 {
|
||||
(1f64 / x).asinh()
|
||||
}
|
||||
|
||||
pub fn asec(x: f64) -> f64 {
|
||||
(1f64 / x).acos()
|
||||
}
|
||||
|
||||
pub fn asech(x: f64) -> f64 {
|
||||
(1f64 / x).acosh()
|
||||
}
|
||||
|
||||
pub fn asin(x: f64) -> f64 {
|
||||
x.asin()
|
||||
}
|
||||
|
||||
pub fn asinh(x: f64) -> f64 {
|
||||
x.asinh()
|
||||
}
|
||||
|
||||
pub fn atan(x: f64) -> f64 {
|
||||
x.atan()
|
||||
}
|
||||
|
||||
pub fn atanh(x: f64) -> f64 {
|
||||
x.atanh()
|
||||
}
|
||||
|
||||
pub fn cbrt(x: f64) -> f64 {
|
||||
x.cbrt()
|
||||
}
|
||||
|
||||
pub fn ceil(x: f64) -> f64 {
|
||||
x.ceil()
|
||||
}
|
||||
|
||||
pub fn cos(x: f64) -> f64 {
|
||||
x.cos()
|
||||
}
|
||||
|
||||
pub fn cosh(x: f64) -> f64 {
|
||||
x.cos()
|
||||
}
|
||||
|
||||
pub fn cosec(x: f64) -> f64 {
|
||||
1f64 / x.sin()
|
||||
}
|
||||
|
||||
pub fn cosech(x: f64) -> f64 {
|
||||
1f64 / x.sinh()
|
||||
}
|
||||
|
||||
pub fn cot(x: f64) -> f64 {
|
||||
x.clone().cos() / x.sin()
|
||||
}
|
||||
|
||||
pub fn coth(x: f64) -> f64 {
|
||||
x.clone().cosh() / x.sinh()
|
||||
}
|
||||
|
||||
pub fn exp(x: f64) -> f64 {
|
||||
x.exp()
|
||||
}
|
||||
|
||||
pub fn floor(x: f64) -> f64 {
|
||||
x.floor()
|
||||
}
|
||||
|
||||
pub fn frac(x: f64) -> f64 {
|
||||
x.fract()
|
||||
}
|
||||
|
||||
pub fn gamma(x: f64) -> f64 {
|
||||
special::Gamma::gamma(x)
|
||||
}
|
||||
|
||||
pub fn hyp(x: f64, y: f64) -> f64 {
|
||||
x.hypot(y)
|
||||
}
|
||||
|
||||
pub fn log(x: f64) -> f64 {
|
||||
x.log10()
|
||||
}
|
||||
|
||||
pub fn logx(x: f64, y: f64) -> f64 {
|
||||
x.log10() / y.log10()
|
||||
}
|
||||
|
||||
pub fn ln(x: f64) -> f64 {
|
||||
x.ln()
|
||||
}
|
||||
|
||||
pub fn max(x: f64, y: f64) -> f64 {
|
||||
x.max(y)
|
||||
}
|
||||
|
||||
pub fn min(x: f64, y: f64) -> f64 {
|
||||
x.min(y)
|
||||
}
|
||||
|
||||
pub fn round(x: f64) -> f64 {
|
||||
x.round()
|
||||
}
|
||||
|
||||
pub fn sec(x: f64) -> f64 {
|
||||
1f64 / x.cos()
|
||||
}
|
||||
|
||||
pub fn sech(x: f64) -> f64 {
|
||||
1f64 / x.cosh()
|
||||
}
|
||||
|
||||
pub fn sin(x: f64) -> f64 {
|
||||
x.sin()
|
||||
}
|
||||
|
||||
pub fn sinh(x: f64) -> f64 {
|
||||
x.sinh()
|
||||
}
|
||||
|
||||
pub fn sqrt(x: f64) -> f64 {
|
||||
x.sqrt()
|
||||
}
|
||||
|
||||
pub fn nth_root(x: f64, n: f64) -> f64 {
|
||||
x.powf(1f64 / n)
|
||||
}
|
||||
|
||||
pub fn tan(x: f64) -> f64 {
|
||||
x.tan()
|
||||
}
|
||||
|
||||
pub fn tanh(x: f64) -> f64 {
|
||||
x.tanh()
|
||||
}
|
||||
|
||||
pub fn trunc(x: f64) -> f64 {
|
||||
x.trunc()
|
||||
}
|
||||
}
|
@ -1,111 +1,12 @@
|
||||
use super::*;
|
||||
use crate::ast::Expr;
|
||||
use crate::interpreter;
|
||||
use funcs::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rug::Float;
|
||||
use std::collections::HashMap;
|
||||
use FuncType::*;
|
||||
|
||||
pub const INIT: &'static str = "unit deg = (rad*180)/pi";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CONSTANTS: HashMap<&'static str, f64> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(
|
||||
"pi",
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923,
|
||||
);
|
||||
m.insert(
|
||||
"π",
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923,
|
||||
);
|
||||
m.insert(
|
||||
"e",
|
||||
2.7182818284590452353602874713526624977572470936999595749669676277,
|
||||
);
|
||||
m.insert(
|
||||
"tau",
|
||||
6.2831853071795864769252867665590057683943387987502116419498891846,
|
||||
);
|
||||
m.insert(
|
||||
"τ",
|
||||
6.2831853071795864769252867665590057683943387987502116419498891846,
|
||||
);
|
||||
m.insert(
|
||||
"phi",
|
||||
1.6180339887498948482045868343656381177203091798057628621354486227,
|
||||
);
|
||||
m.insert(
|
||||
"ϕ",
|
||||
1.6180339887498948482045868343656381177203091798057628621354486227,
|
||||
);
|
||||
m
|
||||
};
|
||||
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("cos", (UnaryFuncInfo(cos, Trig), ""));
|
||||
m.insert("cosec", (UnaryFuncInfo(cosec, Trig), ""));
|
||||
m.insert("cosech", (UnaryFuncInfo(cosech, Trig), ""));
|
||||
m.insert("cosh", (UnaryFuncInfo(cosh, Trig), ""));
|
||||
m.insert("cot", (UnaryFuncInfo(cot, Trig), ""));
|
||||
m.insert("coth", (UnaryFuncInfo(coth, Trig), ""));
|
||||
m.insert("sec", (UnaryFuncInfo(sec, Trig), ""));
|
||||
m.insert("sech", (UnaryFuncInfo(sech, Trig), ""));
|
||||
m.insert("sin", (UnaryFuncInfo(sin, Trig), ""));
|
||||
m.insert("sinh", (UnaryFuncInfo(sinh, Trig), ""));
|
||||
m.insert("tan", (UnaryFuncInfo(tan, Trig), ""));
|
||||
m.insert("tanh", (UnaryFuncInfo(tanh, Trig), ""));
|
||||
|
||||
m.insert("acos", (UnaryFuncInfo(acos, InverseTrig), "rad"));
|
||||
m.insert("acosec", (UnaryFuncInfo(acosec, InverseTrig), "rad"));
|
||||
m.insert("acosech", (UnaryFuncInfo(acosech, InverseTrig), "rad"));
|
||||
m.insert("acosh", (UnaryFuncInfo(acosh, InverseTrig), "rad"));
|
||||
m.insert("acot", (UnaryFuncInfo(acot, InverseTrig), "rad"));
|
||||
m.insert("acoth", (UnaryFuncInfo(acoth, InverseTrig), "rad"));
|
||||
m.insert("asec", (UnaryFuncInfo(asec, InverseTrig), "rad"));
|
||||
m.insert("asech", (UnaryFuncInfo(asech, InverseTrig), "rad"));
|
||||
m.insert("asin", (UnaryFuncInfo(asin, InverseTrig), "rad"));
|
||||
m.insert("asinh", (UnaryFuncInfo(asinh, InverseTrig), "rad"));
|
||||
m.insert("atan", (UnaryFuncInfo(atan, InverseTrig), "rad"));
|
||||
m.insert("atanh", (UnaryFuncInfo(atanh, InverseTrig), "rad"));
|
||||
|
||||
m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
|
||||
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
|
||||
m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
|
||||
m.insert("exp", (UnaryFuncInfo(exp, Other), ""));
|
||||
m.insert("floor", (UnaryFuncInfo(floor, Other), ""));
|
||||
m.insert("frac", (UnaryFuncInfo(frac, Other), ""));
|
||||
m.insert("gamma", (UnaryFuncInfo(gamma, Other), ""));
|
||||
m.insert("Γ", (UnaryFuncInfo(gamma, Other), ""));
|
||||
m.insert("log", (UnaryFuncInfo(log, Other), ""));
|
||||
m.insert("ln", (UnaryFuncInfo(ln, Other), ""));
|
||||
m.insert("round", (UnaryFuncInfo(round, Other), ""));
|
||||
m.insert("sqrt", (UnaryFuncInfo(sqrt, Other), ""));
|
||||
m.insert("√", (UnaryFuncInfo(sqrt, Other), ""));
|
||||
m.insert("trunc", (UnaryFuncInfo(trunc, Other), ""));
|
||||
m
|
||||
};
|
||||
pub static ref BINARY_FUNCS: HashMap<&'static str, (BinaryFuncInfo, &'static str)> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("max", (BinaryFuncInfo(max, Other), ""));
|
||||
m.insert("min", (BinaryFuncInfo(min, Other), ""));
|
||||
m.insert("hyp", (BinaryFuncInfo(hyp, Other), ""));
|
||||
m.insert("log", (BinaryFuncInfo(logx, Other), ""));
|
||||
m.insert("root", (BinaryFuncInfo(nth_root, Other), ""));
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
enum FuncType {
|
||||
Trig,
|
||||
InverseTrig,
|
||||
Other,
|
||||
}
|
||||
|
||||
// Unary functions
|
||||
pub struct UnaryFuncInfo(fn(Float) -> Float, FuncType);
|
||||
pub struct UnaryFuncInfo(pub(super) fn(Float) -> Float, pub(super) FuncType);
|
||||
|
||||
pub struct BinaryFuncInfo(fn(Float, Float) -> Float, FuncType);
|
||||
pub struct BinaryFuncInfo(pub(super) fn(Float, Float) -> Float, pub(super) FuncType);
|
||||
|
||||
impl UnaryFuncInfo {
|
||||
fn call(&self, context: &mut interpreter::Context, x: Float, angle_unit: &str) -> Float {
|
||||
@ -218,7 +119,7 @@ pub mod special_funcs {
|
||||
}
|
||||
}
|
||||
|
||||
mod funcs {
|
||||
pub(super) mod funcs {
|
||||
use rug::ops::Pow;
|
||||
use rug::Float;
|
||||
|
Loading…
Reference in New Issue
Block a user