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