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