Compare commits

..

3 commits
v0.3.1 ... main

4 changed files with 85 additions and 3 deletions

View file

@ -1,3 +1,4 @@
use evalexpr::{ use evalexpr::{
Value, Value,
@ -38,6 +39,51 @@ pub fn fix(arg: &Value) -> EvalResult {
} else { Err(EvalexprError::wrong_function_argument_amount(1, 2)) } } else { Err(EvalexprError::wrong_function_argument_amount(1, 2)) }
} }
pub fn fraction(arg: &Value) -> EvalResult {
if let Value::Float(arg) = arg {
let mut intermediate = arg.clone();
let mut pow = 0;
while intermediate.fract() != 0_f64 {
intermediate *= 10_f64;
pow += 1;
}
let value = intermediate as i64;
let tens: i64 = 10_i64.pow(pow);
let gcd = util::gcd(value, tens);
let numerator = value / gcd;
let denominator = tens / gcd;
Ok(Value::String(format!("{numerator}/{denominator}")))
} else { Err(EvalexprError::expected_float(arg.clone())) }
}
pub fn greatest_common_divisor(arg: &Value) -> EvalResult {
if let Value::Tuple(args) = arg {
let len = args.len();
if len != 2 { return Err(EvalexprError::wrong_function_argument_amount(len, 2)); }
let a = args[0].clone();
let b = args[1].clone();
if let (Value::Int(a), Value::Int(b)) = (a, b) { Ok( Value::Int( util::gcd(i64::max(a, b), i64::min(a, b)) ) ) }
else { Err(EvalexprError::expected_int( if !args[0].is_int() { args[0].clone() } else { args[1].clone() } )) }
} else { Err(EvalexprError::expected_tuple(arg.clone())) }
}
pub fn least_common_multiple(arg: &Value) -> EvalResult {
if let Value::Tuple(args) = arg {
let len = args.len();
if len != 2 { return Err(EvalexprError::wrong_function_argument_amount(len, 2)); }
let a = args[0].clone();
let b = args[1].clone();
if let (Value::Int(a), Value::Int(b)) = (a, b) { Ok( Value::Int( util::lcm(i64::max(a, b), i64::min(a, b)) ) ) }
else { Err(EvalexprError::expected_int( if !args[0].is_int() { args[0].clone() } else { args[1].clone() } )) }
} else { Err(EvalexprError::expected_tuple(arg.clone())) }
}
pub fn logarithm(arg: &Value) -> EvalResult { pub fn logarithm(arg: &Value) -> EvalResult {
let value: f64; let value: f64;
let base: Option<f64>; let base: Option<f64>;
@ -112,11 +158,33 @@ pub fn average(arg: &Value) -> EvalResult {
total += total +=
if let Value::Float(float) = arg { float.clone() } if let Value::Float(float) = arg { float.clone() }
else if let Value::Int(int) = arg { int.clone() as f64 } else if let Value::Int(int) = arg { int.clone() as f64 }
else { todo!() }; else { return Err(EvalexprError::expected_number(arg.clone())) };
} }
Ok( (total / len).into() ) Ok( (total / len).into() )
} else { todo!() } } else { Err(EvalexprError::expected_tuple(arg.clone())) }
}
pub fn median(arg: &Value) -> EvalResult {
if arg.is_tuple() {
let args = sort(arg).unwrap().as_tuple().unwrap();
let len = args.len();
let middle = len / 2;
if len % 2 != 0 { Ok(args[middle].as_number().unwrap().into()) }
else {
let left = args[middle - 1].as_number().unwrap();
let right = args[middle].as_number().unwrap();
Ok( ((left + right) / 2f64 ).into() )
}
} else { Err(EvalexprError::expected_tuple(arg.clone())) }
}
pub fn sort(arg: &Value) -> EvalResult {
if let Value::Tuple(args) = arg {
let mut args = args.clone();
args.sort_by(|a, b| a.as_number().unwrap().total_cmp(&b.as_number().unwrap()));
Ok(args.into())
} else { Err(EvalexprError::expected_tuple(arg.clone())) }
} }
// Radix conversion // Radix conversion

View file

@ -27,7 +27,10 @@ pub fn build(args: &mut Arguments) -> HashMapContext {
// math functions // math functions
"cos" => Function::new(|arg| helper::cosine(arg)), "cos" => Function::new(|arg| helper::cosine(arg)),
"fract" => Function::new(|arg| helper::fraction(arg)),
"fix" => Function::new(|arg| helper::fix(arg)), "fix" => Function::new(|arg| helper::fix(arg)),
"gcd" => Function::new(|arg| helper::greatest_common_divisor(arg)),
"lcm" => Function::new(|arg| helper::least_common_multiple(arg)),
"log" => Function::new(|arg| helper::logarithm(arg)), "log" => Function::new(|arg| helper::logarithm(arg)),
"sin" => Function::new(|arg| helper::sine(arg)), "sin" => Function::new(|arg| helper::sine(arg)),
"sqrt" => Function::new(|arg| helper::square_root(arg)), "sqrt" => Function::new(|arg| helper::square_root(arg)),
@ -35,6 +38,8 @@ pub fn build(args: &mut Arguments) -> HashMapContext {
// data science functions // data science functions
"avg" => Function::new(|arg| helper::average(arg)), "avg" => Function::new(|arg| helper::average(arg)),
"med" => Function::new(|arg| helper::median(arg)),
"sort" => Function::new(|arg| helper::sort(arg)),
// radix functions // radix functions
"bin" => Function::new(|arg| helper::binary(arg)), "bin" => Function::new(|arg| helper::binary(arg)),

View file

@ -14,7 +14,6 @@ use std::{
use evalexpr::{ use evalexpr::{
eval_with_context_mut, eval_with_context_mut,
ContextWithMutableVariables,
EvalexprError, EvalexprError,
HashMapContext, HashMapContext,
Value Value

View file

@ -1,6 +1,16 @@
use evalexpr::{ EvalexprError, Value }; use evalexpr::{ EvalexprError, Value };
pub fn gcd(big: i64, small: i64) -> i64 {
if small == 0 { big }
else { gcd(small, big % small) }
}
pub fn lcm(big: i64, small: i64) -> i64 {
let product = (big * small).abs();
product / gcd(big, small)
}
pub fn parse_radix(prefix: &str, base: u32, arg: &str) -> Result<Value, EvalexprError> { pub fn parse_radix(prefix: &str, base: u32, arg: &str) -> Result<Value, EvalexprError> {
let parse = arg.strip_prefix(prefix).unwrap_or(arg); let parse = arg.strip_prefix(prefix).unwrap_or(arg);