Skip to main content

num_valid/functions/
hyperbolic.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! This module provides traits, error types, and implementations for various
4//! hyperbolic functions and their inverses (e.g., `sinh`, `cosh`, `asinh`, `acosh`).
5//!
6//! It defines a set of traits (e.g., [`SinH`], [`ACosH`], etc.) for standard
7//! hyperbolic operations. These traits are implemented for [`f64`], [`num::Complex<f64>`],
8//! [`RealValidated`](crate::RealValidated), [`ComplexValidated`](crate::ComplexValidated),
9//! and can be extended to other numeric types satisfying the [`RealScalar`](crate::RealScalar) or
10//! [`ComplexScalar`](crate::ComplexScalar) traits.
11//!
12//! A comprehensive error handling system is in place, utilizing specific input
13//! error enums (e.g., [`ACosHInputErrors`], [`TanHComplexInputErrors`], etc.) and
14//! general function error type aliases (e.g., [`SinHErrors`], [`ACosHErrors`], etc.)
15//! built upon the [`FunctionErrors`] struct. This allows for granular reporting
16//! of issues such as invalid arguments (NaN, infinity) or out-of-domain values.
17//!
18//! The design emphasizes robustness through strict validation boundaries.
19//! For validated wrapper types, invariants are preserved by wrapper-level policies;
20//! for native raw paths, validation is primarily enforced in debug builds, while
21//! release builds may delegate directly to backend operations for performance.
22
23use crate::{
24    core::{
25        errors::ErrorsValidationRawReal,
26        traits::{raw::RawScalarValidate, validation::sealed::NativeReal},
27    },
28    functions::FunctionErrors,
29    kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait},
30};
31use duplicate::duplicate_item;
32use num::Complex;
33use num_traits::Float;
34use std::backtrace::Backtrace;
35use thiserror::Error;
36
37#[cfg(debug_assertions)]
38use crate::{Constants, core::errors::capture_backtrace};
39
40//------------------------------------------------------------------------------------------------
41#[duplicate_item(
42    enum_name          enum_doc;
43    [CosHInputErrors]  ["Errors that can occur during the computation of the hyperbolic cosine.\n\nPrimarily, this enum handles issues related to invalid input arguments,\\nsuch as NaN (Not a Number) or infinity, as determined by the\\nimplemented validation policy (e.g., `StrictFinitePolicy`).\n\n# Type Parameters\n\n- `ScalarType`: The numeric type for the computation (e.g., `f64`, `Complex<f64>`),\\n  which must implement the [`RawScalarTrait`] trait. The associated type\\n  `<RawScalar as RawScalarValidate>::ValidationError` is used to convey details of underlying\\n  validation failures.\n\n# Variants\n\n- `InvalidArgument`: Signals that the input argument to the hyperbolic cosine\\n  function is invalid. This variant wraps the specific error encountered\\n  during the validation process, providing more context on the nature of\\n  the invalidity."];
44    [SinHInputErrors]  ["Errors that can occur during the computation of the hyperbolic sine.\n\nPrimarily, this enum handles issues related to invalid input arguments,\\nsuch as NaN (Not a Number) or infinity, as determined by the\\nimplemented validation policy (e.g., `StrictFinitePolicy`).\n\n# Type Parameters\n\n- `ScalarType`: The numeric type for the computation (e.g., `f64`, `Complex<f64>`),\\n  which must implement the [`RawScalarTrait`] trait. The associated type\\n  `<RawScalar as RawScalarValidate>::ValidationError` is used to convey details of underlying\\n  validation failures.\n\n# Variants\n\n- `InvalidArgument`: Signals that the input argument to the hyperbolic sine\\n  function is invalid. This variant wraps the specific error encountered\\n  during the validation process, providing more context on the nature of\\n  the invalidity."];
45    [ASinHInputErrors] ["Errors that can occur during the computation of the inverse hyperbolic sine.\n\nPrimarily, this enum handles issues related to invalid input arguments,\\nsuch as NaN (Not a Number) or infinity, as determined by the\\nimplemented validation policy (e.g., `StrictFinitePolicy`).\\nNote: `asinh` is defined for all real and complex numbers, so domain errors\\nare not typically raised at this input stage.\n\n# Type Parameters\n\n- `ScalarType`: The numeric type for the computation (e.g., `f64`, `Complex<f64>`),\\n  which must implement the [`RawScalarTrait`] trait. The associated type\\n  `<RawScalar as RawScalarValidate>::ValidationError` is used to convey details of underlying\\n  validation failures.\n\n# Variants\n\n- `InvalidArgument`: Signals that the input argument to the inverse hyperbolic sine\\n  function is invalid. This variant wraps the specific error encountered\\n  during the validation process, providing more context on the nature of\\n  the invalidity."];
46)]
47#[derive(Debug, Error)]
48#[doc = enum_doc]
49pub enum enum_name<RawScalar: RawScalarTrait> {
50    /// The input argument is invalid (e.g., NaN or infinity).
51    ///
52    /// This error is raised if the input value fails the validation
53    /// (using the chosen validation policy implementation).
54    /// It contains the underlying error from the validation mechanism.
55    #[error("the argument of the function is invalid!")]
56    InvalidArgument {
57        /// The source error that occurred during validation.
58        #[source]
59        #[backtrace]
60        source: <RawScalar as RawScalarValidate>::ValidationError,
61    },
62}
63
64/// Errors that can occur when computing the *hyperbolic tangent* of a *real number*.
65///
66/// This enum covers errors related to invalid input arguments (e.g., NaN, infinity)
67/// as determined by the validation policy for real numbers.
68///
69/// # Type Parameters
70///
71/// - `RawReal`: The real numeric type (e.g., `f64`) for the computation,
72///   implementing [`RawRealTrait`]. The type `<RawReal as RawScalarValidate>::ValidationError` is used for
73///   underlying validation error details.
74///
75/// # Variants
76///
77/// - `InvalidArgument`: The input argument is invalid (e.g., NaN or infinity).
78///   Wraps the source error from the validation process.
79#[derive(Debug, Error)]
80pub enum TanHRealInputErrors<RawReal: RawRealTrait> {
81    /// The input argument is invalid (e.g., NaN or infinity).
82    ///
83    /// This error is raised if the input value fails the validation
84    /// (using the chosen validation policy implementation).
85    /// It contains the underlying error from the validation mechanism.
86    #[error("the argument of the function is invalid!")]
87    InvalidArgument {
88        /// The source error that occurred during validation.
89        #[source]
90        #[backtrace]
91        source: <RawReal as RawScalarValidate>::ValidationError,
92    },
93}
94
95#[duplicate_item(
96    enum_name          enum_doc;
97    [ACosHInputErrors] ["Errors that can occur during the computation of the inverse hyperbolic cosine.\n\nThis enum handles issues related to invalid input arguments, such as NaN or\\ninfinity, as determined by the validation policy (e.g., `StrictFinitePolicy`).\\nIt also includes domain errors specific to `acosh`, which is defined for `x >= 1`\\nfor real numbers and for all complex numbers.\n\n# Type Parameters\n\n- `RawScalar`: The numeric type (e.g., `f64`, `Complex<f64>`), implementing [`RawScalarTrait`].\\n  `<RawScalar as RawScalarValidate>::ValidationError` provides details of validation failures.\n\n# Variants\n\n- `InvalidArgument`: Input is invalid (e.g., NaN, infinity). Wraps `<RawScalar as RawScalarValidate>::ValidationError`.\\n- `DomainError`: Input is outside the function's domain (e.g., `x < 1` for real `acosh`)."];
98    [ATanHInputErrors] ["Errors that can occur during the computation of the inverse hyperbolic tangent.\n\nThis enum handles issues related to invalid input arguments, such as NaN or\\ninfinity, as determined by the validation policy (e.g., `StrictFinitePolicy`).\\nIt also includes domain errors specific to `atanh`, which is defined for `-1 < x < 1`\\nfor real numbers and for complex numbers `z` where `z != ±1`.\n\n# Type Parameters\n\n- `RawScalar`: The numeric type (e.g., `f64`, `Complex<f64>`), implementing [`RawScalarTrait`].\\n  `<RawScalar as RawScalarValidate>::ValidationError` provides details of validation failures.\n\n# Variants\n\n- `InvalidArgument`: Input is invalid (e.g., NaN, infinity). Wraps `<RawScalar as RawScalarValidate>::ValidationError`.\\n- `DomainError`: Input is outside the function's domain (e.g., `|x| >= 1` for real `atanh`)."];
99)]
100#[derive(Debug, Error)]
101#[doc = enum_doc]
102pub enum enum_name<RawScalar: RawScalarTrait> {
103    /// The input value is outside the mathematical domain of the function.
104    ///
105    /// For example, for real `acosh(x)`, `x` must be `>= 1`. For real `atanh(x)`, `|x|` must be `< 1`.
106    /// For complex versions, this refers to values on the branch cuts if they are explicitly excluded.
107    #[error("the input argument is outside the domain of the function!")]
108    OutOfDomain {
109        /// The input value that is outside the function's domain.
110        value: RawScalar,
111
112        /// A captured backtrace for debugging purposes.
113        backtrace: Backtrace,
114    },
115
116    /// The input argument is invalid (e.g., NaN or infinity).
117    ///
118    /// This error is raised if the input value fails the validation
119    /// (using the chosen validation policy implementation).
120    /// It contains the underlying error from the validation mechanism.
121    #[error("the argument of the function is invalid!")]
122    InvalidArgument {
123        /// The source error that occurred during validation.
124        #[source]
125        #[backtrace]
126        source: <RawScalar as RawScalarValidate>::ValidationError,
127    },
128}
129
130#[duplicate_item(
131    enum_name     ErrIn              enum_doc;
132    [CosHErrors]  [CosHInputErrors]  ["Errors that can occur when computing the *hyperbolic cosine* of a real or complex number.\n\nIt includes errors for invalid input and output values.\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 as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.\n- `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation."];
133    [SinHErrors]  [SinHInputErrors]  ["Errors that can occur when computing the *hyperbolic sine* of a real or complex number.\n\nIt includes errors for invalid input and output values.\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 as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.\n- `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation."];
134    [ASinHErrors] [ASinHInputErrors] ["Errors that can occur when computing the *inverse hyperbolic sine* of a real or complex number.\n\nIt includes errors for invalid input and output values.\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 as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.\n- `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation."];
135    [ACosHErrors] [ACosHInputErrors] ["Errors that can occur when computing the *inverse hyperbolic cosine* of a real or complex number.\n\nIt includes errors for invalid input and output values.\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 as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.\n- `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation."];
136    [ATanHErrors] [ATanHInputErrors] ["Errors that can occur when computing the *inverse hyperbolic tangent* of a real or complex number.\n\nIt includes errors for invalid input and output values.\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 as RawScalarValidate>::ValidationError`.\n\n# Variants\n\n- `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.\n- `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation."];
137)]
138#[doc = enum_doc]
139pub type enum_name<RawScalar> =
140    FunctionErrors<ErrIn<RawScalar>, <RawScalar as RawScalarValidate>::ValidationError>;
141
142/// Errors that can occur when computing the *hyperbolic tangent* of a *real number*.
143///
144/// It includes errors for invalid input and output values.
145///
146/// # Type Parameters
147///
148/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify the numeric type for the computation
149///   and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError`.
150///
151/// # Variants
152///
153/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.
154/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation.
155pub type TanHRealErrors<RawReal> =
156    FunctionErrors<TanHRealInputErrors<RawReal>, <RawReal as RawScalarValidate>::ValidationError>;
157
158/// Errors that can occur when computing the *hyperbolic tangent* of a *complex number*.
159///
160/// It includes errors for invalid arguments and other validation errors.
161///
162/// # Type Parameters
163///
164/// - `ComplexType`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify the numeric type
165///   for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.
166///
167/// # Variants
168///
169/// - `InvalidArgument`: Indicates that the argument of the function is invalid. This variant includes the source error that occurred during validation.
170#[derive(Debug, Error)]
171pub enum TanHComplexInputErrors<RawComplex: RawComplexTrait> {
172    /// The input value is outside the mathematical domain of the function.
173    ///
174    /// For complex `tanh`, this occurs when the input would produce a singularity,
175    /// such as when `z = i*(π/2 + n*π)` for integer `n`.
176    #[error("the input argument is outside the domain of the function!")]
177    OutOfDomain {
178        /// The input value that is outside the function's domain.
179        value: RawComplex,
180
181        /// A captured backtrace for debugging purposes.
182        backtrace: Backtrace,
183    },
184
185    /// The input argument is invalid (e.g., NaN or infinity).
186    ///
187    /// This error is raised if the input value fails the validation
188    /// (using the chosen validation policy implementation).
189    /// It contains the underlying error from the validation mechanism.
190    #[error("the argument of the function is invalid!")]
191    InvalidArgument {
192        /// The source error that occurred during validation.
193        #[source]
194        #[backtrace]
195        source: <RawComplex as RawScalarValidate>::ValidationError,
196    },
197}
198
199/// Errors that can occur when computing the *hyperbolic tangent* of a *complex number*.
200///
201/// It includes errors for invalid input and output values.
202///
203/// # Type Parameters
204///
205/// - `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify the numeric type for the computation
206///   and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.
207///
208/// # Variants
209///
210/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that occurred during validation.
211/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that occurred during validation.
212pub type TanHComplexErrors<RawComplex> = FunctionErrors<
213    TanHComplexInputErrors<RawComplex>,
214    <RawComplex as RawScalarValidate>::ValidationError,
215>;
216//------------------------------------------------------------------------------------------------
217
218//------------------------------------------------------------------------------------------------
219#[duplicate_item(
220    T       try_func    func    trait_doc try_func_doc func_doc err_doc;
221    [ACosH] [try_acosh] [acosh] ["Trait for computing the *inverse hyperbolic cosine* of a number.\n\nThis trait defines methods for computing the *inverse hyperbolic cosine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_acosh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_acosh`: Computes the *inverse hyperbolic cosine* of `self` 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 - `acosh`: Computes the *inverse hyperbolic cosine* of `self` and directly returns the computed value. In Debug mode this method may panic if the computation fails."]     ["Computes the *inverse hyperbolic 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 hyperbolic 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_acosh` method for safe computations."]  ["The error type that is returned by the `try_acosh` method."];
222    [ASinH] [try_asinh] [asinh] ["Trait for computing the *inverse hyperbolic sine* of a number.\n\nThis trait defines methods for computing the *inverse hyperbolic sine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_asinh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_asinh`: Computes the *inverse hyperbolic sine* of `self` 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 - `asinh`: Computes the *inverse hyperbolic sine* of `self` and directly returns the computed value. In Debug mode this method may panic if the computation fails."]             ["Computes the *inverse hyperbolic 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 hyperbolic 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_asinh` method for safe computations."]    ["The error type that is returned by the `try_asinh` method."];
223    [ATanH] [try_atanh] [atanh] ["Trait for computing the *inverse hyperbolic tangent* of a number.\n\nThis trait defines methods for computing the *inverse hyperbolic tangent* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_atanh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_atanh`: Computes the *inverse hyperbolic tangent* of `self` 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 - `atanh`: Computes the *inverse hyperbolic tangent* of `self` and directly returns the computed value. In Debug mode this method may panic if the computation fails."] ["Computes the *inverse hyperbolic 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 hyperbolic 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_atanh` method for safe computations."] ["The error type that is returned by the `try_atanh` method."];
224    [CosH]  [try_cosh]  [cosh]  ["Trait for computing the *hyperbolic cosine* of a number.\n\nThis trait defines methods for computing the *hyperbolic cosine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_cosh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_cosh`: Computes the *hyperbolic cosine* of `self` 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 - `cosh`: Computes the *hyperbolic cosine* of `self` and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                        ["Computes the *hyperbolic 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 *hyperbolic 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_cosh` method for safe computations."]           ["The error type that is returned by the `try_cosh` method."];
225    [SinH]  [try_sinh]  [sinh]  ["Trait for computing the *hyperbolic sine* of a number.\n\nThis trait defines methods for computing the *hyperbolic sine* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_sinh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_sinh`: Computes the *hyperbolic sine* of `self` 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 - `sinh`: Computes the *hyperbolic sine* of `self` and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                                ["Computes the *hyperbolic 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 *hyperbolic 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_sinh` method for safe computations."]             ["The error type that is returned by the `try_sinh` method."]; 
226    [TanH]  [try_tanh]  [tanh]  ["Trait for computing the *hyperbolic tangent* of a number.\n\nThis trait defines methods for computing the *hyperbolic tangent* of a number. Provides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_tanh` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n - `try_tanh`: Computes the *hyperbolic tangent* of `self` 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 - `tanh`: Computes the *hyperbolic tangent* of the number and directly returns the computed value. In Debug mode this method may panic if the computation fails."]                                ["Computes the *hyperbolic 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 *hyperbolic 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_tanh` method for safe computations."]          ["The error type that is returned by the `try_tanh` method."];
227)]
228#[doc = trait_doc]
229pub trait T: Sized {
230    #[doc = err_doc]
231    type Error: std::error::Error;
232
233    #[doc = try_func_doc]
234    #[must_use = "this `Result` may contain an error that should be handled"]
235    fn try_func(self) -> Result<Self, <Self as T>::Error>;
236
237    #[doc = func_doc]
238    fn func(self) -> Self;
239}
240
241#[duplicate_item(
242    my_trait E                ErrIn                 try_func    func    scalar_type   ;
243    [CosH]   [CosHErrors]     [CosHInputErrors]     [try_cosh]  [cosh]  [T]           ;
244    [CosH]   [CosHErrors]     [CosHInputErrors]     [try_cosh]  [cosh]  [Complex::<T>];
245    [SinH]   [SinHErrors]     [SinHInputErrors]     [try_sinh]  [sinh]  [T]           ;
246    [SinH]   [SinHErrors]     [SinHInputErrors]     [try_sinh]  [sinh]  [Complex::<T>];
247    [TanH]   [TanHRealErrors] [TanHRealInputErrors] [try_tanh]  [tanh]  [T]           ;
248    [ASinH]  [ASinHErrors]    [ASinHInputErrors]    [try_asinh] [asinh] [T]           ;
249    [ASinH]  [ASinHErrors]    [ASinHInputErrors]    [try_asinh] [asinh] [Complex::<T>];
250)]
251impl<T> my_trait for scalar_type
252where
253    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
254{
255    type Error = E<scalar_type>;
256
257    #[inline(always)]
258    fn try_func(self) -> Result<Self, <Self as my_trait>::Error> {
259        #[cfg(debug_assertions)]
260        {
261            self.validate_raw_scalar()
262                .map_err(|e| ErrIn::InvalidArgument { source: e }.into())
263                .and_then(|v| {
264                    scalar_type::func(v)
265                        .validate_raw_scalar()
266                        .map_err(|e| Self::Error::Output { source: e })
267                })
268        }
269        #[cfg(not(debug_assertions))]
270        {
271            Ok(scalar_type::func(self))
272        }
273    }
274
275    #[inline(always)]
276    fn func(self) -> Self {
277        #[cfg(debug_assertions)]
278        {
279            self.try_func().unwrap()
280        }
281        #[cfg(not(debug_assertions))]
282        {
283            scalar_type::func(self)
284        }
285    }
286}
287
288impl<T> ATanH for T
289where
290    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
291{
292    type Error = ATanHErrors<T>;
293
294    #[inline(always)]
295    fn try_atanh(self) -> Result<Self, Self::Error> {
296        #[cfg(debug_assertions)]
297        {
298            self.validate_raw_scalar()
299                .map_err(|e| ATanHInputErrors::InvalidArgument { source: e }.into())
300                .and_then(|v| {
301                    // The domain of atanh is (-1, 1), so we check if the value is within this range.
302                    // If it is outside this range, we return an error.
303                    if v <= T::negative_one() || v >= T::one() {
304                        Err(ATanHInputErrors::OutOfDomain {
305                            value: v,
306                            backtrace: capture_backtrace(),
307                        }
308                        .into())
309                    } else {
310                        <T as Float>::atanh(v)
311                            .validate_raw_scalar()
312                            .map_err(|e| ATanHErrors::Output { source: e })
313                    }
314                })
315        }
316        #[cfg(not(debug_assertions))]
317        {
318            Ok(<T as Float>::atanh(self))
319        }
320    }
321
322    #[inline(always)]
323    fn atanh(self) -> Self {
324        #[cfg(debug_assertions)]
325        {
326            self.try_atanh().unwrap()
327        }
328        #[cfg(not(debug_assertions))]
329        {
330            <T as Float>::atanh(self)
331        }
332    }
333}
334
335impl<T> ACosH for T
336where
337    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
338{
339    type Error = ACosHErrors<T>;
340
341    #[inline(always)]
342    fn try_acosh(self) -> Result<Self, <Self as ACosH>::Error> {
343        #[cfg(debug_assertions)]
344        {
345            self.validate_raw_scalar()
346                .map_err(|e| ACosHInputErrors::InvalidArgument { source: e }.into())
347                .and_then(|v| {
348                    if v < T::one() {
349                        Err(ACosHInputErrors::OutOfDomain {
350                            value: v,
351                            backtrace: capture_backtrace(),
352                        }
353                        .into())
354                    } else {
355                        <T as Float>::acosh(v)
356                            .validate_raw_scalar()
357                            .map_err(|e| ACosHErrors::Output { source: e })
358                    }
359                })
360        }
361        #[cfg(not(debug_assertions))]
362        {
363            Ok(<T as Float>::acosh(self))
364        }
365    }
366
367    #[inline(always)]
368    fn acosh(self) -> Self {
369        #[cfg(debug_assertions)]
370        {
371            self.try_acosh().unwrap()
372        }
373        #[cfg(not(debug_assertions))]
374        {
375            <T as Float>::acosh(self)
376        }
377    }
378}
379
380impl<T> TanH for Complex<T>
381where
382    Self: RawComplexTrait<RawReal = T>,
383    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
384{
385    type Error = TanHComplexErrors<Complex<T>>;
386
387    #[inline(always)]
388    fn try_tanh(self) -> Result<Self, Self::Error> {
389        #[cfg(debug_assertions)]
390        {
391            self.validate_raw_scalar()
392                .map_err(|e| TanHComplexInputErrors::InvalidArgument { source: e }.into())
393                .and_then(|v| {
394                    // The domain of tanh is C minus the set of points where cosh is zero.
395                    if RawScalarTrait::is_zero(&v.cosh()) {
396                        Err(TanHComplexInputErrors::OutOfDomain {
397                            value: v,
398                            backtrace: capture_backtrace(),
399                        }
400                        .into())
401                    } else {
402                        Complex::<T>::tanh(v)
403                            .validate_raw_scalar()
404                            .map_err(|e| TanHComplexErrors::Output { source: e })
405                    }
406                })
407        }
408        #[cfg(not(debug_assertions))]
409        {
410            Ok(Complex::<T>::tanh(self))
411        }
412    }
413
414    #[inline(always)]
415    fn tanh(self) -> Self {
416        #[cfg(debug_assertions)]
417        {
418            self.try_tanh().unwrap()
419        }
420        #[cfg(not(debug_assertions))]
421        {
422            Complex::<T>::tanh(self)
423        }
424    }
425}
426
427impl<T> ATanH for Complex<T>
428where
429    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
430{
431    type Error = ATanHErrors<Complex<T>>;
432
433    #[inline(always)]
434    fn try_atanh(self) -> Result<Self, Self::Error> {
435        #[cfg(debug_assertions)]
436        {
437            self.validate_raw_scalar()
438                .map_err(|e| ATanHInputErrors::InvalidArgument { source: e }.into())
439                .and_then(|v| {
440                    // The principal value of atanh(z) has branch cuts on the real axis for x <= -1 and x >= 1.
441                    if v.im == T::zero() && (v.re <= T::negative_one() || v.re >= T::one()) {
442                        Err(ATanHInputErrors::OutOfDomain {
443                            value: v,
444                            backtrace: capture_backtrace(),
445                        }
446                        .into())
447                    } else {
448                        Complex::<T>::atanh(v)
449                            .validate_raw_scalar()
450                            .map_err(|e| ATanHErrors::Output { source: e })
451                    }
452                })
453        }
454        #[cfg(not(debug_assertions))]
455        {
456            Ok(Complex::<T>::atanh(self))
457        }
458    }
459
460    #[inline(always)]
461    fn atanh(self) -> Self {
462        #[cfg(debug_assertions)]
463        {
464            self.try_atanh().unwrap()
465        }
466        #[cfg(not(debug_assertions))]
467        {
468            Complex::<T>::atanh(self)
469        }
470    }
471}
472
473impl<T> ACosH for Complex<T>
474where
475    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
476{
477    type Error = ACosHErrors<Complex<T>>;
478
479    #[inline(always)]
480    fn try_acosh(self) -> Result<Self, <Self as ACosH>::Error> {
481        #[cfg(debug_assertions)]
482        {
483            self.validate_raw_scalar()
484                .map_err(|e| ACosHInputErrors::InvalidArgument { source: e }.into())
485                .and_then(|v| {
486                    if v.im == T::zero() && v.re < T::one() {
487                        Err(ACosHInputErrors::OutOfDomain {
488                            value: v,
489                            backtrace: capture_backtrace(),
490                        }
491                        .into())
492                    } else {
493                        Complex::<T>::acosh(v)
494                            .validate_raw_scalar()
495                            .map_err(|e| ACosHErrors::Output { source: e })
496                    }
497                })
498        }
499        #[cfg(not(debug_assertions))]
500        {
501            Ok(Complex::<T>::acosh(self))
502        }
503    }
504
505    #[inline(always)]
506    fn acosh(self) -> Self {
507        #[cfg(debug_assertions)]
508        {
509            self.try_acosh().unwrap()
510        }
511        #[cfg(not(debug_assertions))]
512        {
513            Complex::<T>::acosh(self)
514        }
515    }
516}
517
518//------------------------------------------------------------------------------------------------
519
520//------------------------------------------------------------------------------------------------
521/// A convenience trait that aggregates the standard hyperbolic functions and their inverses.
522///
523/// This trait serves as a shorthand for requiring a type to implement all the fundamental
524/// hyperbolic operations:
525/// - [`SinH`] and [`ASinH`]
526/// - [`CosH`] and [`ACosH`]
527/// - [`TanH`] and [`ATanH`]
528///
529/// It is primarily used as a super-trait for [`FpScalar`](crate::FpScalar) to simplify trait bounds
530/// and ensure that any scalar type in the library provides a comprehensive set of hyperbolic
531/// capabilities. By using `HyperbolicFunctions` as a bound, you can write generic functions that
532/// utilize any of its constituent trait methods.
533///
534/// # Examples
535///
536/// ```
537/// use num_valid::functions::{HyperbolicFunctions, Abs};
538/// use std::ops::{Mul, Sub};
539///
540/// // A generic function that verifies the identity cosh(x)^2 - sinh(x)^2 = 1.
541/// // We bound T by HyperbolicFunctions, Clone, and arithmetic ops.
542/// fn verify_hyperbolic_identity<T>(x: T) -> T
543/// where
544///     T: HyperbolicFunctions + Clone + Sub<Output = T> + Mul<Output = T>,
545/// {
546///     let cosh_x = x.clone().cosh();
547///     let sinh_x = x.sinh();
548///     // This works because FpScalar requires the necessary arithmetic traits.
549///     cosh_x.clone() * cosh_x - sinh_x.clone() * sinh_x
550/// }
551///
552/// let value = 0.5f64;
553/// let identity = verify_hyperbolic_identity(value);
554///
555/// // The result should be very close to 1.0.
556/// // We use the Abs trait for comparison.
557/// assert!((identity - 1.0).abs() < 1e-12);
558/// ```
559pub trait HyperbolicFunctions: SinH + ASinH + CosH + ACosH + TanH + ATanH {}
560
561impl<T> HyperbolicFunctions for T where T: SinH + ASinH + CosH + ACosH + TanH + ATanH {}
562//------------------------------------------------------------------------------------------------
563
564//------------------------------------------------------------------------------------------------
565#[cfg(test)]
566mod tests {
567    use super::*;
568    use approx::assert_ulps_eq;
569
570    #[cfg(feature = "rug")]
571    use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
572
573    #[cfg(feature = "rug")]
574    use try_create::TryNew;
575
576    mod sinh {
577        use super::*;
578
579        mod native {
580            use super::*;
581
582            mod real {
583                use super::*;
584
585                #[test]
586                fn test_f64_sinh_valid() {
587                    let value = 1.0;
588                    let expected_result = 1.1752011936438014;
589                    assert_eq!(value.try_sinh().unwrap(), expected_result);
590                    assert_eq!(<f64 as Float>::sinh(value), expected_result);
591                    assert_eq!(value.sinh(), expected_result);
592                }
593
594                #[test]
595                fn test_f64_sinh_negative() {
596                    let value = -1.0;
597                    let expected_result = -1.1752011936438014;
598                    assert_eq!(value.try_sinh().unwrap(), expected_result);
599                    assert_eq!(<f64 as Float>::sinh(value), expected_result);
600                    assert_eq!(SinH::sinh(value), expected_result);
601                }
602
603                #[test]
604                fn test_f64_sinh_zero() {
605                    let value = 0.0;
606                    assert_eq!(value.try_sinh().unwrap(), 0.0);
607                    assert_eq!(ASinH::asinh(value), 0.0);
608                }
609
610                #[test]
611                #[cfg(debug_assertions)]
612                fn test_f64_sinh_nan() {
613                    let value = f64::NAN;
614                    let result = value.try_sinh();
615                    assert!(matches!(result, Err(SinHErrors::Input(..))));
616                }
617
618                #[test]
619                #[cfg(debug_assertions)]
620                fn test_f64_sinh_infinity() {
621                    let value = f64::INFINITY;
622                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
623                }
624
625                #[test]
626                #[cfg(debug_assertions)]
627                fn test_f64_sinh_subnormal() {
628                    let value = f64::MIN_POSITIVE / 2.0;
629                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
630                }
631            }
632
633            mod complex {
634                use super::*;
635
636                #[test]
637                fn sinh_valid() {
638                    let value = Complex::new(1.0, 1.0);
639                    let expected_result = Complex::new(0.6349639147847361, 1.2984575814159773);
640                    assert_eq!(value.try_sinh().unwrap(), expected_result);
641                    assert_eq!(<Complex<f64> as SinH>::sinh(value), expected_result);
642                    assert_eq!(value.sinh(), expected_result);
643                }
644
645                #[test]
646                fn sinh_zero() {
647                    let value = Complex::new(0.0, 0.0);
648                    let expected_result = Complex::new(0.0, 0.0);
649                    assert_eq!(value.try_sinh().unwrap(), expected_result);
650                    assert_eq!(value.sinh(), expected_result);
651                }
652
653                #[test]
654                #[cfg(debug_assertions)]
655                fn sinh_nan() {
656                    let value = Complex::new(f64::NAN, 0.0);
657                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
658
659                    let value = Complex::new(0.0, f64::NAN);
660                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
661                }
662
663                #[test]
664                #[cfg(debug_assertions)]
665                fn sinh_infinity() {
666                    let value = Complex::new(f64::INFINITY, 0.0);
667                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
668
669                    let value = Complex::new(0.0, f64::INFINITY);
670                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
671                }
672
673                #[test]
674                #[cfg(debug_assertions)]
675                fn sinh_subnormal() {
676                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
677                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
678
679                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
680                    assert!(matches!(value.try_sinh(), Err(SinHErrors::Input(..))));
681                }
682            }
683        }
684
685        #[cfg(feature = "rug")]
686        mod rug53 {
687            use super::*;
688            use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
689            use try_create::TryNew;
690
691            mod real {
692                use super::*;
693
694                #[test]
695                fn test_rug_float_sinh_valid() {
696                    let value =
697                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
698
699                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
700                        53,
701                        1.1752011936438014,
702                    ))
703                    .unwrap();
704                    assert_eq!(value.clone().try_sinh().unwrap(), expected_result);
705                    assert_eq!(value.sinh(), expected_result);
706                }
707
708                #[test]
709                fn test_rug_float_sinh_zero() {
710                    let value =
711                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
712
713                    let expected_result =
714                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
715                    assert_eq!(value.clone().try_sinh().unwrap(), expected_result);
716                    assert_eq!(value.sinh(), expected_result);
717                }
718            }
719
720            mod complex {
721                use super::*;
722
723                #[test]
724                fn test_complex_rug_float_sinh_valid() {
725                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
726                        53,
727                        (rug::Float::with_val(53, 1.0), rug::Float::with_val(53, 1.0)),
728                    ))
729                    .unwrap();
730
731                    let expected_result =
732                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
733                            53,
734                            (
735                                rug::Float::with_val(53, 0.6349639147847361),
736                                rug::Float::with_val(53, 1.2984575814159773),
737                            ),
738                        ))
739                        .unwrap();
740                    assert_eq!(value.clone().try_sinh().unwrap(), expected_result);
741                    assert_eq!(value.sinh(), expected_result);
742                }
743
744                #[test]
745                fn test_complex_rug_float_sinh_zero() {
746                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
747                        53,
748                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
749                    ))
750                    .unwrap();
751
752                    let expected_result =
753                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
754                            53,
755                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
756                        ))
757                        .unwrap();
758                    assert_eq!(value.clone().try_sinh().unwrap(), expected_result);
759                    assert_eq!(value.sinh(), expected_result);
760                }
761            }
762        }
763    }
764
765    mod cosh {
766        use super::*;
767
768        mod native {
769            use super::*;
770
771            mod real {
772                use super::*;
773
774                #[test]
775                fn test_f64_cosh_valid() {
776                    let value = 1.0;
777                    let expected_result = 1.5430806348152437;
778                    assert_eq!(value.try_cosh().unwrap(), expected_result);
779                    assert_eq!(<f64 as CosH>::cosh(value), expected_result);
780                    assert_eq!(CosH::cosh(value), expected_result);
781                }
782
783                #[test]
784                fn test_f64_cosh_negative() {
785                    let value = -1.0;
786                    let expected_result = 1.5430806348152437;
787                    assert_eq!(value.try_cosh().unwrap(), expected_result);
788                    assert_eq!(<f64 as CosH>::cosh(value), expected_result);
789                    assert_eq!(CosH::cosh(value), expected_result);
790                }
791
792                #[test]
793                fn test_f64_cosh_zero() {
794                    let value = 0.0;
795                    assert_eq!(value.try_cosh().unwrap(), 1.0);
796                    assert_eq!(<f64 as CosH>::cosh(value), 1.0);
797                    assert_eq!(CosH::cosh(value), 1.0);
798                }
799
800                #[test]
801                #[cfg(debug_assertions)]
802                fn test_f64_cosh_nan() {
803                    let value = f64::NAN;
804                    let result = value.try_cosh();
805                    assert!(matches!(result, Err(CosHErrors::Input(..))));
806                }
807
808                #[test]
809                #[cfg(debug_assertions)]
810                fn test_f64_cosh_infinity() {
811                    let value = f64::INFINITY;
812                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
813                }
814
815                #[test]
816                #[cfg(debug_assertions)]
817                fn test_f64_cosh_subnormal() {
818                    let value = f64::MIN_POSITIVE / 2.0;
819                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
820                }
821            }
822
823            mod complex {
824                use super::*;
825
826                #[test]
827                fn cosh_valid() {
828                    let value = Complex::new(1.0, 1.0);
829                    let expected_result = Complex::new(0.8337300251311491, 0.9888977057628651);
830                    assert_eq!(value.try_cosh().unwrap(), expected_result);
831                    assert_eq!(<Complex<f64> as CosH>::cosh(value), expected_result);
832                    assert_eq!(value.cosh(), expected_result);
833                }
834
835                #[test]
836                fn cosh_zero() {
837                    let value = Complex::new(0.0, 0.0);
838                    let expected_result = Complex::new(1.0, 0.0);
839                    assert_eq!(value.try_cosh().unwrap(), expected_result);
840                    assert_eq!(value.cosh(), expected_result);
841                }
842
843                #[test]
844                #[cfg(debug_assertions)]
845                fn cosh_nan() {
846                    let value = Complex::new(f64::NAN, 0.0);
847                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
848
849                    let value = Complex::new(0.0, f64::NAN);
850                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
851                }
852
853                #[test]
854                #[cfg(debug_assertions)]
855                fn cosh_infinity() {
856                    let value = Complex::new(f64::INFINITY, 0.0);
857                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
858
859                    let value = Complex::new(0.0, f64::INFINITY);
860                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
861                }
862
863                #[test]
864                #[cfg(debug_assertions)]
865                fn cosh_subnormal() {
866                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
867                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
868
869                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
870                    assert!(matches!(value.try_cosh(), Err(CosHErrors::Input(..))));
871                }
872            }
873        }
874
875        #[cfg(feature = "rug")]
876        mod rug53 {
877            use super::*;
878
879            mod real {
880                use super::*;
881
882                #[test]
883                fn test_rug_float_cosh_valid() {
884                    let value =
885                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
886
887                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
888                        53,
889                        1.5430806348152437,
890                    ))
891                    .unwrap();
892                    assert_eq!(value.clone().try_cosh().unwrap(), expected_result);
893                    assert_eq!(value.cosh(), expected_result);
894                }
895
896                #[test]
897                fn test_rug_float_cosh_zero() {
898                    let value =
899                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
900
901                    let expected_result =
902                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
903                    assert_eq!(value.clone().try_cosh().unwrap(), expected_result);
904                    assert_eq!(value.cosh(), expected_result);
905                }
906            }
907
908            mod complex {
909                use super::*;
910
911                #[test]
912                fn test_complex_rug_float_cosh_valid() {
913                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
914                        53,
915                        (rug::Float::with_val(53, 1.0), rug::Float::with_val(53, 1.0)),
916                    ))
917                    .unwrap();
918
919                    let expected_result =
920                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
921                            53,
922                            (
923                                rug::Float::with_val(53, 0.833730025131149),
924                                rug::Float::with_val(53, 0.9888977057628651),
925                            ),
926                        ))
927                        .unwrap();
928                    assert_eq!(value.clone().try_cosh().unwrap(), expected_result);
929                    assert_eq!(value.cosh(), expected_result);
930                }
931
932                #[test]
933                fn test_complex_rug_float_cosh_zero() {
934                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
935                        53,
936                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
937                    ))
938                    .unwrap();
939
940                    let expected_result =
941                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
942                            53,
943                            (rug::Float::with_val(53, 1.0), rug::Float::with_val(53, 0.0)),
944                        ))
945                        .unwrap();
946                    assert_eq!(value.clone().try_cosh().unwrap(), expected_result);
947                    assert_eq!(value.cosh(), expected_result);
948                }
949            }
950        }
951    }
952
953    mod tanh {
954        use super::*;
955
956        mod native {
957            use super::*;
958
959            mod real {
960                use super::*;
961
962                #[test]
963                fn test_f64_tanh_valid() {
964                    let value = 1.0;
965                    let expected_result = 0.7615941559557649;
966                    assert_eq!(value.try_tanh().unwrap(), expected_result);
967                    assert_eq!(<f64 as TanH>::tanh(value), expected_result);
968                    assert_eq!(value.tanh(), expected_result);
969                }
970
971                #[test]
972                fn test_f64_tanh_negative() {
973                    let value = -1.0;
974                    let expected_result = -0.7615941559557649;
975                    assert_eq!(value.try_tanh().unwrap(), expected_result);
976                    assert_eq!(<f64 as Float>::tanh(value), expected_result);
977                    assert_eq!(TanH::tanh(value), expected_result);
978                }
979
980                #[test]
981                fn test_f64_tanh_zero() {
982                    let value = 0.0;
983                    let expected_result = 0.0;
984                    assert_eq!(value.try_tanh().unwrap(), expected_result);
985                    assert_eq!(<f64 as Float>::tanh(value), expected_result);
986                    assert_eq!(TanH::tanh(value), expected_result);
987                }
988
989                #[test]
990                #[cfg(debug_assertions)]
991                fn test_f64_tanh_nan() {
992                    let value = f64::NAN;
993                    let result = value.try_tanh();
994                    assert!(matches!(result, Err(TanHRealErrors::Input(..))));
995                }
996
997                #[test]
998                #[cfg(debug_assertions)]
999                fn test_f64_tanh_infinity() {
1000                    let value = f64::INFINITY;
1001                    assert!(matches!(value.try_tanh(), Err(TanHRealErrors::Input(..))));
1002                }
1003
1004                #[test]
1005                #[cfg(debug_assertions)]
1006                fn test_f64_tanh_subnormal() {
1007                    let value = f64::MIN_POSITIVE / 2.0;
1008                    assert!(matches!(value.try_tanh(), Err(TanHRealErrors::Input(..))));
1009                }
1010            }
1011
1012            mod complex {
1013                use super::*;
1014
1015                #[test]
1016                fn tanh_valid() {
1017                    let value = Complex::new(1.0, 1.0);
1018                    let expected_result = if cfg!(target_arch = "x86_64") {
1019                        Complex::new(1.0839233273386948, 0.27175258531951174)
1020                    } else if cfg!(target_arch = "aarch64") {
1021                        Complex::new(1.0839233273386946, 0.27175258531951174)
1022                    } else {
1023                        todo!("Architecture not-tested");
1024                    };
1025
1026                    assert_eq!(value.try_tanh().unwrap(), expected_result);
1027                    assert_eq!(<Complex<f64> as TanH>::tanh(value), expected_result);
1028                    assert_eq!(value.tanh(), expected_result);
1029                }
1030
1031                #[test]
1032                fn tanh_zero() {
1033                    let value = Complex::new(0.0, 0.0);
1034                    let expected_result = Complex::new(0.0, 0.0);
1035                    assert_eq!(value.try_tanh().unwrap(), expected_result);
1036                    assert_eq!(value.tanh(), expected_result);
1037                }
1038
1039                #[test]
1040                #[cfg(debug_assertions)]
1041                fn tanh_nan() {
1042                    let value = Complex::new(f64::NAN, 0.0);
1043                    assert!(matches!(
1044                        value.try_tanh(),
1045                        Err(TanHComplexErrors::Input(..))
1046                    ));
1047
1048                    let value = Complex::new(0.0, f64::NAN);
1049                    assert!(matches!(
1050                        value.try_tanh(),
1051                        Err(TanHComplexErrors::Input(..))
1052                    ));
1053                }
1054
1055                #[test]
1056                #[cfg(debug_assertions)]
1057                fn tanh_infinity() {
1058                    let value = Complex::new(f64::INFINITY, 0.0);
1059                    assert!(matches!(
1060                        value.try_tanh(),
1061                        Err(TanHComplexErrors::Input(..))
1062                    ));
1063
1064                    let value = Complex::new(0.0, f64::INFINITY);
1065                    assert!(matches!(
1066                        value.try_tanh(),
1067                        Err(TanHComplexErrors::Input(..))
1068                    ));
1069                }
1070
1071                #[test]
1072                #[cfg(debug_assertions)]
1073                fn tanh_subnormal() {
1074                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1075                    assert!(matches!(
1076                        value.try_tanh(),
1077                        Err(TanHComplexErrors::Input(..))
1078                    ));
1079
1080                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1081                    assert!(matches!(
1082                        value.try_tanh(),
1083                        Err(TanHComplexErrors::Input(..))
1084                    ));
1085                }
1086            }
1087        }
1088
1089        #[cfg(feature = "rug")]
1090        mod rug53 {
1091            use super::*;
1092
1093            mod real {
1094                use super::*;
1095
1096                #[test]
1097                fn test_rug_float_tanh_valid() {
1098                    let value =
1099                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
1100
1101                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1102                        53,
1103                        0.7615941559557649,
1104                    ))
1105                    .unwrap();
1106                    assert_eq!(value.clone().try_tanh().unwrap(), expected_result);
1107                    assert_eq!(value.tanh(), expected_result);
1108                }
1109
1110                #[test]
1111                fn test_rug_float_tanh_zero() {
1112                    let value =
1113                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1114
1115                    let expected_result =
1116                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1117                    assert_eq!(value.clone().try_tanh().unwrap(), expected_result);
1118                    assert_eq!(value.tanh(), expected_result);
1119                }
1120            }
1121
1122            mod complex {
1123                use super::*;
1124
1125                #[test]
1126                fn test_complex_rug_float_tanh_valid() {
1127                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1128                        53,
1129                        (rug::Float::with_val(53, 0.5), rug::Float::with_val(53, 0.5)),
1130                    ))
1131                    .unwrap();
1132
1133                    let expected_result =
1134                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1135                            53,
1136                            (
1137                                rug::Float::with_val(53, 5.640831412674985e-1),
1138                                rug::Float::with_val(53, 4.0389645531602575e-1),
1139                            ),
1140                        ))
1141                        .unwrap();
1142                    assert_eq!(value.clone().try_tanh().unwrap(), expected_result);
1143                    assert_eq!(value.tanh(), expected_result);
1144                }
1145
1146                #[test]
1147                fn test_complex_rug_float_tanh_zero() {
1148                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1149                        53,
1150                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1151                    ))
1152                    .unwrap();
1153
1154                    let expected_result =
1155                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1156                            53,
1157                            (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1158                        ))
1159                        .unwrap();
1160                    assert_eq!(value.clone().try_tanh().unwrap(), expected_result);
1161                    assert_eq!(value.tanh(), expected_result);
1162                }
1163            }
1164        }
1165    }
1166
1167    mod asinh {
1168        use super::*;
1169
1170        mod native {
1171            use super::*;
1172
1173            mod real {
1174                use super::*;
1175
1176                #[test]
1177                fn test_f64_asinh_valid() {
1178                    let value = 1.0;
1179                    let expected_result = 0.881373587019543;
1180                    assert_eq!(value.try_asinh().unwrap(), expected_result);
1181                    assert_eq!(<f64 as ASinH>::asinh(value), expected_result);
1182                    assert_eq!(value.asinh(), expected_result);
1183                }
1184
1185                #[test]
1186                fn test_f64_asinh_negative() {
1187                    let value = -1.0;
1188                    let expected_result = -0.881373587019543;
1189                    assert_eq!(value.try_asinh().unwrap(), expected_result);
1190                    assert_eq!(<f64 as Float>::asinh(value), expected_result);
1191                    assert_eq!(ASinH::asinh(value), expected_result);
1192                }
1193
1194                #[test]
1195                fn test_f64_asinh_zero() {
1196                    let value = 0.0;
1197                    assert_eq!(value.try_asinh().unwrap(), 0.0);
1198                    assert_eq!(<f64 as Float>::asinh(value), 0.0);
1199                    assert_eq!(ASinH::asinh(value), 0.0);
1200                }
1201
1202                #[test]
1203                #[cfg(debug_assertions)]
1204                fn test_f64_asinh_nan() {
1205                    let value = f64::NAN;
1206                    let result = value.try_asinh();
1207                    assert!(matches!(result, Err(ASinHErrors::Input(..))));
1208                }
1209
1210                #[test]
1211                #[cfg(debug_assertions)]
1212                fn test_f64_asinh_infinity() {
1213                    let value = f64::INFINITY;
1214                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1215                }
1216
1217                #[test]
1218                #[cfg(debug_assertions)]
1219                fn test_f64_asinh_subnormal() {
1220                    let value = f64::MIN_POSITIVE / 2.0;
1221                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1222                }
1223            }
1224
1225            mod complex {
1226                use super::*;
1227
1228                #[test]
1229                fn asinh_valid() {
1230                    let value = Complex::new(1.0, 1.0);
1231                    let expected_result = Complex::new(1.0612750619050357, 0.6662394324925153);
1232                    assert_eq!(value.try_asinh().unwrap(), expected_result);
1233                    assert_eq!(<Complex<f64> as ASinH>::asinh(value), expected_result);
1234                    assert_eq!(value.asinh(), expected_result);
1235                }
1236
1237                #[test]
1238                fn asinh_zero() {
1239                    let value = Complex::new(0.0, 0.0);
1240                    let expected_result = Complex::new(0.0, 0.0);
1241                    assert_eq!(value.try_asinh().unwrap(), expected_result);
1242                    assert_eq!(value.asinh(), expected_result);
1243                }
1244
1245                #[test]
1246                #[cfg(debug_assertions)]
1247                fn asinh_nan() {
1248                    let value = Complex::new(f64::NAN, 0.0);
1249                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1250
1251                    let value = Complex::new(0.0, f64::NAN);
1252                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1253                }
1254
1255                #[test]
1256                #[cfg(debug_assertions)]
1257                fn asinh_infinity() {
1258                    let value = Complex::new(f64::INFINITY, 0.0);
1259                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1260
1261                    let value = Complex::new(0.0, f64::INFINITY);
1262                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1263                }
1264
1265                #[test]
1266                #[cfg(debug_assertions)]
1267                fn asinh_subnormal() {
1268                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1269                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
1270
1271                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1272                    assert!(matches!(value.try_asinh(), Err(ASinHErrors::Input(..))));
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_asinh_valid() {
1286                    let value =
1287                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
1288
1289                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1290                        53,
1291                        0.881373587019543,
1292                    ))
1293                    .unwrap();
1294                    assert_eq!(value.clone().try_asinh().unwrap(), expected_result);
1295                    assert_eq!(value.asinh(), expected_result);
1296                }
1297
1298                #[test]
1299                fn test_rug_float_asinh_zero() {
1300                    let value =
1301                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1302
1303                    let expected_result =
1304                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1305                    assert_eq!(value.clone().try_asinh().unwrap(), expected_result);
1306                    assert_eq!(value.asinh(), expected_result);
1307                }
1308            }
1309
1310            mod complex {
1311                use super::*;
1312
1313                #[test]
1314                fn test_complex_rug_float_asinh_valid() {
1315                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1316                        53,
1317                        (rug::Float::with_val(53, 1.0), rug::Float::with_val(53, 1.0)),
1318                    ))
1319                    .unwrap();
1320
1321                    let expected_result =
1322                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1323                            53,
1324                            (
1325                                rug::Float::with_val(53, 1.0612750619050357),
1326                                rug::Float::with_val(53, 0.6662394324925153),
1327                            ),
1328                        ))
1329                        .unwrap();
1330                    assert_eq!(value.clone().try_asinh().unwrap(), expected_result);
1331                    assert_eq!(value.asinh(), expected_result);
1332                }
1333
1334                #[test]
1335                fn test_complex_rug_float_asinh_zero() {
1336                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1337                        53,
1338                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1339                    ))
1340                    .unwrap();
1341
1342                    let expected_result =
1343                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1344                            53,
1345                            (rug::Float::with_val(53, 0.), rug::Float::with_val(53, 0.)),
1346                        ))
1347                        .unwrap();
1348                    assert_eq!(value.clone().try_asinh().unwrap(), expected_result);
1349                    assert_eq!(value.asinh(), expected_result);
1350                }
1351            }
1352        }
1353    }
1354
1355    mod acosh {
1356        use super::*;
1357
1358        mod native {
1359            use super::*;
1360
1361            mod real {
1362                use super::*;
1363
1364                #[test]
1365                fn test_f64_acosh_valid() {
1366                    let value = 1.5;
1367                    let expected_result = 0.9624236501192069;
1368                    assert_eq!(value.try_acosh().unwrap(), expected_result);
1369                    assert_eq!(<f64 as ACosH>::acosh(value), expected_result);
1370                    assert_eq!(value.acosh(), expected_result);
1371                }
1372
1373                #[test]
1374                #[cfg(debug_assertions)]
1375                fn test_f64_acosh_out_of_domain() {
1376                    let value = 0.9;
1377                    let err = value.try_acosh().unwrap_err();
1378                    assert!(matches!(
1379                        err,
1380                        ACosHErrors::Input(ACosHInputErrors::OutOfDomain { value: 0.9, .. })
1381                    ));
1382                }
1383
1384                #[test]
1385                fn test_f64_acosh_one() {
1386                    let value = 1.0;
1387                    let expected_result = 0.0;
1388                    assert_eq!(value.try_acosh().unwrap(), expected_result);
1389                    assert_eq!(<f64 as ACosH>::acosh(value), expected_result);
1390                }
1391
1392                #[test]
1393                #[cfg(debug_assertions)]
1394                fn test_f64_acosh_nan() {
1395                    let value = f64::NAN;
1396                    let result = value.try_acosh();
1397                    assert!(matches!(result, Err(ACosHErrors::Input(..))));
1398                }
1399
1400                #[test]
1401                #[cfg(debug_assertions)]
1402                fn test_f64_acosh_infinity() {
1403                    let value = f64::INFINITY;
1404                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1405                }
1406
1407                #[test]
1408                #[cfg(debug_assertions)]
1409                fn test_f64_acosh_subnormal() {
1410                    let value = f64::MIN_POSITIVE / 2.0;
1411                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1412                }
1413            }
1414
1415            mod complex {
1416                use super::*;
1417
1418                #[test]
1419                fn acosh_valid() {
1420                    let value = Complex::new(1.5, 1.5);
1421                    let expected_result = if cfg!(target_arch = "x86_64") {
1422                        Complex::new(1.44973434958536, 0.840395108841671)
1423                    } else if cfg!(target_arch = "aarch64") {
1424                        Complex::new(1.4497343495853596, 0.8403951088416711)
1425                    } else {
1426                        todo!("Architecture not-tested");
1427                    };
1428
1429                    assert_eq!(value.try_acosh().unwrap(), expected_result);
1430                    assert_eq!(<Complex<f64> as ACosH>::acosh(value), expected_result);
1431                    assert_eq!(value.acosh(), expected_result);
1432                }
1433
1434                #[test]
1435                #[cfg(debug_assertions)]
1436                fn acosh_out_of_domain() {
1437                    let v = Complex::new(-1.1, 0.);
1438                    let err = v.try_acosh().unwrap_err();
1439                    assert!(matches!(
1440                        err,
1441                        ACosHErrors::Input(ACosHInputErrors::OutOfDomain { .. })
1442                    ));
1443                }
1444
1445                #[test]
1446                fn acosh_one() {
1447                    let value = Complex::new(1.0, 0.0);
1448                    let expected_result = Complex::new(0.0, 0.0);
1449                    assert_eq!(value.try_acosh().unwrap(), expected_result);
1450                    assert_eq!(value.acosh(), expected_result);
1451                }
1452
1453                #[test]
1454                #[cfg(debug_assertions)]
1455                fn acosh_nan() {
1456                    let value = Complex::new(f64::NAN, 0.0);
1457                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1458
1459                    let value = Complex::new(0.0, f64::NAN);
1460                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1461                }
1462
1463                #[test]
1464                #[cfg(debug_assertions)]
1465                fn acosh_infinity() {
1466                    let value = Complex::new(f64::INFINITY, 0.0);
1467                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1468
1469                    let value = Complex::new(0.0, f64::INFINITY);
1470                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1471                }
1472
1473                #[test]
1474                #[cfg(debug_assertions)]
1475                fn acosh_subnormal() {
1476                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1477                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1478
1479                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1480                    assert!(matches!(value.try_acosh(), Err(ACosHErrors::Input(..))));
1481                }
1482            }
1483        }
1484
1485        #[cfg(feature = "rug")]
1486        mod rug53 {
1487            use super::*;
1488
1489            mod real {
1490                use super::*;
1491
1492                #[test]
1493                fn test_rug_float_acosh_valid() {
1494                    let value =
1495                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.5)).unwrap();
1496
1497                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1498                        53,
1499                        0.9624236501192069,
1500                    ))
1501                    .unwrap();
1502                    assert_eq!(value.clone().try_acosh().unwrap(), expected_result);
1503                    assert_eq!(value.acosh(), expected_result);
1504                }
1505
1506                #[test]
1507                fn test_rug_float_acosh_one() {
1508                    let value =
1509                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 1.0)).unwrap();
1510
1511                    let expected_result =
1512                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1513                    assert_eq!(value.clone().try_acosh().unwrap(), expected_result);
1514                    assert_eq!(value.acosh(), expected_result);
1515                }
1516            }
1517
1518            mod complex {
1519                use super::*;
1520
1521                #[test]
1522                fn test_complex_rug_float_acosh_valid() {
1523                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1524                        53,
1525                        (rug::Float::with_val(53, 1.5), rug::Float::with_val(53, 1.5)),
1526                    ))
1527                    .unwrap();
1528
1529                    let expected_result =
1530                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1531                            53,
1532                            (
1533                                rug::Float::with_val(53, 1.4497343495853598),
1534                                rug::Float::with_val(53, 8.403951088416711e-1),
1535                            ),
1536                        ))
1537                        .unwrap();
1538                    assert_eq!(value.clone().try_acosh().unwrap(), expected_result);
1539                    assert_eq!(value.acosh(), expected_result);
1540                }
1541
1542                #[test]
1543                fn test_complex_rug_float_acosh_one() {
1544                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1545                        53,
1546                        (rug::Float::with_val(53, 1.0), rug::Float::with_val(53, 0.0)),
1547                    ))
1548                    .unwrap();
1549
1550                    let expected_result =
1551                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1552                            53,
1553                            (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1554                        ))
1555                        .unwrap();
1556                    assert_eq!(value.clone().try_acosh().unwrap(), expected_result);
1557                    assert_eq!(value.acosh(), expected_result);
1558                }
1559            }
1560        }
1561    }
1562
1563    mod atanh {
1564        use super::*;
1565
1566        mod native {
1567            use super::*;
1568
1569            mod real {
1570                use super::*;
1571
1572                #[test]
1573                fn test_f64_atanh_valid() {
1574                    let value = 0.5;
1575                    let expected_result = 0.5493061443340548;
1576
1577                    assert_ulps_eq!(value.try_atanh().unwrap(), expected_result);
1578                    assert_ulps_eq!(<f64 as ATanH>::atanh(value), expected_result);
1579                    assert_ulps_eq!(value.atanh(), expected_result);
1580                }
1581
1582                #[test]
1583                fn test_f64_atanh_negative() {
1584                    let value = -0.5;
1585                    let expected_result = -0.5493061443340548;
1586                    assert_eq!(value.try_atanh().unwrap(), expected_result);
1587                    assert_eq!(ATanH::atanh(value), expected_result);
1588                }
1589
1590                #[test]
1591                #[cfg(debug_assertions)]
1592                fn test_f64_atanh_out_of_domain() {
1593                    let value = 1.0;
1594                    let err = value.try_atanh().unwrap_err();
1595                    assert!(matches!(
1596                        err,
1597                        ATanHErrors::Input(ATanHInputErrors::OutOfDomain { value: 1., .. })
1598                    ));
1599                }
1600
1601                #[test]
1602                fn test_f64_atanh_zero() {
1603                    let value = 0.0;
1604                    assert_eq!(value.try_atanh().unwrap(), 0.0);
1605                    assert_eq!(ATanH::atanh(value), 0.0);
1606                }
1607
1608                #[test]
1609                #[cfg(debug_assertions)]
1610                fn test_f64_atanh_nan() {
1611                    let value = f64::NAN;
1612                    let result = value.try_atanh();
1613                    assert!(matches!(result, Err(ATanHErrors::Input(..))));
1614                }
1615
1616                #[test]
1617                #[cfg(debug_assertions)]
1618                fn test_f64_atanh_infinity() {
1619                    let value = f64::INFINITY;
1620                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1621                }
1622
1623                #[test]
1624                #[cfg(debug_assertions)]
1625                fn test_f64_atanh_subnormal() {
1626                    let value = f64::MIN_POSITIVE / 2.0;
1627                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1628                }
1629            }
1630
1631            mod complex {
1632                use super::*;
1633
1634                #[test]
1635                fn atanh_valid() {
1636                    let value = Complex::new(0.5, 0.5);
1637                    let expected_result = Complex::new(0.4023594781085251, 0.5535743588970452);
1638                    assert_eq!(value.try_atanh().unwrap(), expected_result);
1639                    assert_eq!(<Complex<f64> as ATanH>::atanh(value), expected_result);
1640                    assert_eq!(value.atanh(), expected_result);
1641                }
1642
1643                #[test]
1644                #[cfg(debug_assertions)]
1645                fn atanh_out_of_domain() {
1646                    let v = Complex::new(-1., 0.);
1647                    let err = v.try_atanh().unwrap_err();
1648                    assert!(matches!(
1649                        err,
1650                        ATanHErrors::Input(ATanHInputErrors::OutOfDomain { .. })
1651                    ));
1652                }
1653
1654                #[test]
1655                fn atanh_zero() {
1656                    let value = Complex::new(0.0, 0.0);
1657                    let expected_result = Complex::new(0.0, 0.0);
1658                    assert_eq!(value.try_atanh().unwrap(), expected_result);
1659                    assert_eq!(value.atanh(), expected_result);
1660                }
1661
1662                #[test]
1663                #[cfg(debug_assertions)]
1664                fn atanh_nan() {
1665                    let value = Complex::new(f64::NAN, 0.0);
1666                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1667
1668                    let value = Complex::new(0.0, f64::NAN);
1669                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1670                }
1671
1672                #[test]
1673                #[cfg(debug_assertions)]
1674                fn atanh_infinity() {
1675                    let value = Complex::new(f64::INFINITY, 0.0);
1676                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1677
1678                    let value = Complex::new(0.0, f64::INFINITY);
1679                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1680                }
1681
1682                #[test]
1683                #[cfg(debug_assertions)]
1684                fn atanh_subnormal() {
1685                    let value = Complex::new(f64::MIN_POSITIVE / 2.0, 0.0);
1686                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1687
1688                    let value = Complex::new(0.0, f64::MIN_POSITIVE / 2.0);
1689                    assert!(matches!(value.try_atanh(), Err(ATanHErrors::Input(..))));
1690                }
1691            }
1692        }
1693
1694        #[cfg(feature = "rug")]
1695        mod rug53 {
1696            use super::*;
1697
1698            mod real {
1699                use super::*;
1700
1701                #[test]
1702                fn test_rug_float_atanh_valid() {
1703                    let value =
1704                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.5)).unwrap();
1705
1706                    let expected_result = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
1707                        53,
1708                        0.5493061443340549,
1709                    ))
1710                    .unwrap();
1711                    assert_eq!(value.clone().try_atanh().unwrap(), expected_result);
1712                    assert_eq!(value.atanh(), expected_result);
1713                }
1714
1715                #[test]
1716                fn test_rug_float_atanh_zero() {
1717                    let value =
1718                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1719
1720                    let expected_result =
1721                        RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
1722                    assert_eq!(value.clone().try_atanh().unwrap(), expected_result);
1723                    assert_eq!(value.atanh(), expected_result);
1724                }
1725            }
1726
1727            mod complex {
1728                use super::*;
1729
1730                #[test]
1731                fn test_complex_rug_float_atanh_valid() {
1732                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1733                        53,
1734                        (rug::Float::with_val(53, 0.5), rug::Float::with_val(53, 0.5)),
1735                    ))
1736                    .unwrap();
1737
1738                    let expected_result =
1739                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1740                            53,
1741                            (
1742                                rug::Float::with_val(53, 0.40235947810852507),
1743                                rug::Float::with_val(53, 0.5535743588970452),
1744                            ),
1745                        ))
1746                        .unwrap();
1747                    assert_eq!(value.clone().try_atanh().unwrap(), expected_result);
1748                    assert_eq!(value.atanh(), expected_result);
1749                }
1750
1751                #[test]
1752                fn test_complex_rug_float_atanh_zero() {
1753                    let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1754                        53,
1755                        (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1756                    ))
1757                    .unwrap();
1758
1759                    let expected_result =
1760                        ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
1761                            53,
1762                            (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
1763                        ))
1764                        .unwrap();
1765                    assert_eq!(value.clone().try_atanh().unwrap(), expected_result);
1766                    assert_eq!(value.atanh(), expected_result);
1767                }
1768            }
1769        }
1770    }
1771}
1772//------------------------------------------------------------------------------------------------