From f2f4992230cd50760609d8e9626548ac85dc4dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher=20Andr=C3=A9s?= Date: Thu, 30 Oct 2025 17:38:02 +0100 Subject: [PATCH] UPDATE: Add some missing trigonometric functions (#487) Acot, Acoth, Cot, Coth, Csc, Csch, Sec, Sech, --- .../src/expressions/parser/static_analysis.rs | 16 +++++++ base/src/functions/mathematical.rs | 40 ++++++++++++++++ base/src/functions/mod.rs | 46 ++++++++++++++++++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/base/src/expressions/parser/static_analysis.rs b/base/src/expressions/parser/static_analysis.rs index 3abade6..e50e023 100644 --- a/base/src/expressions/parser/static_analysis.rs +++ b/base/src/expressions/parser/static_analysis.rs @@ -834,6 +834,14 @@ fn get_function_args_signature(kind: &Function, arg_count: usize) -> Vec vec![Signature::Vector; arg_count], Function::Networkdays => args_signature_networkdays(arg_count), Function::NetworkdaysIntl => args_signature_networkdays_intl(arg_count), + Function::Acot => args_signature_scalars(arg_count, 1, 0), + Function::Acoth => args_signature_scalars(arg_count, 1, 0), + Function::Cot => args_signature_scalars(arg_count, 1, 0), + Function::Coth => args_signature_scalars(arg_count, 1, 0), + Function::Csc => args_signature_scalars(arg_count, 1, 0), + Function::Csch => args_signature_scalars(arg_count, 1, 0), + Function::Sec => args_signature_scalars(arg_count, 1, 0), + Function::Sech => args_signature_scalars(arg_count, 1, 0), } } @@ -1056,5 +1064,13 @@ fn static_analysis_on_function(kind: &Function, args: &[Node]) -> StaticResult { Function::Geomean => not_implemented(args), Function::Networkdays => not_implemented(args), Function::NetworkdaysIntl => not_implemented(args), + Function::Acot => scalar_arguments(args), + Function::Acoth => scalar_arguments(args), + Function::Cot => scalar_arguments(args), + Function::Coth => scalar_arguments(args), + Function::Csc => scalar_arguments(args), + Function::Csch => scalar_arguments(args), + Function::Sec => scalar_arguments(args), + Function::Sech => scalar_arguments(args), } } diff --git a/base/src/functions/mathematical.rs b/base/src/functions/mathematical.rs index 4f9cc88..290c0cf 100644 --- a/base/src/functions/mathematical.rs +++ b/base/src/functions/mathematical.rs @@ -414,6 +414,46 @@ impl Model { } else { Ok((f * PI).sqrt()) }); + single_number_fn!(fn_acot, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(f64::atan(1.0 / f)) + }); + single_number_fn!(fn_acoth, |f: f64| if f.abs() == 1.0 { + Err(Error::DIV) + } else { + Ok(0.5 * (f64::ln((f + 1.0) / (f - 1.0)))) + }); + single_number_fn!(fn_cot, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(f64::cos(f) / f64::sin(f)) + }); + single_number_fn!(fn_coth, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(f64::cosh(f) / f64::sinh(f)) + }); + single_number_fn!(fn_csc, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(1.0 / f64::sin(f)) + }); + single_number_fn!(fn_csch, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(1.0 / f64::sinh(f)) + }); + single_number_fn!(fn_sec, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(1.0 / f64::cos(f)) + }); + single_number_fn!(fn_sech, |f| if f == 0.0 { + Err(Error::DIV) + } else { + Ok(1.0 / f64::cosh(f)) + }); pub(crate) fn fn_pi(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { if !args.is_empty() { diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index c829a1b..95c7e84 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -76,6 +76,14 @@ pub enum Function { Sumifs, Tan, Tanh, + Acot, + Acoth, + Cot, + Coth, + Csc, + Csch, + Sec, + Sech, // Information ErrorType, @@ -270,7 +278,7 @@ pub enum Function { } impl Function { - pub fn into_iter() -> IntoIter { + pub fn into_iter() -> IntoIter { [ Function::And, Function::False, @@ -303,6 +311,14 @@ impl Function { Function::Sqrt, Function::Sqrtpi, Function::Atan2, + Function::Acot, + Function::Acoth, + Function::Cot, + Function::Coth, + Function::Csc, + Function::Csch, + Function::Sec, + Function::Sech, Function::Power, Function::Max, Function::Min, @@ -568,6 +584,15 @@ impl Function { "ACOSH" => Some(Function::Acosh), "ATANH" => Some(Function::Atanh), + "ACOT" => Some(Function::Acot), + "COTH" => Some(Function::Coth), + "COT" => Some(Function::Cot), + "CSC" => Some(Function::Csc), + "CSCH" => Some(Function::Csch), + "SEC" => Some(Function::Sec), + "SECH" => Some(Function::Sech), + "ACOTH" => Some(Function::Acoth), + "PI" => Some(Function::Pi), "ABS" => Some(Function::Abs), "SQRT" => Some(Function::Sqrt), @@ -811,6 +836,16 @@ impl fmt::Display for Function { Function::Asinh => write!(f, "ASINH"), Function::Acosh => write!(f, "ACOSH"), Function::Atanh => write!(f, "ATANH"), + + Function::Acot => write!(f, "ACOT"), + Function::Acoth => write!(f, "ACOTH"), + Function::Cot => write!(f, "COT"), + Function::Coth => write!(f, "COTH"), + Function::Csc => write!(f, "CSC"), + Function::Csch => write!(f, "CSCH"), + Function::Sec => write!(f, "SEC"), + Function::Sech => write!(f, "SECH"), + Function::Abs => write!(f, "ABS"), Function::Pi => write!(f, "PI"), Function::Sqrt => write!(f, "SQRT"), @@ -1260,8 +1295,15 @@ impl Model { Function::Convert => self.fn_convert(args, cell), Function::Delta => self.fn_delta(args, cell), Function::Gestep => self.fn_gestep(args, cell), - Function::Subtotal => self.fn_subtotal(args, cell), + Function::Acot => self.fn_acot(args, cell), + Function::Acoth => self.fn_acoth(args, cell), + Function::Cot => self.fn_cot(args, cell), + Function::Coth => self.fn_coth(args, cell), + Function::Csc => self.fn_csc(args, cell), + Function::Csch => self.fn_csch(args, cell), + Function::Sec => self.fn_sec(args, cell), + Function::Sech => self.fn_sech(args, cell), } } }