Skip to main content

num_valid/functions/
trigonometric.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! This module provides traits, error types, and implementations for various
4//! trigonometric functions.
5//!
6//! It defines a set of traits (e.g., [`Sin`], [`Cos`], [`ATan2`]) for standard
7//! trigonometric operations and their inverses. These traits are implemented
8//! for [`f64`], [`num::Complex<f64>`], [`RealValidated`](crate::RealValidated), [`ComplexValidated`](crate::ComplexValidated)
9//! and can be extended to other numeric types satisfying the [`RealScalar`](crate::RealScalar) or [`ComplexScalar`](crate::ComplexScalar) traits.
10//!
11//! A comprehensive error handling system is in place, utilizing specific input
12//! error enums (e.g., [`ASinRealInputErrors`], [`ATanComplexInputErrors`]) and
13//! general function error type aliases (e.g., [`SinErrors`], [`CosErrors`])
14//! built upon the [`FunctionErrors`] struct. This allows for granular reporting
15//! of issues such as invalid arguments (NaN, infinity), out-of-domain values,
16//! or poles.
17//!
18//! The design emphasizes robustness through strict validation of inputs and outputs,
19//! primarily using the [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
20
21use crate::{
22    core::traits::{raw::RawScalarValidate, validation::sealed::NativeReal},
23    functions::FunctionErrors,
24    kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait},
25};
26use duplicate::duplicate_item;
27use num::Complex;
28use num_traits::Float;
29use std::backtrace::Backtrace;
30use thiserror::Error;
31
32#[cfg(debug_assertions)]
33use crate::{Constants, core::errors::capture_backtrace};
34
35#[cfg(debug_assertions)]
36use num::Zero;
37
38//------------------------------------------------------------------------------------------------
39// Real and Complex Number Input Errors (for functions like sin, cos)
40//------------------------------------------------------------------------------------------------
41#[duplicate_item(
42    enum_name             enum_doc;
43    [CosInputErrors]  ["Errors that can occur during the input validation phase when computing the *cosine* of a real or complex number.\n\nThis enum is used as a source for the `Input` variant of [`CosErrors`].\n\n# Type Parameters\n\n- `RawScalar`: A type that implements the [`RawScalarTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `RawScalar::ValidationError` (e.g., [`crate::core::errors::ErrorsValidationRawReal`], [`crate::core::errors::ErrorsValidationRawComplex`], etc.).\n\n# Variants\n\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity). The `source` field provides the specific raw validation error."];
44    [SinInputErrors]  ["Errors that can occur during the input validation phase when computing the *sine* of a real or complex number.\n\nThis enum is used as a source for the `Input` variant of [`SinErrors`].\n\n# Type Parameters\n\n- `RawScalar`: A type that implements the [`RawScalarTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `RawScalar::ValidationError` (e.g., [`crate::core::errors::ErrorsValidationRawReal`], [`crate::core::errors::ErrorsValidationRawComplex`], etc.).\n\n# Variants\n\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity). The `source` field provides the specific raw validation error."];
45)]
46#[derive(Debug, Error)]
47#[doc = enum_doc]
48pub enum enum_name<RawScalar: RawScalarTrait> {
49    /// The argument of the function is invalid.
50    ///
51    /// This variant indicates that the argument failed general validation checks
52    /// according to the chosen validation policy (e.g., NaN, Infinity).
53    #[error("the argument of the function is invalid!")]
54    InvalidArgument {
55        /// The underlying validation error from the input's raw scalar type.
56        #[source]
57        #[backtrace]
58        source: RawScalar::ValidationError,
59    },
60}
61
62//------------------------------------------------------------------------------------------------
63// Real Number Input Errors (for functions like tan, atan)
64//------------------------------------------------------------------------------------------------
65
66/// Errors that can occur during the input validation phase when computing the *tangent* of a *real number*.
67///
68/// This enum is used as a source for the `Input` variant of [`TanRealErrors`].
69///
70/// # Type Parameters
71///
72/// - `RawReal`: A type that implements the [`RawRealTrait`] trait.
73///
74/// # Variants
75///
76/// - `ArgumentIsPole`: Indicates the input argument is a mathematical pole (e.g., π/2 + kπ).
77/// - `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity).
78#[derive(Debug, Error)]
79pub enum TanRealInputErrors<RawReal: RawRealTrait> {
80    /// The argument of the function is a mathematical pole (e.g., π/2 + kπ).
81    #[error("the argument ({value}) is a mathematical pole for the tangent function!")]
82    ArgumentIsPole {
83        /// The value that is a pole.
84        value: RawReal,
85        /// The backtrace of the error.
86        backtrace: Backtrace,
87    },
88
89    /// The argument of the function is invalid.
90    ///
91    /// This variant indicates that the argument failed general validation checks
92    /// according to the chosen validation policy (e.g., NaN, Infinity).
93    #[error("the argument of the function is invalid!")]
94    InvalidArgument {
95        /// The underlying validation error from the input's raw real type.
96        #[source]
97        #[backtrace]
98        source: <RawReal as RawScalarValidate>::ValidationError,
99    },
100}
101
102/// Errors that can occur during the input validation phase when computing the *inverse tangent* of a *real number*.
103///
104/// This enum is used as a source for the `Input` variant of [`ATanRealErrors`].
105///
106/// # Type Parameters
107///
108/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError` (e.g., [`crate::core::errors::ErrorsValidationRawReal<f64>`]).
109///
110/// # Variants
111/// - `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity). The `source` field provides the specific raw validation error.
112#[derive(Debug, Error)]
113pub enum ATanRealInputErrors<RawReal: RawRealTrait> {
114    /// The argument of the function is invalid.
115    ///
116    /// This variant indicates that the argument failed general validation checks
117    /// according to the chosen validation policy (e.g., NaN, Infinity).
118    #[error("the argument of the function is invalid!")]
119    InvalidArgument {
120        /// The underlying validation error from the input's raw real type.
121        #[source]
122        #[backtrace]
123        source: RawReal::ValidationError,
124    },
125}
126
127//------------------------------------------------------------------------------------------------
128// Real Number Input Errors (for functions like asin, acos with domain constraints)
129//------------------------------------------------------------------------------------------------
130#[duplicate_item(
131    enum_name             enum_doc;
132    [ASinRealInputErrors] ["Errors that can occur during the input validation phase when computing the *inverse sine* of a *real number*.\n\nThis enum is used as a source for the `Input` variant of [`ASinRealErrors`].\n\n# Type Parameters\n\n- `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError` (e.g., [`crate::core::errors::ErrorsValidationRawReal<f64>`]).\n\n# Variants\n\n- `OutOfDomain`: Indicates the input argument is outside the valid domain `[-1, 1]`.\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity). The `source` field provides the specific raw validation error."];
133    [ACosRealInputErrors] ["Errors that can occur during the input validation phase when computing the *inverse cosine* of a *real number*.\n\nThis enum is used as a source for the `Input` variant of [`ACosRealErrors`].\n\n# Type Parameters\n\n- `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError` (e.g., [`crate::core::errors::ErrorsValidationRawReal<f64>`]).\n\n# Variants\n\n- `OutOfDomain`: Indicates the input argument is outside the valid domain `[-1, 1]`.\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., NaN, Infinity). The `source` field provides the specific raw validation error."];
134)]
135#[derive(Debug, Error)]
136#[doc = enum_doc]
137pub enum enum_name<RawReal: RawRealTrait> {
138    /// The argument of the function is not in the valid domain `[-1, 1]`.
139    #[error("the argument of the function ({value}) is not in the domain [-1.,1.]!")]
140    OutOfDomain {
141        /// The value that is out of the domain [-1.,1.].
142        value: RawReal,
143
144        /// The backtrace of the error.
145        backtrace: Backtrace,
146    },
147
148    /// The argument of the function is invalid (e.g., NaN, Infinity, or subnormal).
149    ///
150    /// This variant indicates that the argument failed general validation checks
151    /// according to the chosen validation policy (e.g., NaN, Infinity).
152    #[error("the argument of the function is invalid!")]
153    InvalidArgument {
154        /// The source error that occurred during validation.
155        #[source]
156        #[backtrace]
157        source: <RawReal as RawScalarValidate>::ValidationError,
158    },
159}
160
161//------------------------------------------------------------------------------------------------
162// Real and Complex Number General Function Errors (Type Aliases for FunctionErrors)
163//------------------------------------------------------------------------------------------------
164#[duplicate_item(
165    enum_name   ErrIn            enum_doc;
166    [CosErrors] [CosInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *cosine* computation on a real or complex number.\n\nRepresents failures from [`Cos::try_cos()`].\n\n# Type Parameters\n\n- `RawScalar`: Implements [`RawScalarTrait`]. Defines input error type via `ErrIn<RawScalar>` and output raw error via `RawScalar::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawScalar> }`: Input was invalid (e.g., NaN, Infinity).\n- `Output { source: RawScalar::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
167    [SinErrors] [SinInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *sine* computation on a real or complex number.\n\nRepresents failures from [`Sin::try_sin()`].\n\n# Type Parameters\n\n- `RawScalar`: Implements [`RawScalarTrait`]. Defines input error type via `ErrIn<RawScalar>` and output raw error via `RawScalar::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawScalar> }`: Input was invalid (e.g., NaN, Infinity).\n- `Output { source: RawScalar::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
168)]
169#[doc = enum_doc]
170pub type enum_name<RawScalar> =
171    FunctionErrors<ErrIn<RawScalar>, <RawScalar as RawScalarValidate>::ValidationError>;
172
173//------------------------------------------------------------------------------------------------
174// Real Number General Function Errors (Type Aliases for FunctionErrors)
175//------------------------------------------------------------------------------------------------
176#[duplicate_item(
177    enum_name        ErrIn                 enum_doc;
178    [ACosRealErrors] [ACosRealInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse cosine* computation on a *real number*.\n\nRepresents failures from [`ACos::try_acos()`].\n\n# Type Parameters\n\n- `RawReal`: Implements [`RawRealTrait`]. Defines input error type via `ErrIn<RawReal>` and output raw error via `<RawReal as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawReal> }`: Input was invalid (e.g., out of domain `[-1,1]`, NaN, Infinity).\n- `Output { source: <RawReal as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
179    [ASinRealErrors] [ASinRealInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse sine* computation on a *real number*.\n\nRepresents failures from [`ASin::try_asin()`].\n\n# Type Parameters\n\n- `RawReal`: Implements [`RawRealTrait`]. Defines input error type via `ErrIn<RawReal>` and output raw error via `<RawReal as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawReal> }`: Input was invalid (e.g., out of domain `[-1,1]`, NaN, Infinity).\n- `Output { source: <RawReal as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
180    [ATanRealErrors] [ATanRealInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse tangent* computation on a *real number*.\n\nRepresents failures from [`ATan::try_atan()`].\n\n# Type Parameters\n\n- `RawReal`: Implements [`RawRealTrait`]. Defines input error type via `ErrIn<RawReal>` and output raw error via `<RawReal as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawReal> }`: Input was invalid (e.g., NaN, Infinity).\n- `Output { source: <RawReal as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
181    [TanRealErrors]  [TanRealInputErrors]  ["A type alias for [`FunctionErrors`], specialized for errors during *tangent* computation on a *real number*.\n\nRepresents failures from [`Tan::try_tan()`].\n\n# Type Parameters\n\n- `RawReal`: Implements [`RawRealTrait`]. Defines input error type via `ErrIn<RawReal>` and output raw error via `<RawReal as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawReal> }`: Input was invalid (e.g., NaN, Infinity).\n- `Output { source: <RawReal as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., NaN, Infinity)."];
182)]
183#[doc = enum_doc]
184pub type enum_name<RawReal> =
185    FunctionErrors<ErrIn<RawReal>, <RawReal as RawScalarValidate>::ValidationError>;
186
187//------------------------------------------------------------------------------------------------
188// Complex Number Input Errors (for functions like tan, asin, acos)
189//------------------------------------------------------------------------------------------------
190#[duplicate_item(
191    enum_name                enum_doc;
192    [ACosComplexInputErrors] ["Errors that can occur during the input validation phase when computing the *inverse cosine* of a *complex number*.\n\nThis enum is used as a source for the `Input` variant of [`ACosComplexErrors`].\n\n# Type Parameters\n\n- `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., components are NaN, Infinity). The `source` field provides the specific raw validation error."];
193    [ASinComplexInputErrors] ["Errors that can occur during the input validation phase when computing the *inverse sine* of a *complex number*.\n\nThis enum is used as a source for the `Input` variant of [`ASinComplexErrors`].\n\n# Type Parameters\n\n- `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., components are NaN, Infinity). The `source` field provides the specific raw validation error."];
194    [TanComplexInputErrors]  ["Errors that can occur during the input validation phase when computing the *tangent* of a *complex number*.\n\nThis enum is used as a source for the `Input` variant of [`TanComplexErrors`].\n\n# Type Parameters\n\n- `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `InvalidArgument`: Indicates that the input argument failed general validation checks (e.g., components are NaN, Infinity). The `source` field provides the specific raw validation error."];
195)]
196#[derive(Debug, Error)]
197#[doc = enum_doc]
198pub enum enum_name<RawComplex: RawComplexTrait> {
199    /// The argument of the function is invalid (e.g., one or both components are NaN, Infinity, or subnormal).
200    ///
201    /// This variant indicates that the argument failed general validation checks
202    /// according to the chosen validation policy.
203    #[error("the argument of the function is invalid!")]
204    InvalidArgument {
205        /// The underlying validation error from the input's raw complex type.
206        #[source]
207        #[backtrace]
208        source: <RawComplex as RawScalarValidate>::ValidationError,
209    },
210}
211
212//------------------------------------------------------------------------------------------------
213// Complex ATan Input Errors (Specific due to poles)
214//------------------------------------------------------------------------------------------------
215/// Errors that can occur during the input validation phase when attempting to compute
216/// the arctangent of a complex number.
217///
218/// This enum is used as a source for the `Input` variant of [`ATanComplexErrors`].
219/// It is generic over `RawComplex`, which must implement [`RawComplexTrait`].
220/// This enum addresses failures in the initial validation of the input complex
221/// number (e.g., components being NaN, Infinity, or subnormal) or if the
222/// argument is a pole for the complex arctangent function (e.g., `0 +/- 1i`).
223#[derive(Debug, Error)]
224pub enum ATanComplexInputErrors<RawComplex: RawComplexTrait> {
225    /// The input complex number is a pole for the arctangent function (e.g., `i` or `-i`).
226    ///
227    /// The complex arctangent function is undefined at these points.
228    #[error("the argument ({value:?}) is a pole for the function!")]
229    ArgumentIsPole {
230        /// The argument value that is a pole.
231        value: RawComplex,
232
233        /// The backtrace of the error.
234        backtrace: std::backtrace::Backtrace,
235    },
236
237    /// The argument of the function is invalid due to failing general validation checks.
238    ///
239    /// This variant indicates that the argument of the function is invalid w.r.t. the chosen validation policy (e.g. NaN, Infinity).
240    /// It includes the source error that occurred during validation.
241    #[error("the argument of the function is invalid!")]
242    InvalidArgument {
243        /// The source error that occurred during validation.
244        #[source]
245        #[backtrace]
246        source: <RawComplex as RawScalarValidate>::ValidationError,
247    },
248}
249
250//------------------------------------------------------------------------------------------------
251// Complex Number General Function Errors (Type Aliases for FunctionErrors)
252//------------------------------------------------------------------------------------------------
253#[duplicate_item(
254    enum_name           ErrIn                    enum_doc;
255    [ACosComplexErrors] [ACosComplexInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse cosine* computation on a *complex number*.\n\nRepresents failures from [`ACos::try_acos()`].\n\n# Type Parameters\n\n- `RawComplex`: Implements [`RawComplexTrait`]. Defines input error type via `ErrIn<RawComplex>` and output raw error via `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawComplex> }`: Input was invalid (e.g., components are NaN, Infinity).\n- `Output { source: <RawComplex as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., components are NaN, Infinity)."];
256    [ASinComplexErrors] [ASinComplexInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse sine* computation on a *complex number*.\n\nRepresents failures from [`ASin::try_asin()`].\n\n# Type Parameters\n\n- `RawComplex`: Implements [`RawComplexTrait`]. Defines input error type via `ErrIn<RawComplex>` and output raw error via `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawComplex> }`: Input was invalid (e.g., components are NaN, Infinity).\n- `Output { source: <RawComplex as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., components are NaN, Infinity)."];
257    [TanComplexErrors]  [TanComplexInputErrors]  ["A type alias for [`FunctionErrors`], specialized for errors during *tangent* computation on a *complex number*.\n\nRepresents failures from [`Tan::try_tan()`].\n\n# Type Parameters\n\n- `RawComplex`: Implements [`RawComplexTrait`]. Defines input error type via `ErrIn<RawComplex>` and output raw error via `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawComplex> }`: Input was invalid (e.g., components are NaN, Infinity).\n- `Output { source: <RawComplex as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., components are NaN, Infinity)."];
258    [ATanComplexErrors] [ATanComplexInputErrors] ["A type alias for [`FunctionErrors`], specialized for errors during *inverse tangent* computation on a *complex number*.\n\nRepresents failures from [`ATan::try_atan()`].\n\n# Type Parameters\n\n- `RawComplex`: Implements [`RawComplexTrait`]. Defines input error type via `ErrIn<RawComplex>` and output raw error via `<RawComplex as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input { source: ErrIn<RawComplex> }`: Input was invalid (e.g., components are NaN, Infinity, or a pole like `0 +/- 1i`).\n- `Output { source: <RawComplex as RawScalarValidate>::ValidationError }`: Computed output was invalid (e.g., components are NaN, Infinity)."];
259)]
260#[doc = enum_doc]
261pub type enum_name<RawComplex> =
262    FunctionErrors<ErrIn<RawComplex>, <RawComplex as RawScalarValidate>::ValidationError>;
263
264//------------------------------------------------------------------------------------------------
265// Trigonometric Traits (Sin, Cos, Tan, ASin, ACos, ATan)
266//------------------------------------------------------------------------------------------------
267#[duplicate_item(
268    trait_name try_func   func   trait_doc try_func_doc func_doc err_doc;
269    [ACos]     [try_acos] [acos] ["Trait for computing the *inverse cosine* of a number.\n\nThis trait defines methods for computing the *inverse cosine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_acos` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_acos`: Computes the inverse cosine of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `acos`: Computes the inverse cosine of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]     ["Computes the *inverse cosine* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."]  ["Computes and returns the *inverse cosine* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_acos` method for safe computations."]  ["The error type that is returned by the `try_acos` method."];
270    [ASin]     [try_asin] [asin] ["Trait for computing the *inverse sine* of a number.\n\nThis trait defines methods for computing the *inverse sine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_asin` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_asin`: Computes the inverse sine of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `asin`: Computes the inverse sine of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]             ["Computes the *inverse sine* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."]    ["Computes and returns the *inverse sine* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_asin` method for safe computations."]    ["The error type that is returned by the `try_asin` method."];
271    [ATan]     [try_atan] [atan] ["Trait for computing the *inverse tangent* of a number.\n\nThis trait defines methods for computing the *inverse tangent* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_atan` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_atan`: Computes the inverse tangent of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `atan`: Computes the inverse tangent of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."] ["Computes the *inverse tangent* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."] ["Computes and returns the *inverse tangent* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_atan` method for safe computations."] ["The error type that is returned by the `try_atan` method."];
272    [Cos]      [try_cos]  [cos]  ["Trait for computing the *cosine* of a number.\n\nThis trait defines methods for computing the *cosine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_cos` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_cos`: Computes the cosine of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `cos`: Computes the cosine of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                        ["Computes the *cosine* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."]          ["Computes and returns the *cosine* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_cos` method for safe computations."]           ["The error type that is returned by the `try_cos` method."];
273    [Sin]      [try_sin]  [sin]  ["Trait for computing the *sine* of a number.\n\nThis trait defines methods for computing the *sine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_sin` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_sin`: Computes the sine of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `sin`: Computes the sine of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                                ["Computes the *sine* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."]            ["Computes and returns the *sine* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_sin` method for safe computations."]             ["The error type that is returned by the `try_sin` method."]; 
274    [Tan]      [try_tan]  [tan]  ["Trait for computing the *tangent* of a number.\n\nThis trait defines methods for computing the *tangent* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_tan` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_tan`: Computes the tangent of the number and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n - `tan`: Computes the tangent of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                    ["Computes the *tangent* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Error`] type."]         ["Computes and returns the *tangent* of `self`.\n\nIn Debug mode this method may panic if the computation fails.\n\n# Panics\n\nIn Debug mode this method may panic if the computation fails. It is recommended to use the `try_tan` method for safe computations."]          ["The error type that is returned by the `try_tan` method."];
275)]
276#[doc = trait_doc]
277pub trait trait_name: Sized {
278    #[doc = err_doc]
279    type Error: std::error::Error;
280
281    #[doc = try_func_doc]
282    #[must_use = "this `Result` may contain an error that should be handled"]
283    fn try_func(self) -> Result<Self, <Self as trait_name>::Error>;
284
285    #[doc = func_doc]
286    fn func(self) -> Self;
287}
288
289#[duplicate_item(
290    type_name        trait_name Err                 ErrIn                    try_func   func;
291    [T]            [Sin]      [SinErrors]         [SinInputErrors]         [try_sin]  [sin];
292    [Complex::<T>] [Sin]      [SinErrors]         [SinInputErrors]         [try_sin]  [sin];
293    [T]            [Cos]      [CosErrors]         [CosInputErrors]         [try_cos]  [cos];
294    [Complex::<T>] [Cos]      [CosErrors]         [CosInputErrors]         [try_cos]  [cos];
295    [T]            [ATan]     [ATanRealErrors]    [ATanRealInputErrors]    [try_atan] [atan];
296)]
297impl<T> trait_name for type_name
298where
299    T: NativeReal,
300{
301    type Error = Err<type_name>;
302
303    #[inline(always)]
304    fn try_func(self) -> Result<Self, Self::Error> {
305        #[cfg(debug_assertions)]
306        {
307            self.validate_raw_scalar()
308                .map_err(|e| ErrIn::InvalidArgument { source: e }.into())
309                .and_then(|v| {
310                    type_name::func(v)
311                        .validate_raw_scalar()
312                        .map_err(|e| Err::Output { source: e })
313                })
314        }
315        #[cfg(not(debug_assertions))]
316        {
317            Ok(type_name::func(self))
318        }
319    }
320
321    #[inline(always)]
322    fn func(self) -> Self {
323        #[cfg(debug_assertions)]
324        {
325            self.try_func().unwrap()
326        }
327        #[cfg(not(debug_assertions))]
328        {
329            type_name::func(self)
330        }
331    }
332}
333
334#[duplicate_item(
335    type_name      trait_name Err                 ErrIn                    try_func   func;
336    [Complex::<T>] [Tan]      [TanComplexErrors]  [TanComplexInputErrors]  [try_tan]  [tan];
337    [Complex::<T>] [ASin]     [ASinComplexErrors] [ASinComplexInputErrors] [try_asin] [asin];
338    [Complex::<T>] [ACos]     [ACosComplexErrors] [ACosComplexInputErrors] [try_acos] [acos];
339
340)]
341impl<T> trait_name for type_name
342where
343    Self: RawComplexTrait<RawReal = T>,
344    T: NativeReal,
345{
346    type Error = Err<type_name>;
347
348    #[inline(always)]
349    fn try_func(self) -> Result<Self, Self::Error> {
350        #[cfg(debug_assertions)]
351        {
352            self.validate_raw_scalar()
353                .map_err(|e| ErrIn::InvalidArgument { source: e }.into())
354                .and_then(|v| {
355                    type_name::func(v)
356                        .validate_raw_scalar()
357                        .map_err(|e| Err::Output { source: e })
358                })
359        }
360        #[cfg(not(debug_assertions))]
361        {
362            Ok(type_name::func(self))
363        }
364    }
365
366    #[inline(always)]
367    fn func(self) -> Self {
368        #[cfg(debug_assertions)]
369        {
370            self.try_func().unwrap()
371        }
372        #[cfg(not(debug_assertions))]
373        {
374            type_name::func(self)
375        }
376    }
377}
378
379impl<T> Tan for T
380where
381    T: NativeReal,
382{
383    type Error = TanRealErrors<T>;
384
385    #[inline(always)]
386    fn try_tan(self) -> Result<Self, Self::Error> {
387        #[cfg(debug_assertions)]
388        {
389            self.validate_raw_scalar()
390                .map_err(|e| TanRealInputErrors::InvalidArgument { source: e }.into())
391                .and_then(|v| {
392                    // Check if the cosine of the value is zero, which would indicate a pole
393                    // for the tangent function (e.g., π/2, 3π/2, etc.).
394                    // If it is, return an error indicating the argument is a pole.
395                    // This is a more efficient check than computing the tangent directly.
396                    // Note: This check is valid because tan(x) = sin(x) / cos(x), and if cos(x) == 0,
397                    // then tan(x) is undefined (pole).
398                    if <T as Zero>::is_zero(&<T as Float>::cos(v)) {
399                        Err(TanRealInputErrors::ArgumentIsPole {
400                            value: v,
401                            backtrace: capture_backtrace(),
402                        }
403                        .into())
404                    } else {
405                        <T as Float>::tan(v)
406                            .validate_raw_scalar()
407                            .map_err(|e| TanRealErrors::Output { source: e })
408                    }
409                })
410        }
411        #[cfg(not(debug_assertions))]
412        {
413            Ok(<T as Float>::tan(self))
414        }
415    }
416
417    #[inline(always)]
418    fn tan(self) -> Self {
419        #[cfg(debug_assertions)]
420        {
421            self.try_tan().unwrap()
422        }
423        #[cfg(not(debug_assertions))]
424        {
425            <T as Float>::tan(self)
426        }
427    }
428}
429
430#[duplicate_item(
431    my_trait E                ErrIn                 try_func   func;
432    [ASin]   [ASinRealErrors] [ASinRealInputErrors] [try_asin] [asin];
433    [ACos]   [ACosRealErrors] [ACosRealInputErrors] [try_acos] [acos];
434)]
435impl<T> my_trait for T
436where
437    T: NativeReal,
438{
439    type Error = E<T>;
440
441    #[inline(always)]
442    fn try_func(self) -> Result<Self, <Self as my_trait>::Error> {
443        #[cfg(debug_assertions)]
444        {
445            self.validate_raw_scalar()
446                .map_err(|e| ErrIn::InvalidArgument { source: e }.into())
447                .and_then(|v| {
448                    if !(T::negative_one()..=T::one()).contains(&v) {
449                        Err(ErrIn::OutOfDomain {
450                            value: v,
451                            backtrace: capture_backtrace(),
452                        }
453                        .into())
454                    } else {
455                        <T as Float>::func(v)
456                            .validate_raw_scalar()
457                            .map_err(|e| E::Output { source: e })
458                    }
459                })
460        }
461        #[cfg(not(debug_assertions))]
462        {
463            Ok(<T as Float>::func(self))
464        }
465    }
466
467    #[inline(always)]
468    fn func(self) -> Self {
469        #[cfg(debug_assertions)]
470        {
471            self.try_func().unwrap()
472        }
473        #[cfg(not(debug_assertions))]
474        {
475            <T as Float>::func(self)
476        }
477    }
478}
479
480impl<T> ATan for Complex<T>
481where
482    Self: RawComplexTrait<RawReal = T>,
483    T: NativeReal,
484{
485    type Error = ATanComplexErrors<Complex<T>>;
486
487    #[inline(always)]
488    fn try_atan(self) -> Result<Self, <Self as ATan>::Error> {
489        #[cfg(debug_assertions)]
490        {
491            if self.re == T::zero() && self.im.abs() == T::one() {
492                Err(ATanComplexInputErrors::ArgumentIsPole {
493                    value: self,
494                    backtrace: capture_backtrace(),
495                }
496                .into())
497            } else {
498                self.validate_raw_scalar()
499                    .map_err(|e| ATanComplexInputErrors::InvalidArgument { source: e }.into())
500                    .and_then(|v| {
501                        Complex::<T>::atan(v)
502                            .validate_raw_scalar()
503                            .map_err(|e| Self::Error::Output { source: e })
504                    })
505            }
506        }
507        #[cfg(not(debug_assertions))]
508        {
509            Ok(Complex::<T>::atan(self))
510        }
511    }
512
513    #[inline(always)]
514    fn atan(self) -> Self {
515        #[cfg(debug_assertions)]
516        {
517            self.try_atan().unwrap()
518        }
519        #[cfg(not(debug_assertions))]
520        {
521            Complex::<T>::atan(self)
522        }
523    }
524}
525
526//------------------------------------------------------------------------------------------------
527
528//------------------------------------------------------------------------------------------------
529/// Errors that can occur during the input validation phase when attempting to compute
530/// the 2-argument arctangent (`atan2`).
531///
532/// This enum is used as a source for the `Input` variant of [`ATan2Errors`].
533/// It is generic over `RawReal: RawRealTrait`, which defines the specific raw real number type
534/// (via `RawReal: RawRealTrait`) and its associated validation error type (via `<RawReal as RawScalarValidate>::ValidationError`)
535/// for the numerator and denominator inputs.
536///
537/// `atan2(y, x)` computes the principal value of the arctangent of `y/x`, using the
538/// signs of both arguments to determine the quadrant of the result.
539#[derive(Debug, Error)]
540pub enum ATan2InputErrors<RawReal: RawRealTrait> {
541    /// The numerator (`y` in `atan2(y, x)`) failed basic validation checks.
542    ///
543    /// This error occurs if the numerator itself is considered invalid
544    /// according to the validation policy (e.g., [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy)),
545    /// such as being NaN or Infinity.
546    #[error("the numerator is invalid!")]
547    InvalidNumerator {
548        /// The underlying validation error from the numerator's raw real type.
549        #[source]
550        #[backtrace]
551        source: <RawReal as RawScalarValidate>::ValidationError,
552    },
553
554    /// The denominator (`x` in `atan2(y, x)`) failed basic validation checks.
555    ///
556    /// This error occurs if the denominator itself is considered invalid
557    /// according to the validation policy (e.g., [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy)),
558    /// such as being NaN or Infinity.
559    #[error("the denominator is invalid!")]
560    InvalidDenominator {
561        /// The underlying validation error from the denominator's raw real type.
562        #[source]
563        #[backtrace]
564        source: <RawReal as RawScalarValidate>::ValidationError,
565    },
566
567    /// Both the numerator (`y`) and the denominator (`x`) are zero.
568    ///
569    /// The `atan2(0, 0)` case is undefined or implementation-specific in many contexts.
570    /// This library considers it an error.
571    #[error("the numerator and the denominator are both zero!")]
572    ZeroOverZero {
573        /// A captured backtrace for debugging purposes.
574        backtrace: Backtrace,
575    },
576}
577
578/// A type alias for [`FunctionErrors`], specialized for errors that can occur during
579/// the computation of the 2-argument arctangent (`atan2`).
580///
581/// This type represents the possible failures when calling [`ATan2::try_atan2()`].
582///
583/// # Generic Parameters
584///
585/// - `RawReal`: A type that implements [`RawRealTrait`]. This type parameter defines:
586///   - The type for the input arguments of `atan2` via [`ATan2InputErrors<RawReal>`].
587///   - The raw error type for validating the real number inputs and the output, via `<RawReal as RawScalarTrait>::RawErrors`.
588///     This is typically [`crate::core::errors::ErrorsValidationRawReal<f64>`] for `f64` or a similar type
589///     for other numeric backends.
590///
591/// # Variants
592///
593/// This type alias wraps [`FunctionErrors`], which has the following variants in this context:
594///
595/// - `Input { source: ATan2InputErrors<RawReal> }`:
596///   Indicates that one or both input arguments (`y` or `x` in `atan2(y, x)`) were invalid.
597///   This could be due to:
598///     - The numerator failing general validation checks (e.g., NaN, Infinity).
599///     - The denominator failing general validation checks (e.g., NaN, Infinity).
600///     - Both numerator and denominator being zero.
601///
602///   The `source` field provides more specific details via [`ATan2InputErrors`].
603///
604/// - `Output { source: <RawReal as RawScalarTrait>::RawErrors }`:
605///   Indicates that the computed result of `atan2` itself failed validation.
606///   This typically means the result yielded a non-finite value (e.g., NaN or Infinity),
607///   which should generally not happen if the inputs are valid and finite (excluding 0/0).
608///   The `source` field contains the raw validation error for the output real number.
609pub type ATan2Errors<RawReal> =
610    FunctionErrors<ATan2InputErrors<RawReal>, <RawReal as RawScalarValidate>::ValidationError>;
611
612/// Trait for computing the [*2-argument arctangent*](https://en.wikipedia.org/wiki/Atan2)
613/// of two numbers, `y` (self) and `x` (denominator).
614///
615/// The `atan2(y, x)` function calculates the principal value of the arctangent of `y/x`,
616/// using the signs of both arguments to determine the correct quadrant of the result.
617/// The result is an angle in radians, typically in the range `(-π, π]`.
618///
619/// This trait provides two methods:
620/// - [`try_atan2`](ATan2::try_atan2): A fallible version that performs validation on
621///   both inputs (numerator `self` and denominator `x`) and potentially the output.
622///   It returns a [`Result`]. This is the preferred method for robust error handling.
623/// - [`atan2`](ATan2::atan2): A convenient infallible version that panics if `try_atan2`
624///   would return an error in debug builds, or directly computes the value in release builds.
625///   Use this when inputs are known to be valid or when panicking on error is acceptable.
626///
627/// # Associated Types
628///
629/// - `Error`: The error type returned by the [`try_atan2`](ATan2::try_atan2) method.
630///   This type must implement [`std::error::Error`]. For `f64`, this is typically
631///   [`ATan2Errors<f64>`].
632///
633/// # Required Methods
634///
635/// - `try_atan2(self, denominator: &Self) -> Result<Self, Self::Error>`:
636///   Attempts to compute `atan2(self, denominator)`.
637///   Validates both `self` (numerator) and `denominator` using [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
638///   Also considers the case `atan2(0, 0)` as an error ([`ATan2InputErrors::ZeroOverZero`]).
639///   The output is also validated using [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
640///
641/// - `atan2(self, denominator: &Self) -> Self`:
642///   Computes `atan2(self, denominator)` directly.
643///   In debug builds, this calls `try_atan2` and unwraps.
644///   In release builds, this typically calls the underlying standard library's `atan2` function.
645///
646/// # Example
647///
648/// ```
649/// use num_valid::{functions::ATan2, backends::native::raw::Native64}; // Assuming Native64 implements ATan2
650///
651/// let y = 1.0; // Represents the numerator
652/// let x = 1.0; // Represents the denominator
653///
654/// // Using the fallible method
655/// match y.try_atan2(&x) {
656///     Ok(result) => println!("atan2(y, x): {}", result), // Expected: π/4 (approx 0.785)
657///     Err(e) => println!("Error: {:?}", e),
658/// }
659///
660/// // Using the infallible method (panics on error in debug)
661/// let result = ATan2::atan2(y, &x);
662/// println!("atan2(y, x): {}", result);
663///
664/// // Example of an error case (0/0)
665/// let y_zero = 0.0;
666/// let x_zero = 0.0;
667/// match y_zero.try_atan2(&x_zero) {
668///     Ok(_) => println!("This should not happen for 0/0"),
669///     Err(e) => println!("Error for atan2(0,0): {:?}", e), // Expected: ZeroOverZero error
670/// }
671/// ```
672pub trait ATan2: Sized {
673    /// The error type that is returned by the `try_atan2` method.
674    type Error: std::error::Error;
675
676    /// Computes the arctangent of `self` (numerator `y`) and `denominator` (`x`),
677    /// returning a [`Result`].
678    ///
679    /// This method validates both inputs to ensure they are finite numbers
680    /// (not NaN, Infinity, or subnormal) using the [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
681    /// The specific case where both `self` and `denominator` are zero is
682    /// considered an error ([`ATan2InputErrors::ZeroOverZero`]).
683    /// The computed result is also validated to be a finite number.
684    ///
685    /// # Arguments
686    ///
687    /// * `self`: The numerator `y` of the `atan2(y, x)` operation.
688    /// * `denominator`: A reference to the denominator `x` of the `atan2(y, x)` operation.
689    ///
690    /// # Errors
691    ///
692    /// Returns `Err(Self::Error)` if:
693    /// - Either `self` or `denominator` fails validation (e.g., NaN, Infinity).
694    /// - Both `self` and `denominator` are zero.
695    /// - The computed result fails validation (e.g., results in NaN or Infinity,
696    ///   though this is less common for `atan2` with valid finite inputs).
697    #[must_use = "this `Result` may contain an error that should be handled"]
698    fn try_atan2(self, denominator: &Self) -> Result<Self, Self::Error>;
699
700    /// Computes the arctangent of `self` (numerator `y`) and `denominator` (`x`),
701    /// returning the result directly.
702    fn atan2(self, denominator: &Self) -> Self;
703}
704
705impl<T> ATan2 for T
706where
707    T: NativeReal,
708{
709    /// The error type that is returned by the `try_atan2` method.
710    type Error = ATan2Errors<T>;
711
712    /// Computes the arctangent of `self` (numerator `y`) and `denominator` (`x`),
713    /// returning a [`Result`].
714    ///
715    /// This method validates both inputs to ensure they are finite numbers
716    /// (not NaN, Infinity, or subnormal) using the [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
717    /// The specific case where both `self` and `denominator` are zero is
718    /// considered an error ([`ATan2InputErrors::ZeroOverZero`]).
719    /// The computed result is also validated to be a finite number.
720    ///
721    /// # Arguments
722    ///
723    /// * `self`: The numerator `y` of the `atan2(y, x)` operation.
724    /// * `denominator`: A reference to the denominator `x` of the `atan2(y, x)` operation.
725    ///
726    /// # Errors
727    ///
728    /// Returns `Err(Self::Error)` if:
729    /// - Either `self` or `denominator` fails validation (e.g., NaN, Infinity).
730    /// - Both `self` and `denominator` are zero.
731    /// - The computed result fails validation (e.g., results in NaN or Infinity,
732    ///   though this is less common for `atan2` with valid finite inputs).
733    ///
734    /// # Note on Infinite Inputs
735    ///
736    /// This implementation, using `StrictFinitePolicy`, rejects infinite inputs and
737    /// returns an `InvalidArgument` error. This differs from some standard library
738    /// implementations (like `libm` or `std::f64::atan2`) which may return specific
739    /// values for infinite arguments.
740    fn try_atan2(self, denominator: &Self) -> Result<Self, Self::Error> {
741        #[cfg(debug_assertions)]
742        {
743            // Validate the denominator
744            denominator
745                .validate_raw_scalar_ref()
746                .map_err(|e| ATan2InputErrors::InvalidDenominator { source: e })?;
747
748            // Validate the numerator
749            let numerator = self
750                .validate_raw_scalar()
751                .map_err(|e| ATan2InputErrors::InvalidNumerator { source: e })?;
752
753            // Check for the specific case of 0/0
754            // This is a special case that is often considered undefined or implementation-specific.
755            // Here, we treat it as an error.
756            // Note: This is different from the standard library's behavior, which returns NaN.
757            let zero = T::zero();
758            if numerator == zero && *denominator == zero {
759                Err(ATan2InputErrors::ZeroOverZero {
760                    backtrace: capture_backtrace(),
761                }
762                .into())
763            } else {
764                <T as Float>::atan2(self, *denominator)
765                    .validate_raw_scalar()
766                    .map_err(|e| ATan2Errors::Output { source: e })
767            }
768        }
769        #[cfg(not(debug_assertions))]
770        {
771            Ok(<T as Float>::atan2(self, *denominator))
772        }
773    }
774
775    /// Computes the arctangent of `self` (numerator `y`) and `denominator` (`x`),
776    /// returning the result directly.
777    ///
778    /// # Behavior
779    ///
780    /// - In **debug builds** (`#[cfg(debug_assertions)]`): This method calls
781    ///   [`try_atan2()`](ATan2::try_atan2) and unwraps the result. It will panic if `try_atan2`
782    ///   returns an error.
783    /// - In **release builds** (`#[cfg(not(debug_assertions))]`): This method typically
784    ///   calls the underlying standard library's `atan2` function directly for performance,
785    ///   bypassing the explicit validations performed by `try_atan2`.
786    ///
787    /// # Arguments
788    ///
789    /// * `self`: The numerator `y` of the `atan2(y, x)` operation.
790    /// * `denominator`: A reference to the denominator `x` of the `atan2(y, x)` operation.
791    ///
792    /// # Panics
793    ///
794    /// This method will panic in debug builds if `try_atan2()` would return an `Err`.
795    /// In release builds, the behavior for invalid inputs (like NaN or Infinity)
796    /// will match the underlying standard library function (e.g., `f64::atan2(f64::NAN, 1.0)` is `NAN`).
797    fn atan2(self, denominator: &Self) -> Self {
798        #[cfg(debug_assertions)]
799        {
800            self.try_atan2(denominator).unwrap()
801        }
802        #[cfg(not(debug_assertions))]
803        {
804            <T as Float>::atan2(self, *denominator)
805        }
806    }
807}
808//------------------------------------------------------------------------------------------------
809
810//------------------------------------------------------------------------------------------------
811/// A convenience trait that aggregates the standard trigonometric functions and their inverses.
812///
813/// This trait serves as a shorthand for requiring a type to implement all the fundamental
814/// trigonometric operations:
815/// - [`Sin`] and [`ASin`]
816/// - [`Cos`] and [`ACos`]
817/// - [`Tan`] and [`ATan`]
818///
819/// It is primarily used as a super-trait for [`FpScalar`](crate::FpScalar) to simplify trait bounds
820/// and ensure that any scalar type in the library provides a comprehensive set of trigonometric
821/// capabilities. By using `TrigonometricFunctions` as a bound, you can write generic functions that
822/// utilize any of its constituent trait methods.
823///
824/// # Examples
825///
826/// ```
827/// use num_valid::{FpScalar ,functions::{TrigonometricFunctions, Sin, Cos}};
828/// use std::ops::{Add, Mul};
829///
830/// // A generic function that verifies the identity sin(x)^2 + cos(x)^2 = 1.
831/// // We bound T by FpScalar which implies TrigonometricFunctions, Clone, and arithmetic ops.
832/// fn verify_trig_identity<T>(x: T) -> T
833/// where
834///     T: TrigonometricFunctions + Clone + Mul<Output = T> + Add<Output = T>,
835/// {
836///     let sin_x = x.clone().sin();
837///     let cos_x = x.cos();
838///     // This works because FpScalar requires the necessary arithmetic traits.
839///     sin_x.clone() * sin_x + cos_x.clone() * cos_x
840/// }
841///
842/// let angle = 0.5f64;
843/// let identity = verify_trig_identity(angle);
844///
845/// // The result should be very close to 1.0.
846/// assert!((identity - 1.0).abs() < 1e-15);
847/// ```
848pub trait TrigonometricFunctions: Sin + ASin + Cos + ACos + Tan + ATan {}
849
850impl<T> TrigonometricFunctions for T where T: Sin + ASin + Cos + ACos + Tan + ATan {}
851//------------------------------------------------------------------------------------------------
852
853//------------------------------------------------------------------------------------------------
854#[cfg(test)]
855mod tests {
856    use super::*;
857    use approx::assert_ulps_eq;
858    use num::Complex;
859
860    #[cfg(feature = "rug")]
861    use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
862
863    #[cfg(feature = "rug")]
864    use try_create::TryNew;
865
866    mod sin {
867        use super::*;
868
869        mod native {
870            use super::*;
871
872            mod real {
873                use super::*;
874
875                #[test]
876                fn sin_valid() {
877                    let value = 4.0;
878                    let expected_result = -0.7568024953079282;
879                    assert_ulps_eq!(value.try_sin().unwrap(), expected_result);
880                    assert_ulps_eq!(<f64 as Float>::sin(value), expected_result);
881                    assert_ulps_eq!(<f64 as Sin>::sin(value), expected_result);
882                }
883
884                #[test]
885                fn sin_negative() {
886                    let value = -4.0;
887                    let expected_result = 0.7568024953079282;
888                    assert_ulps_eq!(value.try_sin().unwrap(), expected_result);
889                    assert_ulps_eq!(<f64 as Float>::sin(value), expected_result);
890                    assert_ulps_eq!(<f64 as Sin>::sin(value), expected_result);
891                }
892
893                #[test]
894                fn sin_zero() {
895                    let value = 0.0;
896                    assert_eq!(value.try_sin().unwrap(), 0.0);
897                    assert_eq!(<f64 as Float>::sin(value), 0.0);
898                    assert_eq!(<f64 as Sin>::sin(value), 0.0);
899                }
900
901                #[test]
902                #[cfg(debug_assertions)]
903                fn sin_nan() {
904                    let value = f64::NAN;
905                    let result = value.try_sin();
906                    assert!(matches!(result, Err(SinErrors::Input(..))));
907                }
908
909                #[test]
910                #[cfg(debug_assertions)]
911                fn sin_infinity() {
912                    let value = f64::INFINITY;
913                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
914                }
915
916                #[test]
917                #[cfg(debug_assertions)]
918                fn sin_subnormal() {
919                    let value = f64::MIN_POSITIVE / 2.0;
920                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
921                }
922            }
923
924            mod complex {
925                use super::*;
926
927                #[test]
928                fn sin_valid() {
929                    let value = Complex::new(4.0, 1.0);
930                    let expected_result = if cfg!(target_arch = "x86_64") {
931                        Complex::new(-1.1678072748895183, -0.7681627634565731)
932                    } else if cfg!(target_arch = "aarch64") {
933                        Complex::new(-1.1678072748895185, -0.7681627634565731)
934                    } else {
935                        todo!("Architecture not-tested");
936                    };
937
938                    assert_eq!(value.try_sin().unwrap(), expected_result);
939                    assert_eq!(<Complex<f64> as Sin>::sin(value), expected_result);
940                    assert_eq!(value.sin(), expected_result);
941                }
942
943                #[test]
944                fn sin_zero() {
945                    let value = Complex::new(0.0, 0.0);
946                    let expected_result = Complex::new(0.0, 0.0);
947                    assert_eq!(value.try_sin().unwrap(), expected_result);
948                    assert_eq!(value.sin(), expected_result);
949                }
950
951                #[test]
952                #[cfg(debug_assertions)]
953                fn sin_nan() {
954                    let value = Complex::new(f64::NAN, 0.0);
955                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
956
957                    let value = Complex::new(0.0, f64::NAN);
958                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
959                }
960
961                #[test]
962                #[cfg(debug_assertions)]
963                fn sin_infinity() {
964                    let value = Complex::new(f64::INFINITY, 0.0);
965                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
966
967                    let value = Complex::new(0.0, f64::INFINITY);
968                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
969                }
970
971                #[test]
972                #[cfg(debug_assertions)]
973                fn sin_subnormal() {
974                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
975                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
976
977                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
978                    assert!(matches!(value.try_sin(), Err(SinErrors::Input(..))));
979                }
980            }
981        }
982
983        #[cfg(feature = "rug")]
984        mod rug53 {
985            use super::*;
986
987            mod real {
988                use super::*;
989
990                #[test]
991                fn test_rug_float_sin_valid() {
992                    let value =
993                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
994
995                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
996                        53,
997                        7.568024953079282e-1,
998                    ))
999                    .unwrap();
1000                    assert_eq!(value.clone().try_sin().unwrap(), expected_result);
1001                    assert_eq!(value.sin(), expected_result);
1002                }
1003
1004                #[test]
1005                fn test_rug_float_sin_zero() {
1006                    let value =
1007                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1008
1009                    let expected_result =
1010                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1011                    assert_eq!(value.clone().try_sin().unwrap(), expected_result);
1012                    assert_eq!(value.sin(), expected_result);
1013                }
1014            }
1015
1016            mod complex {
1017                use super::*;
1018
1019                #[test]
1020                fn test_complex_rug_float_sin_valid() {
1021                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1022                        53,
1023                        (rug::Float::with_val(53, 4.0), rug::Float::with_val(53, 1.0)),
1024                    ))
1025                    .unwrap();
1026
1027                    let expected_result =
1028                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1029                            53,
1030                            (
1031                                rug::Float::with_val(53, -1.1678072748895185),
1032                                rug::Float::with_val(53, -7.681627634565731e-1),
1033                            ),
1034                        ))
1035                        .unwrap();
1036                    assert_eq!(value.clone().try_sin().unwrap(), expected_result);
1037                    assert_eq!(value.sin(), expected_result);
1038                }
1039
1040                #[test]
1041                fn test_complex_rug_float_sin_zero() {
1042                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1043                        53,
1044                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1045                    ))
1046                    .unwrap();
1047
1048                    let expected_result =
1049                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1050                            53,
1051                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
1052                        ))
1053                        .unwrap();
1054                    assert_eq!(value.clone().try_sin().unwrap(), expected_result);
1055                    assert_eq!(value.sin(), expected_result);
1056                }
1057            }
1058        }
1059    }
1060
1061    mod cos {
1062        use super::*;
1063
1064        mod native {
1065            use super::*;
1066
1067            mod real {
1068                use super::*;
1069
1070                #[test]
1071                fn cos_valid() {
1072                    let value = 4.0;
1073                    let expected_result = -0.6536436208636119;
1074                    assert_eq!(value.try_cos().unwrap(), expected_result);
1075                    assert_ulps_eq!(<f64 as Float>::cos(value), expected_result);
1076                    assert_ulps_eq!(<f64 as Cos>::cos(value), expected_result);
1077                }
1078
1079                #[test]
1080                fn cos_negative() {
1081                    let value = -4.0;
1082                    let expected_result = -0.6536436208636119;
1083                    assert_eq!(value.try_cos().unwrap(), expected_result);
1084                    assert_ulps_eq!(<f64 as Float>::cos(value), expected_result);
1085                    assert_ulps_eq!(<f64 as Cos>::cos(value), expected_result);
1086                }
1087
1088                #[test]
1089                fn cos_zero() {
1090                    let value = 0.0;
1091                    assert_eq!(value.try_cos().unwrap(), 1.0);
1092                    assert_ulps_eq!(<f64 as Float>::cos(value), 1.0);
1093                    assert_ulps_eq!(<f64 as Cos>::cos(value), 1.0);
1094                }
1095
1096                #[test]
1097                #[cfg(debug_assertions)]
1098                fn cos_nan() {
1099                    let value = f64::NAN;
1100                    let result = value.try_cos();
1101                    assert!(matches!(result, Err(CosErrors::Input(..))));
1102                }
1103
1104                #[test]
1105                #[cfg(debug_assertions)]
1106                fn cos_infinity() {
1107                    let value = f64::INFINITY;
1108                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1109                }
1110
1111                #[test]
1112                #[cfg(debug_assertions)]
1113                fn cos_subnormal() {
1114                    let value = f64::MIN_POSITIVE / 2.0;
1115                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1116                }
1117            }
1118
1119            mod complex {
1120                use super::*;
1121
1122                #[test]
1123                fn cos_valid() {
1124                    let value = Complex::new(4.0, 1.0);
1125                    let expected_result = if cfg!(target_arch = "x86_64") {
1126                        Complex::new(-1.0086248134251568, 0.8893951958384846)
1127                    } else if cfg!(target_arch = "aarch64") {
1128                        Complex::new(-1.0086248134251568, 0.8893951958384847)
1129                    } else {
1130                        todo!("Architecture not-tested");
1131                    };
1132                    assert_eq!(value.try_cos().unwrap(), expected_result);
1133                    assert_eq!(<Complex<f64> as Cos>::cos(value), expected_result);
1134                    assert_eq!(value.cos(), expected_result);
1135                }
1136
1137                #[test]
1138                fn cos_zero() {
1139                    let value = Complex::new(0.0, 0.0);
1140                    let expected_result = Complex::new(1.0, 0.0);
1141                    assert_eq!(value.try_cos().unwrap(), expected_result);
1142                    assert_eq!(value.cos(), expected_result);
1143                }
1144
1145                #[test]
1146                #[cfg(debug_assertions)]
1147                fn cos_nan() {
1148                    let value = Complex::new(f64::NAN, 0.0);
1149                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1150
1151                    let value = Complex::new(0.0, f64::NAN);
1152                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1153                }
1154
1155                #[test]
1156                #[cfg(debug_assertions)]
1157                fn cos_infinity() {
1158                    let value = Complex::new(f64::INFINITY, 0.0);
1159                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1160
1161                    let value = Complex::new(0.0, f64::INFINITY);
1162                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1163                }
1164
1165                #[test]
1166                #[cfg(debug_assertions)]
1167                fn cos_subnormal() {
1168                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1169                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1170
1171                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1172                    assert!(matches!(value.try_cos(), Err(CosErrors::Input(..))));
1173                }
1174            }
1175        }
1176
1177        #[cfg(feature = "rug")]
1178        mod rug53 {
1179            use super::*;
1180
1181            mod real {
1182                use super::*;
1183
1184                #[test]
1185                fn test_rug_float_cos_valid() {
1186                    let value =
1187                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
1188
1189                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1190                        53,
1191                        -0.6536436208636119,
1192                    ))
1193                    .unwrap();
1194                    assert_eq!(value.clone().try_cos().unwrap(), expected_result);
1195                    assert_eq!(value.cos(), expected_result);
1196                }
1197
1198                #[test]
1199                fn test_rug_float_cos_zero() {
1200                    let value =
1201                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1202
1203                    let expected_result =
1204                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
1205                    assert_eq!(value.clone().try_cos().unwrap(), expected_result);
1206                    assert_eq!(value.cos(), expected_result);
1207                }
1208            }
1209
1210            mod complex {
1211                use super::*;
1212
1213                #[test]
1214                fn test_complex_rug_float_cos_valid() {
1215                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1216                        53,
1217                        (rug::Float::with_val(53, 4.0), rug::Float::with_val(53, 1.0)),
1218                    ))
1219                    .unwrap();
1220
1221                    let expected_result =
1222                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1223                            53,
1224                            (
1225                                rug::Float::with_val(53, -1.0086248134251568),
1226                                rug::Float::with_val(53, 8.893951958384847e-1),
1227                            ),
1228                        ))
1229                        .unwrap();
1230                    assert_eq!(value.clone().try_cos().unwrap(), expected_result);
1231                    assert_eq!(value.cos(), expected_result);
1232                }
1233
1234                #[test]
1235                fn test_complex_rug_float_cos_zero() {
1236                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1237                        53,
1238                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1239                    ))
1240                    .unwrap();
1241
1242                    let expected_result =
1243                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1244                            53,
1245                            (rug::Float::with_val(53, 1.), rug::Float::with_val(53, 0.)),
1246                        ))
1247                        .unwrap();
1248                    assert_eq!(value.clone().try_cos().unwrap(), expected_result);
1249                    assert_eq!(value.cos(), expected_result);
1250                }
1251            }
1252        }
1253    }
1254
1255    mod tan {
1256        use super::*;
1257
1258        mod native {
1259            use super::*;
1260
1261            mod real {
1262                use super::*;
1263
1264                #[test]
1265                fn tan_valid() {
1266                    let value = 4.0;
1267                    let expected_result = 1.1578212823495775;
1268                    assert_eq!(value.try_tan().unwrap(), expected_result);
1269                    assert_eq!(<f64 as Tan>::tan(value), expected_result);
1270                    assert_eq!(value.tan(), expected_result);
1271                }
1272
1273                /*
1274                #[test]
1275                #[ignore = "at the moment we cannot generate a pole for the Tan function"]
1276                fn tan_argument_pole() {
1277                    let value = f64::pi_div_2();
1278                    let err = value.try_tan().unwrap_err();
1279                    assert!(matches!(
1280                        err,
1281                        TanRealErrors::Input(TanRealInputErrors::ArgumentIsPole { .. })
1282                    ));
1283                }
1284                */
1285
1286                #[test]
1287                fn tan_negative() {
1288                    let value = -4.0;
1289                    let expected_result = -1.1578212823495775;
1290                    assert_eq!(value.try_tan().unwrap(), expected_result);
1291                    assert_eq!(<f64 as Float>::tan(value), expected_result);
1292                    assert_eq!(<f64 as Tan>::tan(value), expected_result);
1293                }
1294
1295                #[test]
1296                fn tan_zero() {
1297                    let value = 0.0;
1298                    assert_eq!(value.try_tan().unwrap(), 0.0);
1299                    assert_eq!(<f64 as Float>::tan(value), 0.0);
1300                    assert_eq!(<f64 as Tan>::tan(value), 0.0);
1301                }
1302
1303                #[test]
1304                #[cfg(debug_assertions)]
1305                fn tan_nan() {
1306                    let value = f64::NAN;
1307                    let result = value.try_tan();
1308                    assert!(matches!(result, Err(TanRealErrors::Input(..))));
1309                }
1310
1311                #[test]
1312                #[cfg(debug_assertions)]
1313                fn tan_infinity() {
1314                    let value = f64::INFINITY;
1315                    assert!(matches!(value.try_tan(), Err(TanRealErrors::Input(..))));
1316                }
1317
1318                #[test]
1319                #[cfg(debug_assertions)]
1320                fn tan_subnormal() {
1321                    let value = f64::MIN_POSITIVE / 2.0;
1322                    assert!(matches!(value.try_tan(), Err(TanRealErrors::Input(..))));
1323                }
1324            }
1325
1326            mod complex {
1327                use super::*;
1328
1329                #[test]
1330                fn tan_valid() {
1331                    let value = Complex::new(4.0, 1.0);
1332                    let expected_result = Complex::new(0.27355308280730734, 1.002810507583505);
1333                    assert_eq!(value.try_tan().unwrap(), expected_result);
1334                    assert_eq!(<Complex<f64> as Tan>::tan(value), expected_result);
1335                    assert_eq!(value.tan(), expected_result);
1336                }
1337
1338                #[test]
1339                fn tan_zero() {
1340                    let value = Complex::new(0.0, 0.0);
1341                    let expected_result = Complex::new(0.0, 0.0);
1342                    assert_eq!(value.try_tan().unwrap(), expected_result);
1343                    assert_eq!(value.tan(), expected_result);
1344                }
1345
1346                #[test]
1347                #[cfg(debug_assertions)]
1348                fn tan_nan() {
1349                    let value = Complex::new(f64::NAN, 0.0);
1350                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1351
1352                    let value = Complex::new(0.0, f64::NAN);
1353                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1354                }
1355
1356                #[test]
1357                #[cfg(debug_assertions)]
1358                fn tan_infinity() {
1359                    let value = Complex::new(f64::INFINITY, 0.0);
1360                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1361
1362                    let value = Complex::new(0.0, f64::INFINITY);
1363                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1364                }
1365
1366                #[test]
1367                #[cfg(debug_assertions)]
1368                fn tan_subnormal() {
1369                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1370                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1371
1372                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1373                    assert!(matches!(value.try_tan(), Err(TanComplexErrors::Input(..))));
1374                }
1375            }
1376        }
1377
1378        #[cfg(feature = "rug")]
1379        mod rug53 {
1380            use super::*;
1381
1382            mod real {
1383                use super::*;
1384
1385                #[test]
1386                fn test_rug_float_tan_valid() {
1387                    let value =
1388                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
1389
1390                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1391                        53,
1392                        -1.1578212823495775,
1393                    ))
1394                    .unwrap();
1395                    assert_eq!(value.clone().try_tan().unwrap(), expected_result);
1396                    assert_eq!(value.tan(), expected_result);
1397                }
1398
1399                #[cfg(feature = "rug")]
1400                #[test]
1401                fn test_rug_float_tan_zero() {
1402                    let value =
1403                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1404
1405                    let expected_result =
1406                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1407                    assert_eq!(value.clone().try_tan().unwrap(), expected_result);
1408                    assert_eq!(value.tan(), expected_result);
1409                }
1410
1411                /*
1412                #[cfg(feature = "rug")]
1413                #[test]
1414                fn test_rug_float_tan_nan() {
1415                    let value =
1416                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, rug::float::Special::Nan))
1417                            .unwrap();
1418                    let result = value.try_tan();
1419                    assert!(matches!(result, Err(TanRealErrors::Input(..))));
1420                }
1421
1422
1423                #[cfg(feature = "rug")]
1424                #[test]
1425                fn test_rug_float_tan_infinite() {
1426                    let value = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1427                        53,
1428                        rug::float::Special::Infinity,
1429                    ))
1430                    .unwrap();
1431                    let result = value.try_tan();
1432                    assert!(matches!(result, Err(TanRealErrors::Input(..))));
1433                }
1434                */
1435            }
1436
1437            mod complex {
1438                use super::*;
1439
1440                #[test]
1441                fn test_complex_rug_float_tan_valid() {
1442                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1443                        53,
1444                        (rug::Float::with_val(53, 4.0), rug::Float::with_val(53, 1.0)),
1445                    ))
1446                    .unwrap();
1447
1448                    let expected_result =
1449                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1450                            53,
1451                            (
1452                                rug::Float::with_val(53, 2.7355308280730734e-1),
1453                                rug::Float::with_val(53, 1.002810507583505),
1454                            ),
1455                        ))
1456                        .unwrap();
1457                    assert_eq!(value.clone().try_tan().unwrap(), expected_result);
1458                    assert_eq!(value.tan(), expected_result);
1459                }
1460
1461                #[test]
1462                fn test_complex_rug_float_tan_zero() {
1463                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1464                        53,
1465                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1466                    ))
1467                    .unwrap();
1468
1469                    let expected_result =
1470                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1471                            53,
1472                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
1473                        ))
1474                        .unwrap();
1475                    assert_eq!(value.clone().try_tan().unwrap(), expected_result);
1476                    assert_eq!(value.tan(), expected_result);
1477                }
1478
1479                /*
1480
1481                #[test]
1482                fn test_complex_rug_float_tan_nan() {
1483                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1484                        53,
1485                        (
1486                            rug::Float::with_val(53, rug::float::Special::Nan),
1487                            rug::Float::with_val(53, 0.0),
1488                        ),
1489                    ))
1490                    .unwrap();
1491                    assert!(matches!(
1492                        value.try_tan(),
1493                        Err(TanComplexErrors::Input(..))
1494                    ));
1495                }
1496
1497                #[test]
1498                fn test_complex_rug_float_tan_infinite() {
1499                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1500                        53,
1501                        (
1502                            rug::Float::with_val(53, rug::float::Special::Infinity),
1503                            rug::Float::with_val(53, 0.0),
1504                        ),
1505                    ))
1506                    .unwrap();
1507                    assert!(matches!(
1508                        value.try_tan(),
1509                        Err(TanComplexErrors::Input(..))
1510                    ));
1511                }
1512                */
1513            }
1514        }
1515    }
1516
1517    mod atan {
1518        use super::*;
1519
1520        mod native {
1521            use super::*;
1522
1523            mod real {
1524                use super::*;
1525
1526                #[test]
1527                fn atan_valid() {
1528                    let value = 4.0;
1529                    let expected_result = 1.3258176636680326;
1530                    assert_eq!(value.try_atan().unwrap(), expected_result);
1531                    assert_eq!(<f64 as Float>::atan(value), expected_result);
1532                    assert_eq!(<f64 as ATan>::atan(value), expected_result);
1533                }
1534
1535                #[test]
1536                fn atan_negative() {
1537                    let value = -4.0;
1538                    let expected_result = -1.3258176636680326;
1539                    assert_eq!(value.try_atan().unwrap(), expected_result);
1540                    assert_eq!(<f64 as Float>::atan(value), expected_result);
1541                    assert_eq!(<f64 as ATan>::atan(value), expected_result);
1542                }
1543
1544                #[test]
1545                fn atan_zero() {
1546                    let value = 0.0;
1547                    assert_eq!(value.try_atan().unwrap(), 0.0);
1548                    assert_eq!(<f64 as Float>::atan(value), 0.0);
1549                    assert_eq!(<f64 as ATan>::atan(value), 0.0);
1550                }
1551                #[cfg(debug_assertions)]
1552                #[test]
1553                #[cfg(debug_assertions)]
1554                fn atan_nan() {
1555                    let value = f64::NAN;
1556                    let result = value.try_atan();
1557                    assert!(matches!(result, Err(ATanRealErrors::Input(..))));
1558                }
1559
1560                #[test]
1561                #[cfg(debug_assertions)]
1562                fn atan_infinity() {
1563                    let value = f64::INFINITY;
1564                    assert!(matches!(value.try_atan(), Err(ATanRealErrors::Input(..))));
1565                }
1566
1567                #[test]
1568                #[cfg(debug_assertions)]
1569                fn atan_subnormal() {
1570                    let value = f64::MIN_POSITIVE / 2.0;
1571                    assert!(matches!(value.try_atan(), Err(ATanRealErrors::Input(..))));
1572                }
1573            }
1574
1575            mod complex {
1576                use super::*;
1577
1578                #[test]
1579                fn atan_valid() {
1580                    let value = Complex::new(4.0, 1.0);
1581                    let expected_result = Complex::new(1.3389725222944935, 0.05578588782855254);
1582                    assert_eq!(value.try_atan().unwrap(), expected_result);
1583                    assert_eq!(<Complex<f64> as ATan>::atan(value), expected_result);
1584                    assert_eq!(value.atan(), expected_result);
1585                }
1586
1587                #[test]
1588                #[cfg(debug_assertions)]
1589                fn atan_out_of_domain() {
1590                    let value = Complex::new(0.0, 1.0);
1591                    let err = value.try_atan().unwrap_err();
1592                    assert!(matches!(
1593                        err,
1594                        ATanComplexErrors::Input(ATanComplexInputErrors::ArgumentIsPole { .. })
1595                    ));
1596
1597                    let value = Complex::new(0.0, -1.0);
1598                    let err = value.try_atan().unwrap_err();
1599                    assert!(matches!(
1600                        err,
1601                        ATanComplexErrors::Input(ATanComplexInputErrors::ArgumentIsPole { .. })
1602                    ));
1603                }
1604
1605                #[test]
1606                fn atan_zero() {
1607                    let value = Complex::new(0.0, 0.0);
1608                    let expected_result = Complex::new(0.0, 0.0);
1609                    assert_eq!(value.try_atan().unwrap(), expected_result);
1610                    assert_eq!(value.atan(), expected_result);
1611                }
1612
1613                #[test]
1614                #[cfg(debug_assertions)]
1615                fn atan_nan() {
1616                    let value = Complex::new(f64::NAN, 0.0);
1617                    assert!(matches!(
1618                        value.try_atan(),
1619                        Err(ATanComplexErrors::Input(..))
1620                    ));
1621
1622                    let value = Complex::new(0.0, f64::NAN);
1623                    assert!(matches!(
1624                        value.try_atan(),
1625                        Err(ATanComplexErrors::Input(..))
1626                    ));
1627                }
1628
1629                #[test]
1630                #[cfg(debug_assertions)]
1631                fn atan_infinity() {
1632                    let value = Complex::new(f64::INFINITY, 0.0);
1633                    assert!(matches!(
1634                        value.try_atan(),
1635                        Err(ATanComplexErrors::Input(..))
1636                    ));
1637
1638                    let value = Complex::new(0.0, f64::INFINITY);
1639                    assert!(matches!(
1640                        value.try_atan(),
1641                        Err(ATanComplexErrors::Input(..))
1642                    ));
1643                }
1644
1645                #[test]
1646                #[cfg(debug_assertions)]
1647                fn atan_subnormal() {
1648                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1649                    assert!(matches!(
1650                        value.try_atan(),
1651                        Err(ATanComplexErrors::Input(..))
1652                    ));
1653
1654                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1655                    assert!(matches!(
1656                        value.try_atan(),
1657                        Err(ATanComplexErrors::Input(..))
1658                    ));
1659                }
1660            }
1661        }
1662
1663        #[cfg(feature = "rug")]
1664        mod rug53 {
1665            use super::*;
1666
1667            mod real {
1668                use super::*;
1669
1670                #[test]
1671                fn test_rug_float_atan_valid() {
1672                    let value =
1673                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
1674
1675                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1676                        53,
1677                        -1.3258176636680326,
1678                    ))
1679                    .unwrap();
1680                    assert_eq!(value.clone().try_atan().unwrap(), expected_result);
1681                    assert_eq!(value.atan(), expected_result);
1682                }
1683
1684                #[test]
1685                fn test_rug_float_atan_zero() {
1686                    let value =
1687                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1688
1689                    let expected_result =
1690                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1691                    assert_eq!(value.clone().try_atan().unwrap(), expected_result);
1692                    assert_eq!(value.atan(), expected_result);
1693                }
1694            }
1695
1696            mod complex {
1697                use super::*;
1698
1699                #[test]
1700                fn test_complex_rug_float_atan_valid() {
1701                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1702                        53,
1703                        (rug::Float::with_val(53, 4.0), rug::Float::with_val(53, 1.0)),
1704                    ))
1705                    .unwrap();
1706
1707                    let expected_result =
1708                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1709                            53,
1710                            (
1711                                rug::Float::with_val(53, 1.3389725222944935),
1712                                rug::Float::with_val(53, 5.578588782855244e-2),
1713                            ),
1714                        ))
1715                        .unwrap();
1716                    assert_eq!(value.clone().try_atan().unwrap(), expected_result);
1717                    assert_eq!(value.atan(), expected_result);
1718                }
1719
1720                #[test]
1721                fn test_complex_rug_float_atan_zero() {
1722                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1723                        53,
1724                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1725                    ))
1726                    .unwrap();
1727
1728                    let expected_result =
1729                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1730                            53,
1731                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
1732                        ))
1733                        .unwrap();
1734                    assert_eq!(value.clone().try_atan().unwrap(), expected_result);
1735                    assert_eq!(value.atan(), expected_result);
1736                }
1737            }
1738        }
1739    }
1740
1741    mod asin {
1742        use super::*;
1743
1744        mod native {
1745            use super::*;
1746
1747            mod real {
1748                use super::*;
1749
1750                #[test]
1751                fn asin_valid() {
1752                    let value = 0.5;
1753                    let expected_result = std::f64::consts::FRAC_PI_6;
1754
1755                    assert_ulps_eq!(value.try_asin().unwrap(), expected_result);
1756                    assert_ulps_eq!(value.asin(), expected_result);
1757                }
1758
1759                #[test]
1760                fn asin_negative() {
1761                    let value = -0.5;
1762                    let expected_result = -std::f64::consts::FRAC_PI_6;
1763
1764                    assert_ulps_eq!(value.try_asin().unwrap(), expected_result);
1765                    assert_ulps_eq!(value.asin(), expected_result);
1766                }
1767
1768                #[test]
1769                fn asin_zero() {
1770                    let value = 0.0;
1771                    assert_eq!(Float::asin(value), 0.0);
1772                    assert_eq!(ASin::asin(value), 0.0);
1773                    assert_eq!(value.try_asin().unwrap(), 0.0);
1774                }
1775
1776                #[test]
1777                #[cfg(debug_assertions)]
1778                fn asin_out_of_bound() {
1779                    let value = 2.0;
1780                    let result = value.try_asin();
1781                    println!("result: {result:?}");
1782                    assert!(matches!(result, Err(ASinRealErrors::Input(..))));
1783                }
1784
1785                #[test]
1786                #[cfg(debug_assertions)]
1787                fn asin_nan() {
1788                    let value = f64::NAN;
1789                    let result = value.try_asin();
1790                    assert!(matches!(result, Err(ASinRealErrors::Input(..))));
1791                }
1792
1793                #[test]
1794                #[cfg(debug_assertions)]
1795                fn asin_infinity() {
1796                    let value = f64::INFINITY;
1797                    assert!(matches!(value.try_asin(), Err(ASinRealErrors::Input(..))));
1798                }
1799
1800                #[test]
1801                #[cfg(debug_assertions)]
1802                fn asin_subnormal() {
1803                    let value = f64::MIN_POSITIVE / 2.0;
1804                    assert!(matches!(value.try_asin(), Err(ASinRealErrors::Input(..))));
1805                }
1806            }
1807
1808            mod complex {
1809                use super::*;
1810
1811                #[test]
1812                fn asin_valid() {
1813                    let value = Complex::new(0.5, 0.5);
1814                    let expected_result = Complex::new(0.4522784471511907, 0.5306375309525178);
1815                    assert_eq!(value.try_asin().unwrap(), expected_result);
1816                    assert_eq!(<Complex<f64> as ASin>::asin(value), expected_result);
1817                    assert_eq!(value.asin(), expected_result);
1818                }
1819
1820                #[test]
1821                fn asin_zero() {
1822                    let value = Complex::new(0.0, 0.0);
1823                    let expected_result = Complex::new(0.0, 0.0);
1824                    assert_eq!(value.try_asin().unwrap(), expected_result);
1825                    assert_eq!(value.asin(), expected_result);
1826                }
1827
1828                #[test]
1829                #[cfg(debug_assertions)]
1830                fn asin_nan() {
1831                    let value = Complex::new(f64::NAN, 0.0);
1832                    assert!(matches!(
1833                        value.try_asin(),
1834                        Err(ASinComplexErrors::Input(..))
1835                    ));
1836
1837                    let value = Complex::new(0.0, f64::NAN);
1838                    assert!(matches!(
1839                        value.try_asin(),
1840                        Err(ASinComplexErrors::Input(..))
1841                    ));
1842                }
1843
1844                #[test]
1845                #[cfg(debug_assertions)]
1846                fn asin_infinity() {
1847                    let value = Complex::new(f64::INFINITY, 0.0);
1848                    assert!(matches!(
1849                        value.try_asin(),
1850                        Err(ASinComplexErrors::Input(..))
1851                    ));
1852
1853                    let value = Complex::new(0.0, f64::INFINITY);
1854                    assert!(matches!(
1855                        value.try_asin(),
1856                        Err(ASinComplexErrors::Input(..))
1857                    ));
1858                }
1859
1860                #[test]
1861                #[cfg(debug_assertions)]
1862                fn asin_subnormal() {
1863                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1864                    assert!(matches!(
1865                        value.try_asin(),
1866                        Err(ASinComplexErrors::Input(..))
1867                    ));
1868
1869                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1870                    assert!(matches!(
1871                        value.try_asin(),
1872                        Err(ASinComplexErrors::Input(..))
1873                    ));
1874                }
1875            }
1876        }
1877
1878        #[cfg(feature = "rug")]
1879        mod rug53 {
1880            use super::*;
1881
1882            mod real {
1883                use super::*;
1884
1885                #[test]
1886                fn asin_valid() {
1887                    let value =
1888                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.5)).unwrap();
1889
1890                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1891                        53,
1892                        std::f64::consts::FRAC_PI_6,
1893                    ))
1894                    .unwrap();
1895                    assert_eq!(value.clone().try_asin().unwrap(), expected_result);
1896                    assert_eq!(value.asin(), expected_result);
1897                }
1898
1899                #[test]
1900                fn asin_zero() {
1901                    let value =
1902                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1903
1904                    let expected_result =
1905                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1906                    assert_eq!(value.clone().try_asin().unwrap(), expected_result);
1907                    assert_eq!(value.asin(), expected_result);
1908                }
1909
1910                #[test]
1911                #[cfg(debug_assertions)]
1912                fn asin_out_of_bound() {
1913                    let value =
1914                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 2.0)).unwrap();
1915                    let result = value.try_asin();
1916                    println!("result: {result:?}");
1917                    assert!(matches!(result, Err(ASinRealErrors::Input(..))));
1918                }
1919            }
1920
1921            mod complex {
1922                use super::*;
1923
1924                #[test]
1925                fn asin_valid() {
1926                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1927                        53,
1928                        (rug::Float::with_val(53, 0.5), rug::Float::with_val(53, 0.5)),
1929                    ))
1930                    .unwrap();
1931
1932                    let expected_result =
1933                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1934                            53,
1935                            (
1936                                rug::Float::with_val(53, 0.4522784471511907),
1937                                rug::Float::with_val(53, 0.5306375309525179),
1938                            ),
1939                        ))
1940                        .unwrap();
1941                    assert_eq!(value.clone().try_asin().unwrap(), expected_result);
1942                    assert_eq!(value.asin(), expected_result);
1943                }
1944
1945                #[test]
1946                fn asin_zero() {
1947                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1948                        53,
1949                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1950                    ))
1951                    .unwrap();
1952
1953                    let expected_result =
1954                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1955                            53,
1956                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
1957                        ))
1958                        .unwrap();
1959                    assert_eq!(value.clone().try_asin().unwrap(), expected_result);
1960                    assert_eq!(value.asin(), expected_result);
1961                }
1962            }
1963        }
1964    }
1965
1966    mod acos {
1967        use super::*;
1968
1969        mod native {
1970            use super::*;
1971
1972            mod real {
1973                use super::*;
1974
1975                #[test]
1976                fn acos_valid() {
1977                    let value = 0.5;
1978                    let expected_result = std::f64::consts::FRAC_PI_3;
1979
1980                    assert_ulps_eq!(value.try_acos().unwrap(), expected_result);
1981                    assert_ulps_eq!(value.acos(), expected_result);
1982                }
1983
1984                #[test]
1985                fn acos_negative() {
1986                    let value = -0.5;
1987                    let expected_result = 2.0943951023931957;
1988                    assert_eq!(Float::acos(value), expected_result);
1989                    assert_eq!(ACos::acos(value), expected_result);
1990                    assert_eq!(value.try_acos().unwrap(), expected_result);
1991                }
1992
1993                #[test]
1994                fn acos_zero() {
1995                    let value = 0.0;
1996                    let expected_result = std::f64::consts::FRAC_PI_2;
1997                    assert_eq!(Float::acos(value), expected_result);
1998                    assert_eq!(ACos::acos(value), expected_result);
1999                    assert_eq!(value.try_acos().unwrap(), expected_result);
2000                }
2001
2002                #[test]
2003                #[cfg(debug_assertions)]
2004                fn acos_out_of_bound() {
2005                    let value = 2.0;
2006                    let result = value.try_acos();
2007                    println!("result: {result:?}");
2008                    assert!(matches!(result, Err(ACosRealErrors::Input(..))));
2009                }
2010
2011                #[test]
2012                #[cfg(debug_assertions)]
2013                fn acos_nan() {
2014                    let value = f64::NAN;
2015                    let result = value.try_acos();
2016                    assert!(matches!(result, Err(ACosRealErrors::Input(..))));
2017                }
2018
2019                #[test]
2020                #[cfg(debug_assertions)]
2021                fn acos_infinity() {
2022                    let value = f64::INFINITY;
2023                    assert!(matches!(value.try_acos(), Err(ACosRealErrors::Input(..))));
2024                }
2025
2026                #[test]
2027                #[cfg(debug_assertions)]
2028                fn acos_subnormal() {
2029                    let value = f64::MIN_POSITIVE / 2.0;
2030                    assert!(matches!(value.try_acos(), Err(ACosRealErrors::Input(..))));
2031                }
2032            }
2033
2034            mod complex {
2035                use super::*;
2036
2037                #[test]
2038                fn acos_valid() {
2039                    let value = Complex::new(0.5, 0.5);
2040                    let expected_result = Complex::new(1.118517879643706, -0.5306375309525179);
2041                    assert_eq!(value.try_acos().unwrap(), expected_result);
2042                    assert_eq!(<Complex<f64> as ACos>::acos(value), expected_result);
2043                    assert_eq!(value.acos(), expected_result);
2044                }
2045
2046                #[test]
2047                fn acos_zero() {
2048                    let value = Complex::new(0.0, 0.0);
2049                    let expected_result = Complex::new(std::f64::consts::FRAC_PI_2, 0.0);
2050                    assert_eq!(value.try_acos().unwrap(), expected_result);
2051                    assert_eq!(value.acos(), expected_result);
2052                }
2053
2054                #[test]
2055                #[cfg(debug_assertions)]
2056                fn acos_nan() {
2057                    let value = Complex::new(f64::NAN, 0.0);
2058                    assert!(matches!(
2059                        value.try_acos(),
2060                        Err(ACosComplexErrors::Input(..))
2061                    ));
2062
2063                    let value = Complex::new(0.0, f64::NAN);
2064                    assert!(matches!(
2065                        value.try_acos(),
2066                        Err(ACosComplexErrors::Input(..))
2067                    ));
2068                }
2069
2070                #[test]
2071                #[cfg(debug_assertions)]
2072                fn acos_infinity() {
2073                    let value = Complex::new(f64::INFINITY, 0.0);
2074                    assert!(matches!(
2075                        value.try_acos(),
2076                        Err(ACosComplexErrors::Input(..))
2077                    ));
2078
2079                    let value = Complex::new(0.0, f64::INFINITY);
2080                    assert!(matches!(
2081                        value.try_acos(),
2082                        Err(ACosComplexErrors::Input(..))
2083                    ));
2084                }
2085
2086                #[test]
2087                #[cfg(debug_assertions)]
2088                fn acos_subnormal() {
2089                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
2090                    assert!(matches!(
2091                        value.try_acos(),
2092                        Err(ACosComplexErrors::Input(..))
2093                    ));
2094
2095                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
2096                    assert!(matches!(
2097                        value.try_acos(),
2098                        Err(ACosComplexErrors::Input(..))
2099                    ));
2100                }
2101            }
2102        }
2103
2104        #[cfg(feature = "rug")]
2105        mod rug53 {
2106            use super::*;
2107
2108            mod real {
2109                use super::*;
2110
2111                #[test]
2112                fn acos_valid() {
2113                    let value =
2114                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.5)).unwrap();
2115
2116                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
2117                        53,
2118                        std::f64::consts::FRAC_PI_3,
2119                    ))
2120                    .unwrap();
2121                    assert_eq!(value.clone().try_acos().unwrap(), expected_result);
2122                    assert_eq!(value.acos(), expected_result);
2123                }
2124
2125                #[test]
2126                fn acos_zero() {
2127                    let value =
2128                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
2129
2130                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
2131                        53,
2132                        std::f64::consts::FRAC_PI_2,
2133                    ))
2134                    .unwrap();
2135                    assert_eq!(value.clone().try_acos().unwrap(), expected_result);
2136                    assert_eq!(value.acos(), expected_result);
2137                }
2138
2139                #[test]
2140                #[cfg(debug_assertions)]
2141                fn acos_out_of_bound() {
2142                    let value =
2143                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 2.0)).unwrap();
2144                    let result = value.try_acos();
2145                    println!("result: {result:?}");
2146                    assert!(matches!(result, Err(ACosRealErrors::Input(..))));
2147                }
2148            }
2149
2150            mod complex {
2151                use super::*;
2152
2153                #[test]
2154                fn acos_valid() {
2155                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
2156                        53,
2157                        (rug::Float::with_val(53, 0.5), rug::Float::with_val(53, 0.5)),
2158                    ))
2159                    .unwrap();
2160
2161                    let expected_result =
2162                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
2163                            53,
2164                            (
2165                                rug::Float::with_val(53, 1.1185178796437059),
2166                                rug::Float::with_val(53, -5.306375309525179e-1),
2167                            ),
2168                        ))
2169                        .unwrap();
2170                    assert_eq!(value.clone().try_acos().unwrap(), expected_result);
2171                    assert_eq!(value.acos(), expected_result);
2172                }
2173
2174                #[test]
2175                fn acos_zero() {
2176                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
2177                        53,
2178                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
2179                    ))
2180                    .unwrap();
2181
2182                    let expected_result =
2183                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
2184                            53,
2185                            (
2186                                rug::Float::with_val(53, std::f64::consts::FRAC_PI_2),
2187                                rug::Float::with_val(53, 0.),
2188                            ),
2189                        ))
2190                        .unwrap();
2191                    assert_eq!(value.clone().try_acos().unwrap(), expected_result);
2192                    assert_eq!(value.acos(), expected_result);
2193                }
2194            }
2195        }
2196    }
2197
2198    mod atan2 {
2199        use super::*;
2200
2201        mod native {
2202            use super::*;
2203
2204            #[test]
2205            fn atan2_valid() {
2206                let numerator = 1.0;
2207                let denominator = 1.0;
2208                let expected_result = std::f64::consts::FRAC_PI_4; // 45 degrees in radians
2209                assert_eq!(Float::atan2(numerator, denominator), expected_result);
2210                assert_eq!(ATan2::atan2(numerator, &denominator), expected_result);
2211                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2212            }
2213
2214            #[test]
2215            fn atan2_zero_numerator() {
2216                let numerator = 0.0;
2217                let denominator = 1.0;
2218                let expected_result = 0.0;
2219                assert_eq!(Float::atan2(numerator, denominator), expected_result);
2220                assert_eq!(ATan2::atan2(numerator, &denominator), expected_result);
2221                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2222            }
2223
2224            #[test]
2225            fn atan2_zero_denominator() {
2226                let numerator = 1.0;
2227                let denominator = 0.0;
2228                let expected_result = std::f64::consts::FRAC_PI_2; // 90 degrees in radians
2229                assert_eq!(Float::atan2(numerator, denominator), expected_result);
2230                assert_eq!(ATan2::atan2(numerator, &denominator), expected_result);
2231                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2232            }
2233
2234            #[test]
2235            #[cfg(debug_assertions)]
2236            fn atan2_zero_over_zero() {
2237                let numerator = 0.0;
2238                let denominator = 0.0;
2239                let result = numerator.try_atan2(&denominator);
2240                assert!(matches!(
2241                    result,
2242                    Err(ATan2Errors::Input(ATan2InputErrors::ZeroOverZero { .. }))
2243                ));
2244            }
2245
2246            #[test]
2247            fn atan2_negative_numerator() {
2248                let numerator = -1.0;
2249                let denominator = 1.0;
2250                let expected_result = -std::f64::consts::FRAC_PI_4; // -45 degrees in radians
2251                assert_eq!(Float::atan2(numerator, denominator), expected_result);
2252                assert_eq!(ATan2::atan2(numerator, &denominator), expected_result);
2253                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2254            }
2255
2256            #[test]
2257            fn atan2_negative_denominator() {
2258                let numerator = 1.0;
2259                let denominator = -1.0;
2260                let expected_result = 2.356194490192345; // 135 degrees in radians
2261                assert_eq!(Float::atan2(numerator, denominator), expected_result);
2262                assert_eq!(ATan2::atan2(numerator, &denominator), expected_result);
2263                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2264            }
2265
2266            #[test]
2267            #[cfg(debug_assertions)]
2268            fn atan2_nan_numerator() {
2269                let numerator = f64::NAN;
2270                let denominator = 1.0;
2271                let result = numerator.try_atan2(&denominator);
2272                assert!(result.is_err());
2273            }
2274
2275            #[test]
2276            #[cfg(debug_assertions)]
2277            fn atan2_nan_denominator() {
2278                let numerator = 1.0;
2279                let denominator = f64::NAN;
2280                let result = numerator.try_atan2(&denominator);
2281                assert!(result.is_err());
2282            }
2283        }
2284
2285        #[cfg(feature = "rug")]
2286        mod rug53 {
2287            use super::*;
2288            use rug::Float;
2289
2290            #[test]
2291            fn atan2_valid() {
2292                let numerator =
2293                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2294                let denominator =
2295                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2296                let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
2297                    53,
2298                    std::f64::consts::FRAC_PI_4,
2299                ))
2300                .unwrap(); // 45 degrees in radians
2301                assert_eq!(numerator.clone().atan2(&denominator), expected_result);
2302                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2303            }
2304
2305            #[test]
2306            fn atan2_zero_numerator() {
2307                let numerator =
2308                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
2309                let denominator =
2310                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2311                let expected_result =
2312                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
2313                assert_eq!(numerator.clone().atan2(&denominator), expected_result);
2314                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2315            }
2316
2317            #[test]
2318            fn atan2_zero_denominator() {
2319                let numerator =
2320                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2321                let denominator =
2322                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
2323                let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
2324                    53,
2325                    std::f64::consts::FRAC_PI_2,
2326                ))
2327                .unwrap(); // 90 degrees in radians
2328                assert_eq!(numerator.clone().atan2(&denominator), expected_result);
2329                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2330            }
2331
2332            #[test]
2333            #[cfg(debug_assertions)]
2334            fn atan2_zero_over_zero() {
2335                let numerator =
2336                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
2337                let denominator =
2338                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
2339                let result = numerator.try_atan2(&denominator);
2340                assert!(matches!(
2341                    result,
2342                    Err(ATan2Errors::Input(ATan2InputErrors::ZeroOverZero { .. }))
2343                ));
2344            }
2345
2346            #[test]
2347            fn atan2_negative_numerator() {
2348                let numerator =
2349                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, -1.0)).unwrap();
2350                let denominator =
2351                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2352                let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
2353                    53,
2354                    -std::f64::consts::FRAC_PI_4,
2355                ))
2356                .unwrap(); // -45 degrees in radians
2357                assert_eq!(numerator.clone().atan2(&denominator), expected_result);
2358                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2359            }
2360
2361            #[test]
2362            fn atan2_negative_denominator() {
2363                let numerator =
2364                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
2365                let denominator =
2366                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, -1.0)).unwrap();
2367                let expected_result =
2368                    RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.356194490192345))
2369                        .unwrap(); // 135 degrees in radians
2370                assert_eq!(numerator.clone().atan2(&denominator), expected_result);
2371                assert_eq!(numerator.try_atan2(&denominator).unwrap(), expected_result);
2372            }
2373        }
2374    }
2375}
2376//------------------------------------------------------------------------------------------------