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