From 4f05994b3657812cc2974e82eba819fba0953ff5 Mon Sep 17 00:00:00 2001 From: sholderbach Date: Sun, 27 Nov 2022 16:29:38 +0100 Subject: [PATCH] Add basic hyperbolic functions (#7258) `math sinh` `math cosh` `math tanh` --- crates/nu-command/src/default_context.rs | 3 + crates/nu-command/src/math/cosh.rs | 88 ++++++++++++++++++++++++ crates/nu-command/src/math/mod.rs | 6 ++ crates/nu-command/src/math/sinh.rs | 88 ++++++++++++++++++++++++ crates/nu-command/src/math/tanh.rs | 87 +++++++++++++++++++++++ 5 files changed, 272 insertions(+) create mode 100644 crates/nu-command/src/math/cosh.rs create mode 100644 crates/nu-command/src/math/sinh.rs create mode 100644 crates/nu-command/src/math/tanh.rs diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index e9920f9f01..6b52a0264c 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -408,6 +408,9 @@ pub fn create_default_context() -> EngineState { MathSin, MathCos, MathTan, + MathSinH, + MathCosH, + MathTanH, MathPi, MathEuler, }; diff --git a/crates/nu-command/src/math/cosh.rs b/crates/nu-command/src/math/cosh.rs new file mode 100644 index 0000000000..4e0f28c0ba --- /dev/null +++ b/crates/nu-command/src/math/cosh.rs @@ -0,0 +1,88 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "math cosh" + } + + fn signature(&self) -> Signature { + Signature::build("math cosh") + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the hyperbolic cosine of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "hyperbolic"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + input.map( + move |value| operate(value, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + let e = std::f64::consts::E; + vec![Example { + description: "Apply the hyperpolic cosine to 1", + example: "1 | math cosh", + result: Some(Value::test_float(((e * e) + 1.0) / (2.0 * e))), + }] + } +} + +fn operate(value: Value, head: Span) -> Value { + match value { + numeric @ (Value::Int { .. } | Value::Float { .. }) => { + let (val, span) = match numeric { + Value::Int { val, span } => (val as f64, span), + Value::Float { val, span } => (val, span), + _ => unreachable!(), + }; + + Value::Float { + val: val.cosh(), + span, + } + } + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Only numerical values are supported, input type: {:?}", + other.get_type() + ), + other.span().unwrap_or(head), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/math/mod.rs b/crates/nu-command/src/math/mod.rs index dfba8495be..ca95480212 100644 --- a/crates/nu-command/src/math/mod.rs +++ b/crates/nu-command/src/math/mod.rs @@ -2,6 +2,7 @@ mod abs; mod avg; mod ceil; mod cos; +mod cosh; mod euler; mod eval; mod floor; @@ -15,10 +16,12 @@ mod product; mod reducers; mod round; mod sin; +mod sinh; mod sqrt; mod stddev; mod sum; mod tan; +mod tanh; mod utils; mod variance; @@ -40,8 +43,11 @@ pub use sum::SubCommand as MathSum; pub use variance::SubCommand as MathVariance; pub use cos::SubCommand as MathCos; +pub use cosh::SubCommand as MathCosH; pub use sin::SubCommand as MathSin; +pub use sinh::SubCommand as MathSinH; pub use tan::SubCommand as MathTan; +pub use tanh::SubCommand as MathTanH; pub use euler::SubCommand as MathEuler; pub use pi::SubCommand as MathPi; diff --git a/crates/nu-command/src/math/sinh.rs b/crates/nu-command/src/math/sinh.rs new file mode 100644 index 0000000000..225abaf747 --- /dev/null +++ b/crates/nu-command/src/math/sinh.rs @@ -0,0 +1,88 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "math sinh" + } + + fn signature(&self) -> Signature { + Signature::build("math sinh") + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the hyperbolic sine of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "hyperbolic"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + input.map( + move |value| operate(value, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + let e = std::f64::consts::E; + vec![Example { + description: "Apply the hyperpolic sine to 1", + example: "1 | math sinh", + result: Some(Value::test_float((e * e - 1.0) / (2.0 * e))), + }] + } +} + +fn operate(value: Value, head: Span) -> Value { + match value { + numeric @ (Value::Int { .. } | Value::Float { .. }) => { + let (val, span) = match numeric { + Value::Int { val, span } => (val as f64, span), + Value::Float { val, span } => (val, span), + _ => unreachable!(), + }; + + Value::Float { + val: val.sinh(), + span, + } + } + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Only numerical values are supported, input type: {:?}", + other.get_type() + ), + other.span().unwrap_or(head), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/math/tanh.rs b/crates/nu-command/src/math/tanh.rs new file mode 100644 index 0000000000..ab12f6659a --- /dev/null +++ b/crates/nu-command/src/math/tanh.rs @@ -0,0 +1,87 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "math tanh" + } + + fn signature(&self) -> Signature { + Signature::build("math tanh") + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the hyperbolic tangent of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "hyperbolic"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + input.map( + move |value| operate(value, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Apply the hyperpolic tangent to 10*pi", + example: "(math pi) * 10 | math tanh", + result: Some(Value::test_float(1f64)), + }] + } +} + +fn operate(value: Value, head: Span) -> Value { + match value { + numeric @ (Value::Int { .. } | Value::Float { .. }) => { + let (val, span) = match numeric { + Value::Int { val, span } => (val as f64, span), + Value::Float { val, span } => (val, span), + _ => unreachable!(), + }; + + Value::Float { + val: val.tanh(), + span, + } + } + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Only numerical values are supported, input type: {:?}", + other.get_type() + ), + other.span().unwrap_or(head), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +}