diff --git a/src/global.rs b/src/global.rs index 1de2458..3dddcd3 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,3 +1,6 @@ -pub const EULER: f64 = 2.718; -pub const PI: f64 = 3.14; +pub const EULER: f64 = 2.718281828459045; +pub const GOLDEN_RATIO: f64 = 1.618033988749895; +pub const PI: f64 = 3.141592653589793; +pub const ROOT_TWO: f64 = 1.414213562373095; + diff --git a/src/helper.rs b/src/helper.rs index 37b066c..26304ca 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -6,6 +6,58 @@ use evalexpr::{ use crate::util; +// Mathematics +pub fn logarithm(arg: &Value) -> Result { + let arguments: Vec; + let count: usize; + if arg.is_tuple() { + arguments = arg.as_tuple()?; + count = arguments.len(); + } else if arg.is_float() { + arguments = vec!(arg.as_float()?.into()); + count = 1; + } else if arg.is_int() { + arguments = vec!((arg.as_int()? as f64).into()); + count = 1; + } else { + return Err(EvalexprError::CustomMessage("Expected numbers".to_string())); + } + + let output: Value; + match count { + 1 => { + let argument = &arguments[0]; + if !argument.is_number() { + return Err(EvalexprError::CustomMessage("Expected number".to_string())); + } + let number = if argument.is_float() { argument.as_float()? } else { argument.as_int()? as f64 }; + output = number.ln().into(); + }, + 2 => { + let arg_value = &arguments[0]; + let arg_base = &arguments[1]; + if !(arg_value.is_number() && arg_base.is_number()) { + return Err(EvalexprError::CustomMessage("Expected two numbers".to_string())); + } + let value: f64 = if arg_value.is_float() { arg_value.as_float()? } else { arg_value.as_int()? as f64 }; + let base: f64 = if arg_base.is_float() { arg_base.as_float()? } else { arg_base.as_int()? as f64 }; + output = value.log(base).into(); + }, + _ => { + return Err(EvalexprError::WrongFunctionArgumentAmount { expected: 2, actual: count }); + } + } + return Ok(output); +} + +pub fn square_root(arg: &Value) -> Result { + if !arg.is_number() { + return Err(EvalexprError::CustomMessage("Expected a number.".to_string())); + } + let value: f64 = if arg.is_float() { arg.as_float()? } else { arg.as_int()? as f64 }; + return Ok(value.sqrt().into()); +} + // Data Science pub fn average(arg: &Value) -> Result { let arguments = arg.as_tuple()?; diff --git a/src/main.rs b/src/main.rs index 22352bd..9210a8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,9 @@ use evalexpr::{ eval_with_context_mut, HashMapContext, - Value + Value, + + Context }; use termion::{ color, @@ -25,21 +27,32 @@ mod global; mod helper; mod util; -pub const VERSION: &str = "0.1.5"; +pub const VERSION: &str = "0.2.0"; fn main() { let mut context = context_map! { // globals - "e" => global::EULER, - "pi" => global::PI, + "e" => global::EULER, + "phi" => global::GOLDEN_RATIO, + "pi" => global::PI, + "√2" => global::ROOT_TWO, + + // math functions + "log" => Function::new(|arg| helper::logarithm(arg)), + "sqrt" => Function::new(|arg| helper::square_root(arg)), // data science functions - "avg" => Function::new(|arg| helper::average(arg)), + "avg" => Function::new(|arg| helper::average(arg)), // radix functions - "bin" => Function::new(|arg| helper::binary(arg)), - "hex" => Function::new(|arg| helper::hexadecimal(arg)), - "oct" => Function::new(|arg| helper::octal(arg)) + "bin" => Function::new(|arg| helper::binary(arg)), + "hex" => Function::new(|arg| helper::hexadecimal(arg)), + "oct" => Function::new(|arg| helper::octal(arg)), + + // character aliases + "ϕ" => global::GOLDEN_RATIO, + "π" => global::PI, + "√" => Function::new(|arg| helper::square_root(arg)) }.unwrap(); let expressions: Vec = env::args().skip(1).collect(); if expressions.len() == 0 {