diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 6b52a0264..e5929256c 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -411,6 +411,9 @@ pub fn create_default_context() -> EngineState { MathSinH, MathCosH, MathTanH, + MathArcSin, + MathArcCos, + MathArcTan, MathPi, MathEuler, }; diff --git a/crates/nu-command/src/math/arccos.rs b/crates/nu-command/src/math/arccos.rs new file mode 100644 index 000000000..f9eb2c89d --- /dev/null +++ b/crates/nu-command/src/math/arccos.rs @@ -0,0 +1,105 @@ +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 arccos" + } + + fn signature(&self) -> Signature { + Signature::build("math arccos") + .switch("degrees", "Return degrees instead of radians", Some('d')) + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the arccosine of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "inverse"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let use_degrees = call.has_flag("degrees"); + input.map( + move |value| operate(value, head, use_degrees), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Get the arccosine of 1", + example: "1 | math arccos", + result: Some(Value::test_float(0.0f64)), + }, + Example { + description: "Get the arccosine of -1 in degrees", + example: "-1 | math arccos -d", + result: Some(Value::test_float(180.0)), + }, + ] + } +} + +fn operate(value: Value, head: Span, use_degrees: bool) -> 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!(), + }; + + if (-1.0..=1.0).contains(&val) { + let val = val.acos(); + let val = if use_degrees { val.to_degrees() } else { val }; + + Value::Float { val, span } + } else { + Value::Error { + error: ShellError::UnsupportedInput( + "'arccos' undefined for values outside the closed interval [-1, 1].".into(), + 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/arcsin.rs b/crates/nu-command/src/math/arcsin.rs new file mode 100644 index 000000000..8d373bf38 --- /dev/null +++ b/crates/nu-command/src/math/arcsin.rs @@ -0,0 +1,106 @@ +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 arcsin" + } + + fn signature(&self) -> Signature { + Signature::build("math arcsin") + .switch("degrees", "Return degrees instead of radians", Some('d')) + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the arcsine of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "inverse"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let use_degrees = call.has_flag("degrees"); + input.map( + move |value| operate(value, head, use_degrees), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + let pi = std::f64::consts::PI; + vec![ + Example { + description: "Get the arcsine of 1", + example: "1 | math arcsin", + result: Some(Value::test_float(pi / 2.0)), + }, + Example { + description: "Get the arcsine of 1 in degrees", + example: "1 | math arcsin -d", + result: Some(Value::test_float(90.0)), + }, + ] + } +} + +fn operate(value: Value, head: Span, use_degrees: bool) -> 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!(), + }; + + if (-1.0..=1.0).contains(&val) { + let val = val.asin(); + let val = if use_degrees { val.to_degrees() } else { val }; + + Value::Float { val, span } + } else { + Value::Error { + error: ShellError::UnsupportedInput( + "'arcsin' undefined for values outside the closed interval [-1, 1].".into(), + 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/arctan.rs b/crates/nu-command/src/math/arctan.rs new file mode 100644 index 000000000..c4fcaf1b0 --- /dev/null +++ b/crates/nu-command/src/math/arctan.rs @@ -0,0 +1,97 @@ +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 arctan" + } + + fn signature(&self) -> Signature { + Signature::build("math arctan") + .switch("degrees", "Return degrees instead of radians", Some('d')) + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns the arctangent of the number." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["trigonometry", "inverse"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let use_degrees = call.has_flag("degrees"); + input.map( + move |value| operate(value, head, use_degrees), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + let pi = std::f64::consts::PI; + vec![ + Example { + description: "Get the arctangent of 1", + example: "1 | math arctan", + result: Some(Value::test_float(pi / 4.0f64)), + }, + Example { + description: "Get the arctangent of -1 in degrees", + example: "-1 | math arctan -d", + result: Some(Value::test_float(-45.0)), + }, + ] + } +} + +fn operate(value: Value, head: Span, use_degrees: bool) -> 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!(), + }; + + let val = val.atan(); + let val = if use_degrees { val.to_degrees() } else { val }; + + Value::Float { val, 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 ca9548021..35bc35f01 100644 --- a/crates/nu-command/src/math/mod.rs +++ b/crates/nu-command/src/math/mod.rs @@ -1,4 +1,7 @@ mod abs; +mod arccos; +mod arcsin; +mod arctan; mod avg; mod ceil; mod cos; @@ -49,5 +52,9 @@ pub use sinh::SubCommand as MathSinH; pub use tan::SubCommand as MathTan; pub use tanh::SubCommand as MathTanH; +pub use arccos::SubCommand as MathArcCos; +pub use arccosh::SubCommand as MathArcCosH; +pub use arcsin::SubCommand as MathArcSin; + pub use euler::SubCommand as MathEuler; pub use pi::SubCommand as MathPi;