diff --git a/src/context/helper.rs b/src/context/helper.rs index e3bc871..664fed8 100644 --- a/src/context/helper.rs +++ b/src/context/helper.rs @@ -38,6 +38,32 @@ pub fn fix(arg: &Value) -> EvalResult { } else { Err(EvalexprError::wrong_function_argument_amount(1, 2)) } } +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 { let value: f64; let base: Option; diff --git a/src/context/mod.rs b/src/context/mod.rs index 3023be6..58ccdd1 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -28,6 +28,8 @@ pub fn build(args: &mut Arguments) -> HashMapContext { // math functions "cos" => Function::new(|arg| helper::cosine(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)), "sin" => Function::new(|arg| helper::sine(arg)), "sqrt" => Function::new(|arg| helper::square_root(arg)), diff --git a/src/util.rs b/src/util.rs index 6daadbf..c2e1811 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,16 @@ 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 { let parse = arg.strip_prefix(prefix).unwrap_or(arg);