Created a cargo feature for rug, f64 will be used instead if it's disabled

This commit is contained in:
PaddiM8 2020-12-30 16:03:02 +01:00
parent e8c362c72e
commit 8014a61f1a
11 changed files with 639 additions and 141 deletions

10
Cargo.lock generated
View File

@ -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"

View File

@ -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"]

View File

@ -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.

View File

@ -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
View 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::*;

View 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, "")
}
}

View File

@ -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,

View File

@ -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
View 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
View 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()
}
}

View File

@ -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;