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