num_valid/
lib.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2#![feature(error_generic_member_access)]
3//#![feature(const_trait_impl)]
4#![feature(associated_const_equality)]
5#![feature(trait_alias)]
6//#![feature(generic_const_exprs)]
7//#![feature(associated_type_defaults)]
8//#![feature(non_lifetime_binders)]
9//#![feature(negative_impls)]
10
11//! [`num-valid`](crate) is a Rust library designed for robust, generic, and high-performance numerical computation.
12//! It provides a safe and extensible framework for working with both real and complex numbers, addressing the challenges
13//! of floating-point arithmetic by ensuring correctness and preventing common errors like `NaN` propagation.
14//!
15//! # Key Features \& Architecture
16//!
17//! - **Safety by Construction with Validated Types:** Instead of using raw primitives like [`f64`] or [`Complex<f64>`](num::Complex)
18//!   directly, [`num-valid`](crate) encourages the use of validated wrappers like [`RealValidated`]
19//!   and [`ComplexValidated`]. These types guarantee that the value they hold is always valid (e.g.,
20//!   finite) according to a specific policy, eliminating entire classes of numerical bugs.
21//!
22//! - **Enhanced Type Safety with Hashing Support:** Types validated with policies that guarantee
23//!   finite values (like [`Native64StrictFinite`]) automatically
24//!   implement [`Eq`] and [`Hash`]. This enables their use as keys in [`HashMap`](std::collections::HashMap) and other
25//!   hash-based collections, while maintaining compatibility with the library's [`PartialOrd`]-based
26//!   comparison functions. The hashing implementation properly handles IEEE 754 floating-point
27//!   edge cases and ensures that mathematically equal values produce identical hash codes.
28//!
29//! - **Support for Real and Complex Numbers:** The library supports both real and complex numbers,
30//!   with specific validation policies for each type.
31//!
32//! - **Layered and Extensible Design:** The library has a well-defined, layered, and highly generic architecture.
33//!   It abstracts the concept of a "numerical kernel" (the underlying number representation and its operations) from the high-level mathematical traits.
34//!
35//!   The architecture can be understood in four main layers:
36//!   - **Layer 1: Raw Trait Contracts** ([`kernels`] module):
37//!     - The [`RawScalarTrait`], [`RawRealTrait`], and [`RawComplexTrait`](crate::kernels::RawComplexTrait) define the low-level, "unchecked" contract
38//!       for any number type.
39//!     - These traits are the foundation, providing a standard set of `unchecked_*` methods.
40//!     - The contract is that the caller must guarantee the validity of inputs. This is a strong design choice, separating the raw, potentially unsafe operations from the validated, safe API.
41//!
42//!     This design separates the pure, high-performance computational logic from the safety and validation logic.
43//!     It creates a clear, minimal contract for backend implementors and allows the validated wrappers in Layer 3
44//!     to be built on a foundation of trusted, high-speed operations.
45//!
46//!   - **Layer 2: Validation Policies** ([`validation`] module):
47//!     - The [`NumKernel`] trait is the bridge between the raw types and the validated wrappers.
48//!     - It bundles together the raw real/complex types and their corresponding validation policies
49//!       (e.g., [`Native64StrictFinite`], [`Native64StrictFiniteInDebug`],
50//!       etc.). This allows the entire behavior of the validated types to be configured with a single generic parameter.
51//!
52//!     It acts as the central policy configuration point. By choosing a [`NumKernel`], a user selects both a
53//!     numerical backend (e.g., [`f64`]/[`Complex<f64>`] or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html)/[`rug::Complex`](https://docs.rs/rug/latest/rug/struct.Complex.html)) and a set of validation policies (e.g., [`StrictFinitePolicy`](crate::validation::StrictFinitePolicy)
54//!     vs. [`DebugValidationPolicy`](crate::validation::DebugValidationPolicy)) for real and complex numbers,
55//!     with a single generic parameter. This dramatically simplifies writing generic code that can be configured for
56//!     different safety and performance trade-offs.
57//!
58//!   - **Layer 3: Validated Wrappers**:
59//!     - [`RealValidated<K>`] and [`ComplexValidated<K>`]
60//!       are the primary user-facing types.
61//!     - These are [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html) wrappers that are guaranteed to hold a value that conforms to the [`NumKernel`] `K` (and to the validation policies therein).
62//!     - They use extensive macros to implement high-level traits. The logic is clean: perform a check (if necessary) on the input value,
63//!       then call the corresponding `unchecked_*` method from the raw trait, and then perform a check on the output value before returning it.
64//!       This ensures safety and correctness.
65//!
66//!     These wrappers use the [newtype pattern](https://doc.rust-lang.org/rust-by-example/generics/new_types.html) to enforce correctness at the type level. By construction, an instance
67//!     of [`RealValidated`] is guaranteed to contain a value that has passed the validation policy, eliminating entire
68//!     classes of errors (like `NaN` propagation) in user code.
69//!
70//!   - **Layer 4: High-Level Abstraction Traits**:
71//!     - The [`FpScalar`] trait is the central abstraction, defining a common interface for all scalar types. It uses an associated type sealed type (`Kind`),
72//!       to enforce that a scalar is either real or complex, but not both.
73//!     - [`RealScalar`] and [`ComplexScalar`] are specialized sub-traits of [`FpScalar`] that serve as markers for real and complex numbers, respectively.
74//!     - Generic code in a consumer crate is written against these high-level traits.
75//!     - The [`RealValidated`] and [`ComplexValidated`] structs from Layer 3 are the concrete implementors of these traits.
76//!
77//!     These traits provide the final, safe, and generic public API. Library consumers write their algorithms
78//!     against these traits, making their code independent of the specific numerical kernel being used.
79//!
80//!   This layered approach is powerful, providing both high performance (by using unchecked methods internally) and safety
81//!   (through the validated wrappers). The use of generics and traits makes it extensible to new numerical backends (as demonstrated by the rug implementation).
82//!
83//! - **Multiple Numerical Backends**. At the time of writing, 2 numerical backends can be used:
84//!   - the standard (high-performance) numerical backend is the one in which the raw floating point and complex numbers are
85//!     described by the Rust's native [`f64`] and [`Complex<f64>`](num::Complex) types, as described by the ANSI/IEEE Std 754-1985;
86//!   - an optional (high-precision) numerical backend is available if the library is compiled with the optional flag `--features=rug`,
87//!     and uses the arbitrary precision raw types `rug::Float` and `rug::Complex` from the Rust library [`rug`](https://crates.io/crates/rug).
88//! - **Comprehensive Mathematical Library**. It includes a wide range of mathematical functions for
89//!   trigonometry, logarithms, exponentials, and more, all implemented as traits (e.g., [`functions::Sin`], [`functions::Cos`], [`functions::Sqrt`]) and available on the validated types.
90//! - **Numerically Robust Implementations**. The library commits to numerical accuracy. As an example,
91//!   by using `NeumaierSum` for its default [`std::iter::Sum`] implementation to minimize precision loss.
92//! - **Robust Error Handling:** The library defines detailed error types for various numerical operations,
93//!   ensuring that invalid inputs and outputs are properly handled and reported.
94//!   Errors are categorized into input and output errors, with specific variants for different types of numerical
95//!   issues such as division by zero, invalid values, and subnormal numbers.
96//! - **Comprehensive Documentation:** The library includes detailed documentation for each struct, trait, method,
97//!   and error type, making it easy for users to understand and utilize the provided functionality.
98//!   Examples are provided for key functions to demonstrate their usage and expected behavior.
99//! - **Zero-Copy Conversions:** The native 64-bit validated types ([`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`])
100//!   implement [`bytemuck::CheckedBitPattern`](https://docs.rs/bytemuck/latest/bytemuck/checked/trait.CheckedBitPattern.html)
101//!   and [`bytemuck::NoUninit`](https://docs.rs/bytemuck/latest/bytemuck/trait.NoUninit.html),
102//!   enabling safe, zero-copy conversions between byte representations and validated types. This is particularly useful for
103//!   interoperability with binary data formats, serialization, and performance-critical code. The conversion automatically
104//!   validates the bit pattern, rejecting invalid values (NaN, Infinity, subnormal numbers) at compile time for type safety.
105//!
106//! # Compiler Requirement: Rust Nightly
107//! This library currently requires the **nightly** toolchain because it uses some unstable Rust features which,
108//! at the time of writing (September 2025), are not yet available in stable or beta releases. These features are:
109//!   - `trait_alias`: For ergonomic trait combinations
110//!   - `associated_const_equality`: For rug precision safety
111//!   - `error_generic_member_access`: For advanced error handling
112//!
113//! If these features are stabilized in a future Rust release, the library will be updated to support the stable compiler.
114//!
115//! To use the nightly toolchain, please run:
116//!
117//! ```bash
118//! rustup install nightly
119//! rustup override set nightly
120//! ```
121//!
122//! This will set your environment to use the nightly compiler, enabling compatibility with the current version of the
123//! library.
124//!
125//! # Getting Started
126//!
127//! This guide will walk you through the basics of using [`num-valid`](crate).
128//!
129//! ## 1. Add [`num-valid`](crate) to your Project
130//!
131//! Add the following to your `Cargo.toml` (change the versions to the latest ones):
132//!
133//! ```toml
134//! [dependencies]
135//! num-valid = "0.2.0"  # Change to the latest version
136//! try_create = "0.1.2" # Needed for the TryNew trait
137//! num = "0.4"          # For basic numeric traits
138//! ```
139//!
140//! To enable the arbitrary-precision backend, use the `rug` feature:
141//!
142//! ```toml
143//! [dependencies]
144//! num-valid = { version = "0.2.0", features = ["rug"] } # Change to the latest version
145//! try_create = "0.1.2" # Needed for the TryNew trait
146//! num = "0.4"          # For basic numeric traits
147//! ```
148//!
149//! ## 2. Core Concept: Validated Types
150//!
151//! The central idea in [`num-valid`](crate) is to use **validated types** instead of raw primitives like [`f64`].
152//! These are wrappers that guarantee their inner value is always valid (e.g., not `NaN` or `Infinity`) according to
153//! a specific policy.
154//!
155//! The most common type you'll use is [`RealNative64StrictFinite`], which wraps an [`f64`] and ensures it's always finite,
156//! both in Debug and Release mode. For a similar type wrapping an [`f64`] that ensures it's always finite, but with the
157//! validity checks executed only in Debug mode (providing performance equal to the raw [`f64`] type), you can use
158//! [`RealNative64StrictFiniteInDebug`].
159//!
160//! ## 3. Your First Calculation
161//!
162//! Let's perform a square root calculation. You'll need to bring the necessary traits into scope.
163//!
164//! ```rust
165//! // Import the validated type and necessary traits
166//! use num_valid::{
167//!     RealNative64StrictFinite,
168//!     functions::{Sqrt, SqrtRealInputErrors, SqrtRealErrors},
169//! };
170//! use try_create::TryNew;
171//!
172//! // 1. Create a validated number. try_new() returns a Result.
173//! let x = RealNative64StrictFinite::try_new(4.0).unwrap();
174//!
175//! // 2. Use the direct method for operations.
176//! // This will panic if the operation is invalid (e.g., sqrt of a negative).
177//! let sqrt_x = x.sqrt();
178//! assert_eq!(*sqrt_x.as_ref(), 2.0);
179//!
180//! // 3. Use the `try_*` methods for error handling.
181//! // This is the safe way to handle inputs that might be out of the function's domain.
182//! let neg_x = RealNative64StrictFinite::try_new(-4.0).unwrap();
183//! let sqrt_neg_x_result = neg_x.try_sqrt();
184//!
185//! // The operation fails gracefully, returning an Err.
186//! assert!(sqrt_neg_x_result.is_err());
187//!
188//! // The error gives information about the problem that occurred
189//! if let Err(SqrtRealErrors::Input { source }) = sqrt_neg_x_result {
190//!     assert!(matches!(source, SqrtRealInputErrors::NegativeValue { .. }));
191//! }
192//! ```
193//!
194//! ## 4. Writing Generic Functions
195//!
196//! The real power of [`num-valid`](crate) comes from writing generic functions that work with any
197//! supported numerical type. You can do this by using the [`FpScalar`] and [`RealScalar`] traits as bounds.
198//!
199//! ```rust
200//! use num_valid::{
201//!     RealScalar, RealNative64StrictFinite, FpScalar,
202//!     functions::{Abs, Sin, Cos},
203//! };
204//! use num::One;
205//! use try_create::TryNew;
206//!
207//! // This function works for any type that implements RealScalar,
208//! // including f64, RealNative64StrictFinite, and RealRugStrictFinite.
209//! fn verify_trig_identity<T: RealScalar>(angle: T) -> T {
210//!     // We can use .sin(), .cos(), and arithmetic ops because they are
211//!     // required by the RealScalar trait.
212//!     let sin_x = angle.clone().sin();
213//!     let cos_x = angle.cos();
214//!     (sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
215//! }
216//!
217//! // Define a type alias for convenience
218//! type MyReal = RealNative64StrictFinite;
219//!
220//! // Call it with a validated f64 type.
221//! let angle = MyReal::try_from_f64(0.5).unwrap();
222//! let identity = verify_trig_identity(angle);
223//!
224//! // The result should be very close to 1.0.
225//! let one = MyReal::one();
226//! assert!((identity - one).abs() < MyReal::try_from_f64(1e-15).unwrap());
227//! ```
228//!
229//! If the `rug` feature is enabled, you could call the exact same
230//! function with a high-precision number changing only the definition
231//! of the alias type `MyReal`. For example, for real numbers with precision of 100 bits:
232//! ```rust
233//! # #[cfg(feature = "rug")] {
234//! // Import the rug-based types
235//! use num_valid::{
236//!     RealScalar, RealRugStrictFinite, FpScalar,
237//!     functions::{Abs, Sin, Cos},
238//! };
239//! use num::One;
240//! use try_create::TryNew;
241//!
242//! // This function works for any type that implements RealScalar,
243//! // including f64, RealNative64StrictFinite, and RealRugStrictFinite.
244//! fn verify_trig_identity<T: RealScalar>(angle: T) -> T {
245//!     // We can use .sin(), .cos(), and arithmetic ops because they are
246//!     // required by the RealScalar trait.
247//!     let sin_x = angle.clone().sin();
248//!     let cos_x = angle.cos();
249//!     (sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
250//! }
251//!
252//! // Define a type alias for convenience - real number with precision of 100 bits
253//! type MyReal = RealRugStrictFinite<100>;
254//!
255//! // Initialize it with an f64 value.
256//! let angle = MyReal::try_from_f64(0.5).unwrap();
257//! let identity = verify_trig_identity(angle);
258//!
259//! // The result should be very close to 1.0.
260//! let one = MyReal::one();
261//! assert!((identity - one).abs() < MyReal::try_from_f64(1e-15).unwrap());
262//! # }
263//! ```
264//!
265//! ## 5. Working with Complex Numbers
266//!
267//! The library also provides validated complex number types:
268//!
269//! ```rust
270//! use num_valid::{ComplexNative64StrictFinite, functions::Abs};
271//! use num::Complex;
272//! use try_create::TryNew;
273//!
274//! // Create a validated complex number
275//! let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
276//!
277//! // Complex operations work the same way
278//! let magnitude = z.abs();
279//! assert_eq!(*magnitude.as_ref(), 5.0); // |3 + 4i| = 5
280//! ```
281//!
282//! ## 6. Zero-Copy Conversions with Bytemuck
283//!
284//! For performance-critical applications working with binary data, the library provides safe, zero-copy
285//! conversions through the [`bytemuck`](https://docs.rs/bytemuck) crate. The native 64-bit validated types
286//! ([`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`]) implement
287//! [`CheckedBitPattern`](https://docs.rs/bytemuck/latest/bytemuck/checked/trait.CheckedBitPattern.html)
288//! and [`NoUninit`](https://docs.rs/bytemuck/latest/bytemuck/trait.NoUninit.html), enabling safe conversions
289//! that automatically validate bit patterns:
290//!
291//! ```rust
292//! use num_valid::RealNative64StrictFinite;
293//! use bytemuck::checked::try_from_bytes;
294//!
295//! // Convert from bytes - validation happens automatically
296//! let value = 42.0_f64;
297//! let bytes = value.to_ne_bytes();
298//! let validated: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
299//! assert_eq!(*validated.as_ref(), 42.0);
300//!
301//! // Invalid values (NaN, Infinity, subnormals) are rejected
302//! let nan_bytes = f64::NAN.to_ne_bytes();
303//! assert!(try_from_bytes::<RealNative64StrictFinite>(&nan_bytes).is_err());
304//! ```
305//!
306//! This is particularly useful for:
307//! - Loading validated numbers from binary file formats
308//! - Interoperability with serialization libraries
309//! - Processing validated numerical data in performance-critical loops
310//! - Working with memory-mapped files containing numerical data
311//!
312//! For comprehensive examples including slice operations and error handling, see the test module
313//! in the [`native64_validated`](crate::kernels::native64_validated) module source code.
314//!
315//! # License
316//! Copyright 2023-2025, C.N.R. - Consiglio Nazionale delle Ricerche
317//!
318//! Licensed under either of
319//! - Apache License, Version 2.0
320//! - MIT license
321//!
322//! at your option.
323//!
324//! Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you,
325//! as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
326//!
327//! ## License Notice for Optional Feature Dependencies (LGPL-3.0 Compliance)
328//! If you enable the `rug` feature, this project will depend on the [`rug`](https://crates.io/crates/rug) library,
329//! which is licensed under the LGPL-3.0 license. Activating this feature may introduce LGPL-3.0 requirements to your
330//! project. Please review the terms of the LGPL-3.0 license to ensure compliance.
331
332pub mod functions;
333pub mod kernels;
334pub mod neumaier_compensated_sum;
335pub mod validation;
336
337use crate::{
338    functions::{
339        ACos, ACosH, ASin, ASinH, ATan, ATan2, ATanH, Abs, Arg, Arithmetic, Clamp, Classify,
340        ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
341        ComplexScalarSetParts, Conjugate, Cos, CosH, Exp, ExpM1, HyperbolicFunctions, Hypot, Ln,
342        Ln1p, Log2, Log10, LogarithmFunctions, Max, Min, MulAddRef, NegAssign, Pow,
343        PowComplexBaseRealExponentErrors, PowIntExponent, PowRealBaseRealExponentErrors,
344        Reciprocal, Rounding, Sign, Sin, SinH, Sqrt, Tan, TanH, TotalCmp, TrigonometricFunctions,
345    },
346    kernels::{RawRealTrait, RawScalarTrait},
347    neumaier_compensated_sum::NeumaierAddable,
348    validation::{ErrorsRawRealToInteger, ErrorsTryFromf64, FpChecks},
349};
350use num::{Complex, One, Zero};
351use rand::{Rng, distr::Distribution};
352use serde::{Serialize, de::DeserializeOwned};
353use std::{
354    fmt::{Debug, Display},
355    ops::{Mul, MulAssign, Neg},
356};
357use try_create::IntoInner;
358
359pub use crate::kernels::{
360    ComplexValidated, NumKernel, RawKernel, RealValidated,
361    native64::Native64,
362    native64_validated::{
363        ComplexNative64StrictFinite, ComplexNative64StrictFiniteInDebug, Native64StrictFinite,
364        Native64StrictFiniteInDebug, RealNative64StrictFinite, RealNative64StrictFiniteInDebug,
365    },
366};
367
368#[cfg(feature = "rug")]
369pub use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite, RugStrictFinite};
370
371//------------------------------------------------------------------------------------------------
372/// Private module to encapsulate implementation details of the scalar kind for mutual exclusion.
373///
374/// This module provides the sealed trait pattern to ensure that scalar types can only be
375/// either real or complex, but never both. The sealed nature prevents external crates
376/// from implementing the trait, maintaining the library's type safety guarantees.
377pub(crate) mod scalar_kind {
378    /// A sealed trait to mark the "kind" of a scalar.
379    ///
380    /// External users cannot implement this trait due to the sealed pattern.
381    /// This ensures that only the library-defined scalar kinds (Real and Complex)
382    /// can be used with the [`FpScalar`](super::FpScalar) trait.
383    pub trait Sealed {}
384
385    /// A marker type for real scalar types.
386    ///
387    /// This type is used as the `Kind` associated type for real number types
388    /// in the [`FpScalar`](super::FpScalar) trait, ensuring type-level distinction
389    /// between real and complex scalars.
390    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
391    pub struct Real;
392    impl Sealed for Real {}
393
394    /// A marker type for complex scalar types.
395    ///
396    /// This type is used as the `Kind` associated type for complex number types
397    /// in the [`FpScalar`](super::FpScalar) trait, ensuring type-level distinction
398    /// between real and complex scalars.
399    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
400    pub struct Complex;
401    impl Sealed for Complex {}
402}
403//------------------------------------------------------------------------------------------------
404
405//------------------------------------------------------------------------------------------------
406
407/// # Core trait for a floating-point scalar number (real or complex)
408///
409/// [`FpScalar`] is a fundamental trait in [`num-valid`](crate) that provides a common interface
410/// for all floating-point scalar types, whether they are real or complex, and regardless
411/// of their underlying numerical kernel (e.g., native [`f64`] or arbitrary-precision [`rug`](https://docs.rs/rug/latest/rug/index.html) types).
412///
413/// This trait serves as a primary bound for generic functions and structures that need to
414/// operate on scalar values capable of floating-point arithmetic. It aggregates a large
415/// number of mathematical function traits (e.g., [`functions::Sin`], [`functions::Cos`], [`functions::Exp`], [`functions::Sqrt`]) and
416/// core properties.
417///
418/// ## Key Responsibilities and Associated Types:
419///
420/// - **Scalar Kind (`FpScalar::Kind`):**
421///   This associated type specifies the fundamental nature of the scalar, which can be
422///   either `scalar_kind::Real` or `scalar_kind::Complex`. It is bound by the private,
423///   sealed trait `scalar_kind::Sealed`. This design enforces **mutual exclusion**:
424///   since a type can only implement [`FpScalar`] once, it can only have one `Kind`,
425///   making it impossible for a type to be both a `RealScalar` and a `ComplexScalar` simultaneously.
426///
427/// - **Real Type Component ([`FpScalar::RealType`]):**
428///   Specifies the real number type corresponding to this scalar via [`RealType`](FpScalar::RealType).
429///   - For real scalars (e.g., [`f64`], [`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`],
430///     `RealRugStrictFinite`, etc.), [`FpScalar::RealType`] is `Self`.
431///   - For complex scalars (e.g., [`Complex<f64>`](num::Complex), [`ComplexNative64StrictFinite`], [`ComplexNative64StrictFiniteInDebug`],
432///     `ComplexRugStrictFinite`, etc.), [`FpScalar::RealType`] is their underlying real component type
433///     (e.g., [`f64`], [`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`], `RealRugStrictFinite`, etc.).
434///  
435///   Crucially, this [`FpScalar::RealType`] is constrained to implement [`RealScalar`], ensuring consistency.
436///
437/// - **Core Floating-Point Properties:**
438///   [`FpScalar`] requires implementations of the trait [`FpChecks`], which provides fundamental floating-point checks:
439///   - [`is_finite()`](FpChecks::is_finite): Checks if the number is finite.
440///   - [`is_infinite()`](FpChecks::is_infinite): Checks if the number is positive or negative infinity.
441///   - [`is_nan()`](FpChecks::is_nan): Checks if the number is "Not a Number".
442///   - [`is_normal()`](FpChecks::is_normal): Checks if the number is a normal (not zero, subnormal, infinite, or NaN).
443///
444/// ## Trait Bounds:
445///
446/// [`FpScalar`] itself has several important trait bounds:
447/// - `Sized + Clone + Debug + Display + PartialEq`: Standard utility traits. Note that scalar
448///   types are [`Clone`] but not necessarily [`Copy`].
449/// - [`Zero`] + [`One`]: From `num_traits`, ensuring the type has additive and multiplicative identities.
450/// - [`Neg<Output = Self>`](Neg): Ensures the type can be negated.
451/// - [`Arithmetic`]: A custom aggregate trait in [`num-valid`](crate) that bundles standard
452///   arithmetic operator traits (like [`Add`](std::ops::Add), [`Sub`](std::ops::Sub), [`Mul`], [`Div`](std::ops::Div)).
453/// - [`RandomSampleFromF64`]: Allows the type to be randomly generated from any distribution
454///   that produces `f64`, integrating with the [`rand`] crate.
455/// - `Send + Sync + 'static`: Makes the scalar types suitable for use in concurrent contexts.
456/// - A comprehensive suite of mathematical function traits like [`functions::Sin`], [`functions::Cos`], [`functions::Exp`], [`functions::Ln`], [`functions::Sqrt`], etc.
457///
458/// ## Relationship to Other Traits:
459///
460/// - [`RealScalar`]: A sub-trait of [`FpScalar`] for real numbers, defined by the constraint `FpScalar<Kind = scalar_kind::Real>`.
461/// - [`ComplexScalar`]: A sub-trait of [`FpScalar`] for complex numbers, defined by the constraint `FpScalar<Kind = scalar_kind::Complex>`.
462/// - [`NumKernel`]: Policies like [`Native64StrictFinite`]
463///   are used to validate the raw values that are wrapped inside types implementing `FpScalar`.
464///
465/// ## Example: Generic Function
466///
467/// Here is how you can write a generic function that works with any scalar type
468/// implementing `FpScalar`.
469///
470/// ```rust
471/// use num_valid::{FpScalar, functions::{MulAddRef, Sqrt}, RealNative64StrictFinite};
472/// use num::Zero;
473/// use try_create::TryNew;
474///
475/// // This function works with any FpScalar type.
476/// fn norm_and_sqrt<T: FpScalar>(a: T, b: T) -> T {
477///     let val = a.clone().mul_add_ref(&a, &(b.clone() * b)); // a*a + b*b
478///     val.sqrt()
479/// }
480///
481/// // Also this function works with any FpScalar type.
482/// fn multiply_if_not_zero<T: FpScalar>(a: T, b: T) -> T {
483///     if !a.is_zero() && !b.is_zero() {
484///         a * b
485///     } else {
486///         T::zero()
487///     }
488/// }
489///
490/// // Example usage
491/// let a = RealNative64StrictFinite::try_new(3.0).unwrap();
492/// let b = RealNative64StrictFinite::try_new(4.0).unwrap();
493/// let result = norm_and_sqrt(a, b);
494/// assert_eq!(*result.as_ref(), 5.0);
495/// ```
496pub trait FpScalar:
497    Sized
498    + Clone
499    + Send
500    + Sync
501    + Debug
502    + Display
503    + IntoInner<InnerType: RawScalarTrait>
504    + PartialEq
505    + Arithmetic
506    + Abs<Output = Self::RealType>
507    + Sqrt
508    + PowIntExponent<RawType = Self::InnerType>
509    + TrigonometricFunctions
510    + HyperbolicFunctions
511    + LogarithmFunctions
512    + Exp
513    + Zero
514    + One
515    + FpChecks
516    + Neg<Output = Self>
517    + MulAddRef
518    + Reciprocal
519    + NeumaierAddable
520    + RandomSampleFromF64
521    + Serialize
522    + DeserializeOwned
523    + 'static
524{
525    /// The kind of scalar this is, e.g., `Real` or `Complex`.
526    /// This is a sealed trait to prevent external implementations.
527    type Kind: scalar_kind::Sealed;
528
529    /// The real number type corresponding to this scalar.
530    ///
531    /// - For real scalars (e.g., `f64`), `RealType` is `Self`.
532    /// - For complex scalars (e.g., `Complex<f64>`), `RealType` is their underlying
533    ///   real component type (e.g., `f64`).
534    ///
535    /// This `RealType` is guaranteed to implement [`RealScalar`] and belong to the
536    /// same numerical kernel as `Self`.
537    type RealType: RealScalar<RealType = Self::RealType>;
538
539    /// Returns a reference to the underlying raw scalar value.
540    fn as_raw_ref(&self) -> &Self::InnerType;
541}
542//-------------------------------------------------------------------------------------------------------------
543
544//-------------------------------------------------------------------------------------------------------------
545
546/// Provides fundamental mathematical constants for floating-point scalar types.
547///
548/// This trait defines methods to obtain commonly used mathematical constants
549/// in the appropriate precision and type for the implementing scalar type.
550/// All constants are guaranteed to be finite and valid according to the
551/// scalar's validation policy.
552///
553/// ## Design Principles
554///
555/// - **Type-Appropriate Precision**: Constants are provided at the precision
556///   of the implementing type (e.g., `f64` precision for native types,
557///   arbitrary precision for `rug` types).
558/// - **Validation Compliance**: All returned constants are guaranteed to pass
559///   the validation policy of the implementing type.
560/// - **Mathematical Accuracy**: Constants use the most accurate representation
561///   available for the underlying numerical type.
562///
563/// ## Usage Examples
564///
565/// ```rust
566/// use num_valid::{RealNative64StrictFinite, Constants, functions::Exp};
567/// use try_create::TryNew;
568///
569/// // Get mathematical constants
570/// let pi = RealNative64StrictFinite::pi();
571/// let e = RealNative64StrictFinite::e();
572/// let eps = RealNative64StrictFinite::epsilon();
573///
574/// // Use in calculations
575/// let circle_area = pi.clone() * &(pi * RealNative64StrictFinite::two());
576/// let exp_1 = e.exp(); // e^e
577/// ```
578///
579/// ## Backend-Specific Behavior
580///
581/// ### Native `f64` Backend
582/// - Uses standard library constants like `std::f64::consts::PI`
583/// - IEEE 754 double precision (53-bit significand)
584/// - Hardware-optimized representations
585///
586/// ### Arbitrary-Precision (`rug`) Backend
587/// - Constants computed at compile-time specified precision
588/// - Exact representations within precision limits
589/// - May use higher-precision intermediate calculations
590pub trait Constants: Sized {
591    /// [Machine epsilon] value for `Self`.
592    ///
593    /// This is the difference between `1.0` and the next larger representable number.
594    /// It represents the relative precision of the floating-point format.
595    ///
596    /// ## Examples
597    ///
598    /// ```rust
599    /// use num_valid::{RealNative64StrictFinite, Constants};
600    ///
601    /// let eps = RealNative64StrictFinite::epsilon();
602    /// // For f64, this is approximately 2.220446049250313e-16
603    /// ```
604    ///
605    /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
606    fn epsilon() -> Self;
607
608    /// Build and return the (floating point) value -1. represented by the proper type.
609    fn negative_one() -> Self;
610
611    /// Build and return the (floating point) value 0.5 represented by the proper type.
612    fn one_div_2() -> Self;
613
614    /// Build and return the (floating point) value `Ï€` represented by the proper type.
615    fn pi() -> Self;
616
617    /// Build and return the (floating point) value `2 π` represented by the proper type.
618    fn two_pi() -> Self;
619
620    /// Build and return the (floating point) value `Ï€/2` represented by the proper type.
621    fn pi_div_2() -> Self;
622
623    /// Build and return the (floating point) value 2. represented by the proper type.
624    fn two() -> Self;
625
626    /// Build and return the maximum finite value allowed by the current floating point representation.
627    fn max_finite() -> Self;
628
629    /// Build and return the minimum finite (i.e., the most negative) value allowed by the current floating point representation.
630    fn min_finite() -> Self;
631
632    /// Build and return the natural logarithm of 2, i.e. the (floating point) value `ln(2)`, represented by the proper type.
633    fn ln_2() -> Self;
634
635    /// Build and return the natural logarithm of 10, i.e. the (floating point) value `ln(10)`, represented by the proper type.
636    fn ln_10() -> Self;
637
638    /// Build and return the base-10 logarithm of 2, i.e. the (floating point) value `Log_10(2)`, represented by the proper type.
639    fn log10_2() -> Self;
640
641    /// Build and return the base-2 logarithm of 10, i.e. the (floating point) value `Log_2(10)`, represented by the proper type.
642    fn log2_10() -> Self;
643
644    /// Build and return the base-2 logarithm of `e`, i.e. the (floating point) value `Log_2(e)`, represented by the proper type.
645    fn log2_e() -> Self;
646
647    /// Build and return the base-10 logarithm of `e`, i.e. the (floating point) value `Log_10(e)`, represented by the proper type.
648    fn log10_e() -> Self;
649
650    /// Build and return the (floating point) value `e` represented by the proper type.
651    fn e() -> Self;
652}
653
654/// # Trait for scalar real numbers
655///
656/// [`RealScalar`] extends the fundamental [`FpScalar`] trait, providing an interface
657/// specifically for real (non-complex) floating-point numbers. It introduces
658/// operations and properties that are unique to real numbers, such as ordering,
659/// rounding, and clamping.
660///
661/// This trait is implemented by real scalar types within each numerical kernel,
662/// for example, [`f64`] for the native kernel,
663/// and `RealRugStrictFinite` for the `rug` kernel (when the `rug` feature is enabled).
664///
665/// ## Key Design Principles
666///
667/// - **Inheritance from [`FpScalar`]:** As a sub-trait of [`FpScalar`], any `RealScalar`
668///   type automatically gains all the capabilities of a general floating-point number,
669///   including basic arithmetic and standard mathematical functions (e.g., `sin`, `exp`, `sqrt`).
670/// - **Raw Underlying Type ([`RawReal`](Self::RawReal)):**
671///   This associated type specifies the most fundamental, "raw" representation of the real number,
672///   which implements the [`RawRealTrait`]. This is the type used for low-level, unchecked
673///   operations within the library's internal implementation.
674///   - For [`f64`], [`RealNative64StrictFinite`] and [`RealNative64StrictFiniteInDebug`], `RawReal` is [`f64`].
675///   - For `RealRugStrictFinite<P>`, `RawReal` is [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
676/// - **Reference-Based Operations**: Many operations take arguments by reference (`&Self`)
677///   to avoid unnecessary clones of potentially expensive arbitrary-precision numbers.
678/// - **Fallible Constructors**: [`try_from_f64()`](Self::try_from_f64) validates inputs
679///   and ensures exact representability for arbitrary-precision types.
680///
681/// ## Type Safety with Validated Types
682///
683/// Real scalars that use validation policies implementing finite value guarantees
684/// automatically gain:
685/// - **Full Equality ([`Eq`])**: Well-defined, symmetric equality comparisons
686/// - **Hashing ([`Hash`])**: Use as keys in [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet)
687/// - **No Total Ordering**: The library intentionally avoids [`Ord`] in favor of
688///   more efficient reference-based [`functions::Max`]/[`functions::Min`] operations
689///
690/// ## Mathematical Operations
691///
692/// ### Core Arithmetic
693/// All standard arithmetic operations are available through the [`Arithmetic`] trait,
694/// supporting both value and reference semantics:
695/// ```rust
696/// use num_valid::RealNative64StrictFinite;
697/// use try_create::TryNew;
698///
699/// let a = RealNative64StrictFinite::try_new(2.0).unwrap();
700/// let b = RealNative64StrictFinite::try_new(3.0).unwrap();
701///
702/// // All combinations supported: T op T, T op &T, &T op T, &T op &T
703/// let sum1 = a.clone() + b.clone();
704/// let sum2 = &a + &b;
705/// let sum3 = a.clone() + &b;
706/// let sum4 = &a + b.clone();
707///
708/// assert_eq!(sum1, sum2);
709/// assert_eq!(sum2, sum3);
710/// assert_eq!(sum3, sum4);
711/// ```
712///
713/// ### Advanced Functions
714///
715/// In addition to the functions from [`FpScalar`], `RealScalar` provides a suite of methods common in real number arithmetic.
716/// Methods prefixed with `kernel_` provide direct access to underlying mathematical operations with minimal overhead:
717///
718/// - **Rounding ([`Rounding`]):**
719///   [`kernel_ceil()`](Rounding::kernel_ceil), [`kernel_floor()`](Rounding::kernel_floor),
720///   [`kernel_round()`](Rounding::kernel_round), [`kernel_round_ties_even()`](Rounding::kernel_round_ties_even),
721///   [`kernel_trunc()`](Rounding::kernel_trunc), and [`kernel_fract()`](Rounding::kernel_fract).
722///
723/// - **Sign Manipulation ([`Sign`]):**
724///   [`kernel_copysign()`](Sign::kernel_copysign), [`kernel_signum()`](Sign::kernel_signum),
725///   [`kernel_is_sign_positive()`](Sign::kernel_is_sign_positive), and [`kernel_is_sign_negative()`](Sign::kernel_is_sign_negative).
726///
727/// - **Comparison and Ordering:**
728///   - From [`functions::Max`]/[`functions::Min`]: [`max()`](functions::Max::max) and [`min()`](functions::Min::min).
729///   - From [`TotalCmp`]: [`total_cmp()`](TotalCmp::total_cmp) for a total ordering compliant with IEEE 754.
730///   - From [`Clamp`]: [`kernel_clamp()`](Clamp::kernel_clamp).
731///
732/// - **Specialized Functions:**
733///   - From [`ATan2`]: [`atan2()`](ATan2::atan2).
734///   - From [`ExpM1`]/[`Ln1p`]: [`kernel_exp_m1()`](ExpM1::kernel_exp_m1) and [`kernel_ln_1p()`](Ln1p::kernel_ln_1p).
735///   - From [`Hypot`]: [`kernel_hypot()`](Hypot::kernel_hypot) for computing sqrt(a² + b²).
736///   - From [`Classify`]: [`kernel_classify()`](Classify::kernel_classify).
737///
738/// - **Fused Multiply-Add Variants:**
739///   [`kernel_mul_add_mul_mut()`](Self::kernel_mul_add_mul_mut) and
740///   [`kernel_mul_sub_mul_mut()`](Self::kernel_mul_sub_mul_mut).
741///
742/// ### Constants and Utilities
743///
744/// ```rust
745/// use num_valid::{RealNative64StrictFinite, Constants};
746///
747/// let pi = RealNative64StrictFinite::pi();
748/// let e = RealNative64StrictFinite::e();
749/// let eps = RealNative64StrictFinite::epsilon();
750/// let max_val = RealNative64StrictFinite::max_finite();
751/// ```
752///
753/// ## Naming Convention for `kernel_*` Methods
754///
755/// Methods prefixed with `kernel_` (e.g., `kernel_ceil`, `kernel_copysign`) are
756/// part of the low-level kernel interface. They typically delegate directly to the
757/// most efficient implementation for the underlying type (like `f64::ceil`) without
758/// adding extra validation layers. They are intended to be fast primitives upon which
759/// safer, higher-level abstractions can be built.
760///
761/// ## Critical Trait Bounds
762///
763/// - `Self: FpScalar<RealType = Self>`: This is the defining constraint. It ensures that the type
764///   has all basic floating-point capabilities and confirms that its associated real type is itself.
765/// - `Self: PartialOrd + PartialOrd<f64>`: These bounds are essential for comparison operations,
766///   allowing instances to be compared both with themselves and with native `f64` constants.
767///
768/// ## Backend-Specific Behavior
769///
770/// ### Native `f64` Backend
771/// - Direct delegation to standard library functions
772/// - IEEE 754 compliance
773/// - Maximum performance
774///
775/// ### Arbitrary-Precision (`rug`) Backend
776/// - Configurable precision at compile-time
777/// - Exact arithmetic within precision limits
778/// - [`try_from_f64()`](Self::try_from_f64) validates exact representability
779///
780/// ## Error Handling
781///
782/// Operations that can fail provide both panicking and non-panicking variants:
783/// ```rust
784/// use num_valid::{RealNative64StrictFinite, functions::Sqrt};
785/// use try_create::TryNew;
786///
787/// let positive = RealNative64StrictFinite::try_new(4.0).unwrap();
788/// let negative = RealNative64StrictFinite::try_new(-4.0).unwrap();
789///
790/// // Panicking version (use when input validity is guaranteed)
791/// let sqrt_pos = positive.sqrt();
792/// assert_eq!(*sqrt_pos.as_ref(), 2.0);
793///
794/// // Non-panicking version (use for potentially invalid inputs)
795/// let sqrt_neg_result = negative.try_sqrt();
796/// assert!(sqrt_neg_result.is_err());
797/// ```
798pub trait RealScalar:
799    FpScalar<RealType = Self, InnerType = Self::RawReal>
800    + Sign
801    + Rounding
802    + Constants
803    + PartialEq<f64>
804    + PartialOrd
805    + PartialOrd<f64>
806    + Max
807    + Min
808    + ATan2
809    + for<'a> Pow<&'a Self, Error = PowRealBaseRealExponentErrors<Self::RawReal>>
810    + Clamp
811    + Classify
812    + ExpM1
813    + Hypot
814    + Ln1p
815    + TotalCmp
816{
817    /// The most fundamental, "raw" representation of this real number.
818    ///
819    /// This type provides the foundation for all mathematical operations and
820    /// is used to parameterize error types for this scalar.
821    ///
822    /// # Examples
823    /// - For [`f64`]: `RawReal = f64`
824    /// - For [`RealNative64StrictFinite`]: `RawReal = f64`
825    /// - For `RealRugStrictFinite<P>`: `RawReal = rug::Float`
826    type RawReal: RawRealTrait;
827
828    /// Multiplies two products and adds them in one fused operation, rounding to the nearest with only one rounding error.
829    /// `a.kernel_mul_add_mul_mut(&b, &c, &d)` produces a result like `&a * &b + &c * &d`, but stores the result in `a` using its precision.
830    fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self);
831
832    /// Multiplies two products and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
833    /// `a.kernel_mul_sub_mul_mut(&b, &c, &d)` produces a result like `&a * &b - &c * &d`, but stores the result in `a` using its precision.
834    fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self);
835
836    /// Tries to create an instance of `Self` from a [`f64`].
837    ///
838    /// This conversion is fallible and validates the input `value`. For `rug`-based types,
839    /// it also ensures that the `f64` can be represented exactly at the target precision.
840    ///
841    /// # Errors
842    /// Returns [`ErrorsTryFromf64`] if the `value` is not finite or cannot be
843    /// represented exactly by `Self`.
844    fn try_from_f64(value: f64) -> Result<Self, ErrorsTryFromf64<Self::RawReal>>;
845
846    /// Safely truncates the real number and converts it to a `usize`.
847    ///
848    /// This method first truncates the floating-point number towards zero (discarding any
849    /// fractional part) and then attempts to convert the result to a `usize`. The conversion
850    /// is fallible and returns a detailed error if the value cannot be represented as a `usize`.
851    ///
852    /// ## Behavior
853    ///
854    /// 1. **Truncation**: The fractional part is discarded, moving the value towards zero:
855    ///    - `3.7` becomes `3`
856    ///    - `-2.9` becomes `-2`
857    ///    - `0.9` becomes `0`
858    ///
859    /// 2. **Conversion**: The truncated integer is then converted to `usize`:
860    ///    - Must be non-negative (≥ 0)
861    ///    - Must not exceed `usize::MAX`
862    ///    - Must be finite (not NaN or infinity)
863    ///
864    /// ## Return Value
865    ///
866    /// - **`Ok(usize)`**: If the truncated value is within the valid range of `usize`
867    ///   (i.e., `0 ≤ truncated_value ≤ usize::MAX`).
868    /// - **`Err(ErrorsRawRealToInteger)`**: If the conversion fails, with specific error variants:
869    ///   - [`NotFinite`](ErrorsRawRealToInteger::NotFinite): The original value is `NaN` or `±∞`
870    ///   - [`OutOfRange`](ErrorsRawRealToInteger::OutOfRange): The truncated value is negative or exceeds `usize::MAX`
871    ///
872    /// ## Use Cases
873    ///
874    /// This method is particularly useful for:
875    /// - Converting floating-point indices to array indices
876    /// - Converting floating-point sizes to collection capacities
877    /// - Interfacing with APIs that require `usize` parameters
878    /// - Safe downcasting from floating-point calculations to integer contexts
879    ///
880    /// ## Examples
881    ///
882    /// ### Successful Conversions
883    ///
884    /// ```rust
885    /// use num_valid::{RealNative64StrictFinite, RealScalar};
886    /// use try_create::TryNew;
887    ///
888    /// // Positive values with fractional parts
889    /// let value = RealNative64StrictFinite::try_new(42.9).unwrap();
890    /// assert_eq!(value.truncate_to_usize().unwrap(), 42);
891    ///
892    /// // Zero
893    /// let zero = RealNative64StrictFinite::try_new(0.0).unwrap();
894    /// assert_eq!(zero.truncate_to_usize().unwrap(), 0);
895    ///
896    /// // Large but valid values
897    /// let large = RealNative64StrictFinite::try_new(1_000_000.7).unwrap();
898    /// assert_eq!(large.truncate_to_usize().unwrap(), 1_000_000);
899    ///
900    /// // Positive fractional values less than 1
901    /// let small = RealNative64StrictFinite::try_new(0.9).unwrap();
902    /// assert_eq!(small.truncate_to_usize().unwrap(), 0);
903    /// ```
904    ///
905    /// ### Error Cases
906    ///
907    /// ```rust
908    /// use num_valid::{RealNative64StrictFinite, RealScalar, validation::ErrorsRawRealToInteger};
909    /// use try_create::TryNew;
910    ///
911    /// // Negative values are not valid for usize
912    /// let negative = RealNative64StrictFinite::try_new(-10.5).unwrap();
913    /// let result = negative.truncate_to_usize();
914    /// assert!(matches!(result, Err(ErrorsRawRealToInteger::OutOfRange { .. })));
915    ///
916    /// // Values that are too large for usize
917    /// let too_large = RealNative64StrictFinite::try_new(1e20).unwrap();
918    /// let result = too_large.truncate_to_usize();
919    /// assert!(matches!(result, Err(ErrorsRawRealToInteger::OutOfRange { .. })));
920    /// ```
921    ///
922    /// ### Practical Usage Example
923    ///
924    /// ```rust
925    /// use num_valid::{RealNative64StrictFinite, RealScalar};
926    /// use try_create::TryNew;
927    ///
928    /// fn create_vector_with_calculated_size<T: Default + Clone>(
929    ///     size_float: RealNative64StrictFinite
930    /// ) -> Result<Vec<T>, Box<dyn std::error::Error>> {
931    ///     // Safely convert the floating-point size to usize
932    ///     let size = size_float.truncate_to_usize()?;
933    ///     
934    ///     // Create vector with the calculated size
935    ///     Ok(vec![T::default(); size])
936    /// }
937    ///
938    /// // Usage
939    /// let calculated_size = RealNative64StrictFinite::try_new(10.7).unwrap();
940    /// let vec: Vec<i32> = create_vector_with_calculated_size(calculated_size).unwrap();
941    /// assert_eq!(vec.len(), 10); // Truncated from 10.7
942    /// ```
943    ///
944    /// ## Comparison with Other Conversion Methods
945    ///
946    /// | Method | Behavior | Range Check | Fractional Handling |
947    /// |--------|----------|-------------|-------------------|
948    /// | `truncate_to_usize()` | Towards zero | ✓ | Discarded |
949    /// | `as usize` (raw cast) | Undefined for out-of-range | ✗ | Undefined |
950    /// | `round().as usize` | Nearest integer | ✗ | Rounded |
951    /// | `floor().as usize` | Towards -∞ | ✗ | Discarded |
952    /// | `ceil().as usize` | Towards +∞ | ✗ | Discarded |
953    ///
954    /// ## Performance Notes
955    ///
956    /// - This method is optimized for safety over performance
957    /// - The finite check is performed first, avoiding unnecessary conversions for invalid inputs
958    /// - For performance-critical code where inputs are guaranteed to be valid, consider using
959    ///   unchecked casting methods (but only after careful validation)
960    ///
961    /// ## Backend-Specific Behavior
962    ///
963    /// ### Native `f64` Backend
964    /// - Uses `az::CheckedAs` for safe conversion with overflow detection
965    /// - Leverages hardware floating-point classification
966    /// - Direct delegation to standard library truncation
967    ///
968    /// ### Arbitrary-Precision (`rug`) Backend
969    /// - Conversion respects the current precision setting
970    /// - May involve internal precision adjustments for very large numbers
971    /// - Exact integer detection when possible
972    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<Self::RawReal, usize>> {
973        let raw: Self::RawReal = self.into_inner();
974        raw.truncate_to_usize()
975    }
976}
977
978/// # Trait for complex scalar numbers
979///
980/// [`ComplexScalar`] is a specialized trait for complex number types that extends the
981/// core [`FpScalar`] functionality with complex-specific operations. It provides a
982/// unified interface for working with complex numbers across different validation
983/// policies and underlying representations.
984///
985/// ## Design Philosophy
986///
987/// This trait bridges the gap between raw complex number operations and the validated
988/// complex number types in [`num-valid`](crate). It ensures that complex-specific
989/// operations like conjugation, argument calculation, and real-number scaling are
990/// available in a type-safe, validated context.
991///
992/// ## Core Capabilities
993///
994/// The trait provides several key features:
995///
996/// - **Component manipulation**: Through [`ComplexScalarMutateParts`], allowing safe
997///   modification of real and imaginary parts
998/// - **Conjugation**: Via the [`functions::Conjugate`] trait for computing complex conjugates
999/// - **Argument calculation**: Through [`functions::Arg`] for computing the phase angle
1000/// - **Real scaling**: Multiplication and assignment with real numbers
1001/// - **Power operations**: Raising complex numbers to real exponents
1002/// - **Convenience methods**: Like [`scale`](Self::scale) and [`scale_mut`](Self::scale_mut)
1003///   for efficient real-number scaling
1004///
1005/// ## Type Relationships
1006///
1007/// Types implementing [`ComplexScalar`] must also implement [`FpScalar`] with
1008/// `Kind = scalar_kind::Complex`, establishing them as complex number types within
1009/// the [`num-valid`](crate) type system.
1010///
1011/// ## Usage Examples
1012///
1013/// ### Basic Complex Operations
1014/// ```rust
1015/// use num_valid::{ComplexNative64StrictFinite, RealNative64StrictFinite, ComplexScalar};
1016/// use num::Complex;
1017/// use try_create::TryNew;
1018///
1019/// let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
1020/// let factor = RealNative64StrictFinite::try_new(2.5).unwrap();
1021///
1022/// // Scale by a real number
1023/// let scaled = z.scale(&factor);
1024/// // Result: (7.5, 10.0)
1025/// ```
1026///
1027/// ### In-place Operations
1028/// ```rust
1029/// use num_valid::{ComplexNative64StrictFinite, RealNative64StrictFinite, ComplexScalar};
1030/// use num::Complex;
1031/// use try_create::TryNew;
1032///
1033/// let mut z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
1034/// let factor = RealNative64StrictFinite::try_new(3.0).unwrap();
1035///
1036/// z.scale_mut(&factor);
1037/// // z is now (3.0, 6.0)
1038/// ```
1039///
1040/// ## See Also
1041///
1042/// - [`FpScalar`]: The base trait for all floating-point scalars
1043/// - [`RealScalar`]: The equivalent trait for real numbers
1044/// - [`ComplexScalarMutateParts`]: For component-wise operations
1045/// - [`functions`]: Module containing mathematical functions for complex numbers
1046pub trait ComplexScalar:
1047    ComplexScalarMutateParts
1048    + Conjugate
1049    + Arg<Output = Self::RealType>
1050    + for<'a> Mul<&'a Self::RealType, Output = Self>
1051    + for<'a> MulAssign<&'a Self::RealType>
1052    + for<'a> Pow<&'a Self::RealType, Error = PowComplexBaseRealExponentErrors<Self::RawComplex>>
1053{
1054    /// Scale the complex number `self` by the real coefficient `c`.
1055    ///
1056    /// This is equivalent to complex multiplication by a real number,
1057    /// scaling both the real and imaginary parts by the same factor.
1058    ///
1059    /// ## Examples
1060    ///
1061    /// ```rust
1062    /// use num_valid::{ComplexNative64StrictFinite, RealNative64StrictFinite, ComplexScalar};
1063    /// use num::Complex;
1064    /// use try_create::TryNew;
1065    ///
1066    /// let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
1067    /// let factor = RealNative64StrictFinite::try_new(2.0).unwrap();
1068    ///
1069    /// let scaled = z.scale(&factor);
1070    /// // Result: (6.0, 8.0)
1071    /// ```
1072    #[inline(always)]
1073    fn scale(self, c: &Self::RealType) -> Self {
1074        self * c
1075    }
1076
1077    /// Scale (in-place) the complex number `self` by the real coefficient `c`.
1078    ///
1079    /// This modifies the complex number in place, scaling both components
1080    /// by the real factor.
1081    ///
1082    /// ## Examples
1083    ///
1084    /// ```rust
1085    /// use num_valid::{ComplexNative64StrictFinite, RealNative64StrictFinite, ComplexScalar};
1086    /// use num::Complex;
1087    /// use try_create::TryNew;
1088    ///
1089    /// let mut z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
1090    /// let factor = RealNative64StrictFinite::try_new(2.0).unwrap();
1091    ///
1092    /// z.scale_mut(&factor);
1093    /// // z is now (6.0, 8.0)
1094    /// ```
1095    #[inline(always)]
1096    fn scale_mut(&mut self, c: &Self::RealType) {
1097        *self *= c;
1098    }
1099
1100    /// Consumes the complex number and returns its real and imaginary parts as a tuple.
1101    ///
1102    /// This method moves ownership of the complex number and extracts its two components,
1103    /// returning them as separate real scalar values. This is useful when you need to
1104    /// work with the components independently and no longer need the original complex value.
1105    ///
1106    /// # Returns
1107    ///
1108    /// A tuple `(real, imaginary)` where:
1109    /// - `real` is the real part of the complex number
1110    /// - `imaginary` is the imaginary part of the complex number
1111    ///
1112    /// # Examples
1113    ///
1114    /// ```rust
1115    /// use num_valid::{ComplexNative64StrictFinite, ComplexScalar};
1116    /// use num::Complex;
1117    /// use try_create::TryNew;
1118    ///
1119    /// let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
1120    ///
1121    /// // Consume z and extract its parts
1122    /// let (real, imag) = z.into_parts();
1123    ///
1124    /// assert_eq!(*real.as_ref(), 3.0);
1125    /// assert_eq!(*imag.as_ref(), 4.0);
1126    /// // z is no longer available here (moved)
1127    /// ```
1128    ///
1129    /// # See Also
1130    ///
1131    /// - [`ComplexScalarGetParts::real_part`]: Get the real part without consuming
1132    /// - [`ComplexScalarGetParts::imag_part`]: Get the imaginary part without consuming
1133    fn into_parts(self) -> (Self::RealType, Self::RealType);
1134}
1135
1136//------------------------------------------------------------------------------------------------------------
1137
1138//------------------------------------------------------------------------------------------------------------
1139/// Attempts to convert a vector of [`f64`] values into a vector of the specified real scalar type.
1140///
1141/// This function provides a fallible conversion that validates each input value according
1142/// to the target type's validation policy. If any value fails validation, the entire
1143/// operation fails and returns an error.
1144///
1145/// ## Parameters
1146///
1147/// * `vec`: A vector of [`f64`] values to convert
1148///
1149/// ## Return Value
1150///
1151/// * `Ok(Vec<RealType>)`: If all values can be successfully converted and validated
1152/// * `Err(ErrorsTryFromf64)`: If any value fails validation, containing details about the failure
1153///
1154/// ## Usage Examples
1155///
1156/// ### Successful Conversion
1157/// ```rust
1158/// use num_valid::{try_vec_f64_into_vec_real, RealNative64StrictFinite};
1159///
1160/// let input = vec![1.0, -2.5, 3.14159];
1161/// let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
1162/// assert!(result.is_ok());
1163///
1164/// let validated_vec = result.unwrap();
1165/// assert_eq!(validated_vec.len(), 3);
1166/// assert_eq!(*validated_vec[0].as_ref(), 1.0);
1167/// ```
1168///
1169/// ### Failed Conversion
1170/// ```rust
1171/// use num_valid::{try_vec_f64_into_vec_real, RealNative64StrictFinite};
1172///
1173/// let input = vec![1.0, f64::NAN, 3.0]; // Contains NaN
1174/// let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
1175/// assert!(result.is_err()); // Fails due to NaN value
1176/// ```
1177#[inline(always)]
1178pub fn try_vec_f64_into_vec_real<RealType: RealScalar>(
1179    vec: Vec<f64>,
1180) -> Result<Vec<RealType>, ErrorsTryFromf64<RealType::RawReal>> {
1181    vec.into_iter().map(|v| RealType::try_from_f64(v)).collect()
1182}
1183
1184/// Converts a vector of [`f64`] values into a vector of the specified real scalar type.
1185///
1186/// This is the panicking version of [`try_vec_f64_into_vec_real`]. It converts each
1187/// [`f64`] value to the target real scalar type, panicking if any conversion fails.
1188/// Use this function only when you are certain that all input values are valid for
1189/// the target type.
1190///
1191/// ## Parameters
1192///
1193/// * `vec`: A vector of [`f64`] values to convert
1194///
1195/// ## Return Value
1196///
1197/// A vector of validated real scalar values of type `RealType`.
1198///
1199/// ## Panics
1200///
1201/// Panics if any value in the input vector cannot be converted to `RealType`.
1202/// This can happen for various reasons:
1203/// - Input contains `NaN` or infinite values when using strict finite validation
1204/// - Precision loss when converting to arbitrary-precision types
1205/// - Values outside the representable range of the target type
1206///
1207/// ## Usage Examples
1208///
1209/// ### Successful Conversion
1210/// ```rust
1211/// use num_valid::{vec_f64_into_vec_real, RealNative64StrictFinite};
1212///
1213/// let input = vec![0.0, 1.0, -2.5, 3.14159];
1214/// let validated_vec: Vec<RealNative64StrictFinite> = vec_f64_into_vec_real(input);
1215///
1216/// assert_eq!(validated_vec.len(), 4);
1217/// assert_eq!(*validated_vec[0].as_ref(), 0.0);
1218/// assert_eq!(*validated_vec[1].as_ref(), 1.0);
1219/// ```
1220///
1221/// ## When to Use
1222///
1223/// - **Use this function when**: You are certain all input values are valid for the target type
1224/// - **Use [`try_vec_f64_into_vec_real`] when**: Input validation is uncertain and you want to handle errors gracefully
1225#[inline(always)]
1226pub fn vec_f64_into_vec_real<RealType: RealScalar>(vec: Vec<f64>) -> Vec<RealType> {
1227    try_vec_f64_into_vec_real(vec).expect(
1228        "The conversion from f64 to RealType failed, which should not happen in a well-defined numerical kernel."
1229    )
1230}
1231//------------------------------------------------------------------------------------------------------------
1232
1233//------------------------------------------------------------------------------------------------------------
1234/// A trait for types that can be randomly generated from a distribution over `f64`.
1235///
1236/// This trait provides a universal dispatch mechanism for generating random scalar values,
1237/// allowing a single generic API to work for primitive types like [`f64`] and
1238/// [`Complex<f64>`], as well as custom validated types like [`RealValidated`] and
1239/// [`ComplexValidated`].
1240///
1241/// ## Purpose
1242///
1243/// The primary goal of [`RandomSampleFromF64`] is to abstract the process of creating a random
1244/// scalar. Many random number distributions in the [`rand`] crate are defined to produce
1245/// primitive types like `f64`. This trait acts as a bridge, allowing those same
1246/// distributions to be used to generate more complex or validated types.
1247///
1248/// ## How It Works
1249///
1250/// The trait defines a single required method, [`RandomSampleFromF64::sample_from()`], which takes a reference
1251/// to any distribution that implements [`rand::distr::Distribution<f64>`] and a
1252/// random number generator (RNG). Each implementing type provides its own logic for
1253/// this method:
1254///
1255/// - For `f64`, it simply samples directly from the distribution.
1256/// - For `Complex<f64>`, it samples twice to create the real and imaginary parts.
1257/// - For [`RealValidated<K>`], it samples an `f64` and then passes it through the
1258///   validation and conversion logic of [`RealValidated::try_from_f64`].
1259/// - For [`ComplexValidated<K>`], it reuses the logic for `RealValidated<K>` to sample
1260///   the real and imaginary components.
1261///
1262/// ## Example
1263///
1264/// Here is how you can write a generic function that creates a vector of random numbers
1265/// for any type that implements [`RandomSampleFromF64`].
1266///
1267/// ```rust
1268/// use num_valid::{RealNative64StrictFinite, RealScalar, new_random_vec};
1269/// use rand::{distr::Uniform, rngs::StdRng, Rng, SeedableRng};
1270/// use try_create::IntoInner;
1271///
1272/// let seed = [42; 32]; // Example seed for reproducibility
1273/// let mut rng = StdRng::from_seed(seed);
1274/// let uniform = Uniform::new(-10.0, 10.0).unwrap();
1275///
1276/// // Create a vector of random f64 values.
1277/// let f64_vec: Vec<f64> = new_random_vec(3, &uniform, &mut rng);
1278/// assert_eq!(f64_vec.len(), 3);
1279///
1280/// // Create a vector of random validated real numbers using the same function.
1281/// // Reset RNG to get same sequence
1282/// let mut rng = StdRng::from_seed(seed);
1283/// let validated_vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &uniform, &mut rng);
1284/// assert_eq!(validated_vec.len(), 3);
1285///
1286/// // The underlying numerical values should be identical because the RNG was seeded the same.
1287/// assert_eq!(&f64_vec[0], validated_vec[0].as_ref());
1288/// assert_eq!(&f64_vec[1], validated_vec[1].as_ref());
1289/// assert_eq!(&f64_vec[2], validated_vec[2].as_ref());
1290/// ```
1291pub trait RandomSampleFromF64: Sized + Clone {
1292    /// Samples a single value of `Self` using the given `f64` distribution.
1293    fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1294    where
1295        D: Distribution<f64>,
1296        R: Rng + ?Sized;
1297
1298    fn sample_iter_from<D, R>(dist: &D, rng: &mut R, n: usize) -> impl Iterator<Item = Self>
1299    where
1300        D: Distribution<f64>,
1301        R: Rng + ?Sized,
1302    {
1303        // Create an iterator that samples `n` values from the distribution.
1304        (0..n).map(move |_| Self::sample_from(dist, rng))
1305    }
1306}
1307
1308impl RandomSampleFromF64 for f64 {
1309    #[inline]
1310    fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1311    where
1312        D: Distribution<f64>,
1313        R: Rng + ?Sized,
1314    {
1315        // Straightforward implementation: sample a f64.
1316        dist.sample(rng)
1317    }
1318}
1319impl RandomSampleFromF64 for Complex<f64> {
1320    #[inline]
1321    fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1322    where
1323        D: Distribution<f64>,
1324        R: Rng + ?Sized,
1325    {
1326        // Sample two f64 for the real and imaginary parts.
1327        let re = dist.sample(rng);
1328        let im = dist.sample(rng);
1329        Complex::new(re, im)
1330    }
1331}
1332
1333impl<K> RandomSampleFromF64 for RealValidated<K>
1334where
1335    K: NumKernel,
1336{
1337    #[inline]
1338    fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1339    where
1340        D: Distribution<f64>,
1341        R: Rng + ?Sized,
1342    {
1343        loop {
1344            // Sample a f64 and then convert/validate it.
1345            // The loop ensures that a valid value is returned
1346            let value_f64 = dist.sample(rng);
1347            let value = RealValidated::try_from_f64(value_f64);
1348            if let Ok(validated_value) = value {
1349                return validated_value;
1350            }
1351        }
1352    }
1353}
1354
1355impl<K> RandomSampleFromF64 for ComplexValidated<K>
1356where
1357    K: NumKernel,
1358{
1359    #[inline]
1360    fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1361    where
1362        D: Distribution<f64>,
1363        R: Rng + ?Sized,
1364    {
1365        // Reuse the RealValidated sampling logic for both parts.
1366        let re = RealValidated::<K>::sample_from(dist, rng);
1367        let im = RealValidated::<K>::sample_from(dist, rng);
1368        ComplexValidated::new_complex(re, im)
1369    }
1370}
1371
1372//------------------------------------------------------------------------------------------------------------
1373
1374//------------------------------------------------------------------------------------------------------------
1375/// Generates a `Vec<T>` of a specified length with random values.
1376///
1377/// This function leverages the [`RandomSampleFromF64`] trait to provide a universal way
1378/// to create a vector of random numbers for any supported scalar type, including
1379/// primitive types like `f64` and `Complex<f64>`, as well as validated types
1380/// like [`RealValidated`] and [`ComplexValidated`].
1381///
1382/// # Parameters
1383///
1384/// * `n`: The number of random values to generate in the vector.
1385/// * `distribution`: A reference to any distribution from the `rand` crate that
1386///   implements `Distribution<f64>` (e.g., `Uniform`, `StandardNormal`).
1387/// * `rng`: A mutable reference to a random number generator that implements `Rng`.
1388///
1389/// # Type Parameters
1390///
1391/// * `T`: The scalar type of the elements in the returned vector. Must implement [`RandomSampleFromF64`].
1392/// * `D`: The type of the distribution.
1393/// * `R`: The type of the random number generator.
1394///
1395/// # Example
1396///
1397/// # Example
1398///
1399/// ```rust
1400/// use num_valid::{new_random_vec, RealNative64StrictFinite};
1401/// use rand::{distr::Uniform, rngs::StdRng, SeedableRng};
1402/// use try_create::IntoInner;
1403///
1404/// let seed = [42; 32]; // Use a fixed seed for a reproducible example
1405///
1406/// // Generate a vector of random f64 values.
1407/// let mut rng_f64 = StdRng::from_seed(seed);
1408/// let uniform = Uniform::new(-10.0, 10.0).unwrap();
1409/// let f64_vec: Vec<f64> = new_random_vec(3, &uniform, &mut rng_f64);
1410///
1411/// // Generate a vector of random validated real numbers using the same seed.
1412/// let mut rng_validated = StdRng::from_seed(seed);
1413/// let validated_vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &uniform, &mut rng_validated);
1414///
1415/// assert_eq!(f64_vec.len(), 3);
1416/// assert_eq!(validated_vec.len(), 3);
1417///
1418/// // The underlying numerical values should be identical because the RNG was seeded the same.
1419/// assert_eq!(&f64_vec[0], validated_vec[0].as_ref());
1420/// assert_eq!(&f64_vec[1], validated_vec[1].as_ref());
1421/// assert_eq!(&f64_vec[2], validated_vec[2].as_ref());
1422/// ```
1423pub fn new_random_vec<T, D, R>(n: usize, distribution: &D, rng: &mut R) -> Vec<T>
1424where
1425    T: RandomSampleFromF64,
1426    D: Distribution<f64>,
1427    R: Rng + ?Sized,
1428{
1429    T::sample_iter_from(distribution, rng, n).collect()
1430}
1431//------------------------------------------------------------------------------------------------------------
1432
1433//------------------------------------------------------------------------------------------------------------
1434#[cfg(test)]
1435mod tests {
1436    use super::*;
1437    use num::Complex;
1438    use num_traits::MulAddAssign;
1439    use std::ops::{Add, Div, Sub};
1440
1441    mod functions_general_type {
1442        use super::*;
1443
1444        fn test_recip<RealType: RealScalar>() {
1445            let a = RealType::two();
1446
1447            let a = a.try_reciprocal().unwrap();
1448            let expected = RealType::one_div_2();
1449            assert_eq!(a, expected);
1450        }
1451
1452        fn test_zero<RealType: RealScalar>() {
1453            let a = RealType::zero();
1454
1455            assert_eq!(a, 0.0);
1456        }
1457
1458        fn test_one<RealType: RealScalar>() {
1459            let a = RealType::one();
1460
1461            assert_eq!(a, 1.0);
1462        }
1463
1464        fn test_add<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1465        where
1466            for<'a> &'a ScalarType:
1467                Add<ScalarType, Output = ScalarType> + Add<&'a ScalarType, Output = ScalarType>,
1468        {
1469            let c = a.clone() + &b;
1470            assert_eq!(c, c_expected);
1471
1472            let c = &a + b.clone();
1473            assert_eq!(c, c_expected);
1474
1475            let c = a.clone() + b.clone();
1476            assert_eq!(c, c_expected);
1477
1478            let c = &a + &b;
1479            assert_eq!(c, c_expected);
1480        }
1481
1482        fn test_sub<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1483        where
1484            for<'a> &'a ScalarType:
1485                Sub<ScalarType, Output = ScalarType> + Sub<&'a ScalarType, Output = ScalarType>,
1486        {
1487            let c = a.clone() - &b;
1488            assert_eq!(c, c_expected);
1489
1490            let c = &a - b.clone();
1491            assert_eq!(c, c_expected);
1492
1493            let c = a.clone() - b.clone();
1494            assert_eq!(c, c_expected);
1495
1496            let c = &a - &b;
1497            assert_eq!(c, c_expected);
1498        }
1499
1500        fn test_mul<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1501        where
1502            for<'a> &'a ScalarType:
1503                Mul<ScalarType, Output = ScalarType> + Mul<&'a ScalarType, Output = ScalarType>,
1504        {
1505            let c = a.clone() * &b;
1506            assert_eq!(c, c_expected);
1507
1508            let c = &a * b.clone();
1509            assert_eq!(c, c_expected);
1510
1511            let c = a.clone() * b.clone();
1512            assert_eq!(c, c_expected);
1513
1514            let c = &a * &b;
1515            assert_eq!(c, c_expected);
1516        }
1517
1518        fn test_div<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1519        where
1520            for<'a> &'a ScalarType:
1521                Div<ScalarType, Output = ScalarType> + Div<&'a ScalarType, Output = ScalarType>,
1522        {
1523            let c = a.clone() / &b;
1524            assert_eq!(c, c_expected);
1525
1526            let c = &a / b.clone();
1527            assert_eq!(c, c_expected);
1528
1529            let c = a.clone() / b.clone();
1530            assert_eq!(c, c_expected);
1531
1532            let c = &a / &b;
1533            assert_eq!(c, c_expected);
1534        }
1535
1536        fn test_mul_complex_with_real<ComplexType: ComplexScalar>(
1537            a: ComplexType,
1538            b: ComplexType::RealType,
1539            a_times_b_expected: ComplexType,
1540        ) {
1541            let a_times_b = a.clone().scale(&b);
1542            assert_eq!(a_times_b, a_times_b_expected);
1543
1544            let a_times_b = a.clone() * &b;
1545            assert_eq!(a_times_b, a_times_b_expected);
1546
1547            /*
1548            let b_times_a_expected = a_times_b_expected.clone();
1549
1550            let b_times_a = &b * a.clone();
1551            assert_eq!(b_times_a, b_times_a_expected);
1552
1553            let b_times_a = b.clone() * a.clone();
1554            assert_eq!(b_times_a, b_times_a_expected);
1555            */
1556        }
1557
1558        fn test_mul_assign_complex_with_real<ComplexType: ComplexScalar>(
1559            a: ComplexType,
1560            b: ComplexType::RealType,
1561            a_times_b_expected: ComplexType,
1562        ) {
1563            let mut a_times_b = a.clone();
1564            a_times_b.scale_mut(&b);
1565            assert_eq!(a_times_b, a_times_b_expected);
1566
1567            //        let mut a_times_b = a.clone();
1568            //        a_times_b *= b;
1569            //        assert_eq!(a_times_b, a_times_b_expected);
1570        }
1571
1572        fn test_neg_assign_real<RealType: RealScalar>() {
1573            let mut a = RealType::one();
1574            a.neg_assign();
1575
1576            let a_expected = RealType::try_from_f64(-1.).unwrap();
1577            assert_eq!(a, a_expected);
1578        }
1579
1580        fn test_add_assign_real<RealType: RealScalar>() {
1581            let mut a = RealType::try_from_f64(1.0).unwrap();
1582            let b = RealType::try_from_f64(2.0).unwrap();
1583
1584            a += &b;
1585            let a_expected = RealType::try_from_f64(3.0).unwrap();
1586            assert_eq!(a, a_expected);
1587
1588            a += b;
1589            let a_expected = RealType::try_from_f64(5.0).unwrap();
1590            assert_eq!(a, a_expected);
1591        }
1592
1593        fn test_sub_assign_real<RealType: RealScalar>() {
1594            let mut a = RealType::try_from_f64(1.0).unwrap();
1595            let b = RealType::try_from_f64(2.0).unwrap();
1596
1597            a -= &b;
1598            let a_expected = RealType::try_from_f64(-1.0).unwrap();
1599            assert_eq!(a, a_expected);
1600
1601            a -= b;
1602            let a_expected = RealType::try_from_f64(-3.0).unwrap();
1603            assert_eq!(a, a_expected);
1604        }
1605
1606        fn test_mul_assign_real<RealType: RealScalar>() {
1607            let mut a = RealType::try_from_f64(1.0).unwrap();
1608            let b = RealType::try_from_f64(2.0).unwrap();
1609
1610            a *= &b;
1611            let a_expected = RealType::try_from_f64(2.0).unwrap();
1612            assert_eq!(a, a_expected);
1613
1614            a *= b;
1615            let a_expected = RealType::try_from_f64(4.0).unwrap();
1616            assert_eq!(a, a_expected);
1617        }
1618
1619        fn test_div_assign_real<RealType: RealScalar>() {
1620            let mut a = RealType::try_from_f64(4.0).unwrap();
1621            let b = RealType::try_from_f64(2.0).unwrap();
1622
1623            a /= &b;
1624            let a_expected = RealType::try_from_f64(2.0).unwrap();
1625            assert_eq!(a, a_expected);
1626
1627            a /= b;
1628            let a_expected = RealType::try_from_f64(1.0).unwrap();
1629            assert_eq!(a, a_expected);
1630        }
1631
1632        fn test_mul_add_ref_real<RealType: RealScalar>() {
1633            let a = RealType::try_from_f64(2.0).unwrap();
1634            let b = RealType::try_from_f64(3.0).unwrap();
1635            let c = RealType::try_from_f64(1.0).unwrap();
1636
1637            let d_expected = RealType::try_from_f64(7.0).unwrap();
1638
1639            let d = a.mul_add_ref(&b, &c);
1640            assert_eq!(d, d_expected);
1641        }
1642
1643        fn test_sin_real<RealType: RealScalar>() {
1644            let a = RealType::zero();
1645
1646            let a = a.sin();
1647            let expected = RealType::zero();
1648            assert_eq!(a, expected);
1649        }
1650
1651        fn test_cos_real<RealType: RealScalar>() {
1652            let a = RealType::zero();
1653
1654            let a = a.cos();
1655            let expected = RealType::one();
1656            assert_eq!(a, expected);
1657        }
1658
1659        fn test_abs_real<RealType: RealScalar>() {
1660            let a = RealType::try_from_f64(-1.).unwrap();
1661
1662            let abs: RealType = a.abs();
1663            let expected = RealType::one();
1664            assert_eq!(abs, expected);
1665        }
1666
1667        mod native64 {
1668            use super::*;
1669
1670            mod real {
1671                use super::*;
1672
1673                #[test]
1674                fn zero() {
1675                    test_zero::<f64>();
1676                }
1677
1678                #[test]
1679                fn one() {
1680                    test_one::<f64>();
1681                }
1682
1683                #[test]
1684                fn recip() {
1685                    test_recip::<f64>();
1686                }
1687
1688                #[test]
1689                fn add() {
1690                    let a = 1.0;
1691                    let b = 2.0;
1692                    let c_expected = 3.0;
1693                    test_add(a, b, c_expected);
1694                }
1695
1696                #[test]
1697                fn sub() {
1698                    let a = 1.0;
1699                    let b = 2.0;
1700                    let c_expected = -1.0;
1701                    test_sub(a, b, c_expected);
1702                }
1703
1704                #[test]
1705                fn mul() {
1706                    let a = 2.0;
1707                    let b = 3.0;
1708                    let c_expected = 6.0;
1709                    test_mul(a, b, c_expected);
1710                }
1711
1712                #[test]
1713                fn div() {
1714                    let a = 6.;
1715                    let b = 2.;
1716                    let c_expected = 3.;
1717                    test_div(a, b, c_expected);
1718                }
1719
1720                #[test]
1721                fn neg_assign() {
1722                    test_neg_assign_real::<f64>();
1723                }
1724
1725                #[test]
1726                fn add_assign() {
1727                    test_add_assign_real::<f64>();
1728                }
1729
1730                #[test]
1731                fn sub_assign() {
1732                    test_sub_assign_real::<f64>();
1733                }
1734
1735                #[test]
1736                fn mul_assign() {
1737                    test_mul_assign_real::<f64>();
1738                }
1739
1740                #[test]
1741                fn div_assign() {
1742                    test_div_assign_real::<f64>();
1743                }
1744                #[test]
1745                fn mul_add_ref() {
1746                    test_mul_add_ref_real::<f64>();
1747                }
1748
1749                #[test]
1750                fn from_f64() {
1751                    let v_native64 = f64::try_from_f64(16.25).unwrap();
1752                    assert_eq!(v_native64, 16.25);
1753                }
1754
1755                #[test]
1756                fn abs() {
1757                    test_abs_real::<f64>();
1758                }
1759
1760                #[test]
1761                fn acos() {
1762                    let a = 0.;
1763
1764                    let pi_over_2 = a.acos();
1765                    let expected = std::f64::consts::FRAC_PI_2;
1766                    assert_eq!(pi_over_2, expected);
1767                }
1768
1769                #[test]
1770                fn asin() {
1771                    let a = 1.;
1772
1773                    let pi_over_2 = a.asin();
1774                    let expected = std::f64::consts::FRAC_PI_2;
1775                    assert_eq!(pi_over_2, expected);
1776                }
1777
1778                #[test]
1779                fn cos() {
1780                    test_cos_real::<f64>();
1781                }
1782
1783                #[test]
1784                fn sin() {
1785                    test_sin_real::<f64>();
1786                }
1787
1788                #[test]
1789                fn test_acos() {
1790                    let value: f64 = 0.5;
1791                    let result = value.acos();
1792                    assert_eq!(result, value.acos());
1793                }
1794
1795                #[test]
1796                fn test_acosh() {
1797                    let value: f64 = 1.5;
1798                    let result = value.acosh();
1799                    assert_eq!(result, value.acosh());
1800                }
1801
1802                #[test]
1803                fn test_asin() {
1804                    let value: f64 = 0.5;
1805                    let result = value.asin();
1806                    assert_eq!(result, value.asin());
1807                }
1808
1809                #[test]
1810                fn test_asinh() {
1811                    let value: f64 = 0.5;
1812                    let result = value.asinh();
1813                    assert_eq!(result, value.asinh());
1814                }
1815
1816                #[test]
1817                fn test_atan() {
1818                    let value: f64 = 0.5;
1819                    let result = value.atan();
1820                    assert_eq!(result, value.atan());
1821                }
1822
1823                #[test]
1824                fn test_atanh() {
1825                    let value: f64 = 0.5;
1826                    let result = value.atanh();
1827                    assert_eq!(result, value.atanh());
1828                }
1829
1830                #[test]
1831                fn test_cos_02() {
1832                    let value: f64 = 0.5;
1833                    let result = value.cos();
1834                    assert_eq!(result, value.cos());
1835                }
1836
1837                #[test]
1838                fn test_cosh() {
1839                    let value: f64 = 0.5;
1840                    let result = value.cosh();
1841                    assert_eq!(result, value.cosh());
1842                }
1843
1844                #[test]
1845                fn test_exp() {
1846                    let value: f64 = 0.5;
1847                    let result = value.exp();
1848                    println!("result = {result:?}");
1849
1850                    assert_eq!(result, value.exp());
1851                }
1852
1853                #[test]
1854                fn test_is_finite() {
1855                    let value: f64 = 0.5;
1856                    assert!(value.is_finite());
1857
1858                    let value: f64 = f64::INFINITY;
1859                    assert!(!value.is_finite());
1860                }
1861
1862                #[test]
1863                fn test_is_infinite() {
1864                    let value: f64 = f64::INFINITY;
1865                    assert!(value.is_infinite());
1866
1867                    let value: f64 = 0.5;
1868                    assert!(!value.is_infinite());
1869                }
1870
1871                #[test]
1872                fn test_ln() {
1873                    let value: f64 = std::f64::consts::E;
1874                    let result = value.ln();
1875                    println!("result = {result:?}");
1876                    assert_eq!(result, value.ln());
1877                }
1878
1879                #[test]
1880                fn test_log10() {
1881                    let value: f64 = 10.0;
1882                    let result = value.log10();
1883                    println!("result = {result:?}");
1884                    assert_eq!(result, value.log10());
1885                }
1886
1887                #[test]
1888                fn test_log2() {
1889                    let value: f64 = 8.0;
1890                    let result = value.log2();
1891                    println!("result = {result:?}");
1892                    assert_eq!(result, value.log2());
1893                }
1894
1895                #[test]
1896                fn test_recip_02() {
1897                    let value: f64 = 2.0;
1898                    let result = value.try_reciprocal().unwrap();
1899                    assert_eq!(result, value.recip());
1900                }
1901
1902                #[test]
1903                fn test_sin_02() {
1904                    let value: f64 = 0.5;
1905                    let result = value.sin();
1906                    assert_eq!(result, value.sin());
1907                }
1908
1909                #[test]
1910                fn test_sinh() {
1911                    let value: f64 = 0.5;
1912                    let result = value.sinh();
1913                    assert_eq!(result, value.sinh());
1914                }
1915
1916                #[test]
1917                fn sqrt() {
1918                    let value: f64 = 4.0;
1919                    let result = value.sqrt();
1920                    assert_eq!(result, value.sqrt());
1921                }
1922
1923                #[test]
1924                fn try_sqrt() {
1925                    let value: f64 = 4.0;
1926                    let result = value.try_sqrt().unwrap();
1927                    assert_eq!(result, value.sqrt());
1928
1929                    assert!((-1.0).try_sqrt().is_err());
1930                }
1931
1932                #[test]
1933                fn test_tan() {
1934                    let value: f64 = 0.5;
1935                    let result = value.tan();
1936                    assert_eq!(result, value.tan());
1937                }
1938
1939                #[test]
1940                fn test_tanh() {
1941                    let value: f64 = 0.5;
1942                    let result = value.tanh();
1943                    assert_eq!(result, value.tanh());
1944                }
1945            }
1946
1947            mod complex {
1948                use super::*;
1949
1950                #[test]
1951                fn add() {
1952                    let a = Complex::new(1., 2.);
1953                    let b = Complex::new(3., 4.);
1954
1955                    let c_expected = Complex::new(4., 6.);
1956
1957                    test_add(a, b, c_expected);
1958                }
1959
1960                #[test]
1961                fn sub() {
1962                    let a = Complex::new(3., 2.);
1963                    let b = Complex::new(1., 4.);
1964
1965                    let c_expected = Complex::new(2., -2.);
1966
1967                    test_sub(a, b, c_expected);
1968                }
1969
1970                #[test]
1971                fn mul() {
1972                    let a = Complex::new(3., 2.);
1973                    let b = Complex::new(1., 4.);
1974                    let c_expected = Complex::new(-5., 14.);
1975                    test_mul(a, b, c_expected);
1976                }
1977
1978                #[test]
1979                fn div() {
1980                    let a = Complex::new(-5., 14.);
1981                    let b = Complex::new(1., 4.);
1982
1983                    let c_expected = Complex::new(3., 2.);
1984
1985                    test_div(a, b, c_expected);
1986                }
1987
1988                #[test]
1989                fn add_assign() {
1990                    let mut a = Complex::new(1., 2.);
1991                    let b = Complex::new(3., 4.);
1992
1993                    a += &b;
1994                    let a_expected = Complex::new(4., 6.);
1995                    assert_eq!(a, a_expected);
1996
1997                    a += b;
1998                    let a_expected = Complex::new(7., 10.);
1999                    assert_eq!(a, a_expected);
2000                }
2001
2002                #[test]
2003                fn sub_assign() {
2004                    let mut a = Complex::new(3., 2.);
2005                    let b = Complex::new(2., 4.);
2006
2007                    a -= &b;
2008                    let a_expected = Complex::new(1., -2.);
2009                    assert_eq!(a, a_expected);
2010
2011                    a -= b;
2012                    let a_expected = Complex::new(-1., -6.);
2013                    assert_eq!(a, a_expected);
2014                }
2015
2016                #[test]
2017                fn mul_assign() {
2018                    let mut a = Complex::new(3., 2.);
2019                    let b = Complex::new(2., 4.);
2020
2021                    a *= &b;
2022                    let a_expected = Complex::new(-2., 16.);
2023                    assert_eq!(a, a_expected);
2024
2025                    a *= b;
2026                    let a_expected = Complex::new(-68., 24.);
2027                    assert_eq!(a, a_expected);
2028                }
2029
2030                #[test]
2031                fn div_assign() {
2032                    let mut a = Complex::new(-68., 24.);
2033                    let b = Complex::new(2., 4.);
2034
2035                    a /= &b;
2036                    let a_expected = Complex::new(-2., 16.);
2037                    assert_eq!(a, a_expected);
2038
2039                    a /= b;
2040                    let a_expected = Complex::new(3., 2.);
2041                    assert_eq!(a, a_expected);
2042                }
2043
2044                #[test]
2045                fn from_f64() {
2046                    let v = Complex::new(16.25, 2.);
2047                    assert_eq!(v.real_part(), 16.25);
2048                    assert_eq!(v.imag_part(), 2.);
2049                }
2050
2051                #[test]
2052                fn conj() {
2053                    let v = Complex::new(16.25, 2.);
2054
2055                    let v_conj = v.conjugate();
2056                    assert_eq!(v_conj.real_part(), 16.25);
2057                    assert_eq!(v_conj.imag_part(), -2.);
2058                }
2059
2060                #[test]
2061                fn neg_assign() {
2062                    let mut a = Complex::new(1., 2.);
2063                    a.neg_assign();
2064
2065                    let a_expected = Complex::new(-1., -2.);
2066                    assert_eq!(a, a_expected);
2067                }
2068
2069                #[test]
2070                fn abs() {
2071                    let a = Complex::new(-3., 4.);
2072
2073                    let abs = a.abs();
2074                    let expected = 5.;
2075                    assert_eq!(abs, expected);
2076                }
2077
2078                #[test]
2079                fn mul_add_ref() {
2080                    let a = Complex::new(2., -3.);
2081                    let b = Complex::new(3., 1.);
2082                    let c = Complex::new(1., -4.);
2083
2084                    let d_expected = Complex::new(10., -11.);
2085
2086                    let d = a.mul_add_ref(&b, &c);
2087                    assert_eq!(d, d_expected);
2088                }
2089
2090                #[test]
2091                fn mul_complex_with_real() {
2092                    let a = Complex::new(1., 2.);
2093                    let b = 3.;
2094
2095                    let a_times_b_expected = Complex::new(3., 6.);
2096
2097                    test_mul_complex_with_real(a, b, a_times_b_expected);
2098                }
2099
2100                #[test]
2101                fn mul_assign_complex_with_real() {
2102                    let a = Complex::new(1., 2.);
2103                    let b = 3.;
2104
2105                    let a_times_b_expected = Complex::new(3., 6.);
2106
2107                    test_mul_assign_complex_with_real(a, b, a_times_b_expected);
2108                }
2109
2110                #[test]
2111                fn test_acos() {
2112                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2113                    let result = value.acos();
2114                    assert_eq!(result, value.acos());
2115                }
2116
2117                #[test]
2118                fn test_acosh() {
2119                    let value: Complex<f64> = Complex::new(1.5, 0.5);
2120                    let result = value.acosh();
2121                    assert_eq!(result, value.acosh());
2122                }
2123
2124                #[test]
2125                fn test_asin() {
2126                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2127                    let result = value.asin();
2128                    assert_eq!(result, value.asin());
2129                }
2130
2131                #[test]
2132                fn test_asinh() {
2133                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2134                    let result = value.asinh();
2135                    assert_eq!(result, value.asinh());
2136                }
2137
2138                #[test]
2139                fn test_atan() {
2140                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2141                    let result = value.atan();
2142                    assert_eq!(result, value.atan());
2143                }
2144
2145                #[test]
2146                fn test_atanh() {
2147                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2148                    let result = value.atanh();
2149                    assert_eq!(result, value.atanh());
2150                }
2151
2152                #[test]
2153                fn test_cos_01() {
2154                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2155                    let result = value.cos();
2156                    assert_eq!(result, value.cos());
2157                }
2158
2159                #[test]
2160                fn test_cosh() {
2161                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2162                    let result = value.cosh();
2163                    assert_eq!(result, value.cosh());
2164                }
2165
2166                #[test]
2167                fn test_exp() {
2168                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2169                    let result = value.exp();
2170                    println!("result = {result:?}");
2171                    assert_eq!(result, value.exp());
2172                }
2173
2174                /*
2175                #[test]
2176                fn test_is_finite() {
2177                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2178                    assert!(value.is_finite());
2179
2180                    let value: Complex<f64> = Complex::new(f64::INFINITY, 0.5);
2181                    assert!(!value.is_finite());
2182                }
2183
2184                #[test]
2185                fn test_is_infinite() {
2186                    let value: Complex<f64> = Complex::new(f64::INFINITY, 0.5);
2187                    assert!(value.is_infinite());
2188
2189                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2190                    assert!(!value.is_infinite());
2191                }
2192                */
2193
2194                #[test]
2195                fn test_ln() {
2196                    let value: Complex<f64> = Complex::new(std::f64::consts::E, 1.0);
2197                    let result = value.ln();
2198                    println!("result = {result:?}");
2199                    assert_eq!(result, value.ln());
2200                }
2201
2202                #[test]
2203                fn test_log10() {
2204                    let value: Complex<f64> = Complex::new(10.0, 1.0);
2205                    let result = value.log10();
2206                    println!("result = {result:?}");
2207                    assert_eq!(result, value.log10());
2208                }
2209
2210                #[test]
2211                fn test_log2() {
2212                    let value: Complex<f64> = Complex::new(8.0, 1.0);
2213                    let result = value.log2();
2214                    println!("result = {result:?}");
2215                    assert_eq!(result, value.log2());
2216                }
2217
2218                #[test]
2219                fn test_recip() {
2220                    let value: Complex<f64> = Complex::new(2.0, 0.0);
2221                    let result = value.try_reciprocal().unwrap();
2222                    assert_eq!(result, value.finv());
2223                }
2224
2225                #[test]
2226                fn test_sin_01() {
2227                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2228                    let result = value.sin();
2229                    assert_eq!(result, value.sin());
2230                }
2231
2232                #[test]
2233                fn test_sinh() {
2234                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2235                    let result = value.sinh();
2236                    assert_eq!(result, value.sinh());
2237                }
2238
2239                #[test]
2240                fn sqrt() {
2241                    let value: Complex<f64> = Complex::new(4.0, 1.0);
2242                    let result = value.sqrt();
2243                    assert_eq!(result, value.sqrt());
2244                }
2245
2246                #[test]
2247                fn try_sqrt() {
2248                    let value: Complex<f64> = Complex::new(4.0, 1.0);
2249                    let result = value.try_sqrt().unwrap();
2250                    assert_eq!(result, value.sqrt());
2251                }
2252
2253                #[test]
2254                fn test_tan() {
2255                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2256                    let result = value.tan();
2257                    assert_eq!(result, value.tan());
2258                }
2259
2260                #[test]
2261                fn test_tanh() {
2262                    let value: Complex<f64> = Complex::new(0.5, 0.5);
2263                    let result = value.tanh();
2264                    assert_eq!(result, value.tanh());
2265                }
2266            }
2267        }
2268
2269        #[cfg(feature = "rug")]
2270        mod rug_ {
2271            use super::*;
2272            use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite};
2273            use rug::ops::CompleteRound;
2274            use try_create::{IntoInner, TryNew};
2275
2276            const PRECISION: u32 = 100;
2277
2278            mod real {
2279                use super::*;
2280                use rug::Float;
2281
2282                #[test]
2283                fn zero() {
2284                    test_zero::<RealRugStrictFinite<64>>();
2285                    test_zero::<RealRugStrictFinite<PRECISION>>();
2286                }
2287
2288                #[test]
2289                fn one() {
2290                    test_one::<RealRugStrictFinite<64>>();
2291                    test_one::<RealRugStrictFinite<PRECISION>>();
2292                }
2293
2294                #[test]
2295                fn recip() {
2296                    test_recip::<RealRugStrictFinite<64>>();
2297                    test_recip::<RealRugStrictFinite<PRECISION>>();
2298                }
2299
2300                #[test]
2301                fn add() {
2302                    let a = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
2303                    let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2304                    let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
2305                    test_add(a, b, c_expected);
2306                }
2307
2308                #[test]
2309                fn sub() {
2310                    let a = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
2311                    let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2312                    let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
2313                    test_sub(a, b, c_expected);
2314                }
2315
2316                #[test]
2317                fn mul() {
2318                    let a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2319                    let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
2320                    let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(6.0).unwrap();
2321                    test_mul(a, b, c_expected);
2322                }
2323
2324                #[test]
2325                fn div() {
2326                    let a = RealRugStrictFinite::<PRECISION>::try_from_f64(6.).unwrap();
2327                    let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.).unwrap();
2328                    let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap();
2329
2330                    test_div(a, b, c_expected);
2331                }
2332
2333                #[test]
2334                fn neg_assign() {
2335                    test_neg_assign_real::<RealRugStrictFinite<PRECISION>>();
2336                }
2337
2338                #[test]
2339                fn add_assign() {
2340                    test_add_assign_real::<RealRugStrictFinite<PRECISION>>();
2341                }
2342
2343                #[test]
2344                fn sub_assign() {
2345                    test_sub_assign_real::<RealRugStrictFinite<PRECISION>>();
2346                }
2347
2348                #[test]
2349                fn mul_assign() {
2350                    test_mul_assign_real::<RealRugStrictFinite<PRECISION>>();
2351                }
2352
2353                #[test]
2354                fn div_assign() {
2355                    test_div_assign_real::<RealRugStrictFinite<PRECISION>>();
2356                }
2357
2358                #[test]
2359                fn mul_add_ref() {
2360                    test_mul_add_ref_real::<RealRugStrictFinite<PRECISION>>();
2361                }
2362
2363                #[test]
2364                fn abs() {
2365                    test_abs_real::<RealRugStrictFinite<PRECISION>>();
2366                }
2367
2368                #[test]
2369                fn acos() {
2370                    {
2371                        let a = RealRugStrictFinite::<53>::zero();
2372                        let pi_over_2 = RealRugStrictFinite::<53>::acos(a);
2373                        let expected = rug::Float::with_val(53, std::f64::consts::FRAC_PI_2);
2374                        assert_eq!(pi_over_2.as_ref(), &expected);
2375                    }
2376                    {
2377                        let a = RealRugStrictFinite::<100>::zero();
2378                        let pi_over_2 = RealRugStrictFinite::<100>::acos(a);
2379                        let expected = rug::Float::with_val(
2380                            100,
2381                            rug::Float::parse("1.5707963267948966192313216916397").unwrap(),
2382                        );
2383                        assert_eq!(pi_over_2.as_ref(), &expected);
2384                    }
2385                }
2386
2387                #[test]
2388                fn asin() {
2389                    {
2390                        let a = RealRugStrictFinite::<53>::one();
2391                        let pi_over_2 = RealRugStrictFinite::<53>::asin(a);
2392                        let expected = rug::Float::with_val(53, std::f64::consts::FRAC_PI_2);
2393                        assert_eq!(pi_over_2.as_ref(), &expected);
2394                    }
2395                    {
2396                        let a = RealRugStrictFinite::<100>::one();
2397                        let pi_over_2 = RealRugStrictFinite::<100>::asin(a);
2398                        let expected = rug::Float::with_val(
2399                            100,
2400                            rug::Float::parse("1.5707963267948966192313216916397").unwrap(),
2401                        );
2402                        assert_eq!(pi_over_2.as_ref(), &expected);
2403                    }
2404                }
2405
2406                #[test]
2407                fn cos() {
2408                    test_cos_real::<RealRugStrictFinite<64>>();
2409                    test_cos_real::<RealRugStrictFinite<PRECISION>>();
2410                }
2411
2412                #[test]
2413                fn sin() {
2414                    test_sin_real::<RealRugStrictFinite<64>>();
2415                    test_sin_real::<RealRugStrictFinite<PRECISION>>();
2416                }
2417
2418                #[test]
2419                fn dot_product() {
2420                    let a = &[
2421                        RealRugStrictFinite::<100>::one(),
2422                        RealRugStrictFinite::<100>::try_from_f64(2.).unwrap(),
2423                    ];
2424
2425                    let b = &[
2426                        RealRugStrictFinite::<100>::try_from_f64(2.).unwrap(),
2427                        RealRugStrictFinite::<100>::try_from_f64(-1.).unwrap(),
2428                    ];
2429
2430                    let a: Vec<_> = a.iter().map(|a_i| a_i.as_ref()).collect();
2431                    let b: Vec<_> = b.iter().map(|b_i| b_i.as_ref()).collect();
2432
2433                    let value = RealRugStrictFinite::<100>::try_new(
2434                        rug::Float::dot(a.into_iter().zip(b)).complete(100),
2435                    )
2436                    .unwrap();
2437
2438                    assert_eq!(value.as_ref(), &rug::Float::with_val(100, 0.));
2439                }
2440                #[test]
2441                fn test_acos() {
2442                    let value =
2443                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2444                            .unwrap();
2445                    let result = value.clone().acos();
2446                    assert_eq!(
2447                        result,
2448                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2449                            PRECISION,
2450                            value.into_inner().acos()
2451                        ))
2452                        .unwrap()
2453                    );
2454                }
2455
2456                #[test]
2457                fn test_acosh() {
2458                    let value =
2459                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.5))
2460                            .unwrap();
2461                    let result = value.clone().acosh();
2462                    assert_eq!(
2463                        result,
2464                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2465                            PRECISION,
2466                            value.into_inner().acosh()
2467                        ))
2468                        .unwrap()
2469                    );
2470                }
2471
2472                #[test]
2473                fn test_asin() {
2474                    let value =
2475                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2476                            .unwrap();
2477                    let result = value.clone().asin();
2478                    assert_eq!(
2479                        result,
2480                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2481                            PRECISION,
2482                            value.into_inner().asin()
2483                        ))
2484                        .unwrap()
2485                    );
2486                }
2487
2488                #[test]
2489                fn test_asinh() {
2490                    let value =
2491                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2492                            .unwrap();
2493                    let result = value.clone().asinh();
2494                    assert_eq!(
2495                        result,
2496                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2497                            PRECISION,
2498                            value.into_inner().asinh()
2499                        ))
2500                        .unwrap()
2501                    );
2502                }
2503
2504                #[test]
2505                fn test_atan() {
2506                    let value =
2507                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2508                            .unwrap();
2509                    let result = value.clone().atan();
2510                    assert_eq!(
2511                        result,
2512                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2513                            PRECISION,
2514                            value.into_inner().atan()
2515                        ))
2516                        .unwrap()
2517                    );
2518                }
2519
2520                #[test]
2521                fn test_atanh() {
2522                    let value =
2523                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2524                            .unwrap();
2525                    let result = value.clone().atanh();
2526                    assert_eq!(
2527                        result,
2528                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2529                            PRECISION,
2530                            value.into_inner().atanh()
2531                        ))
2532                        .unwrap()
2533                    );
2534                }
2535
2536                #[test]
2537                fn test_cos_02() {
2538                    let value =
2539                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2540                            .unwrap();
2541                    let result = value.clone().cos();
2542                    assert_eq!(
2543                        result,
2544                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2545                            PRECISION,
2546                            value.into_inner().cos()
2547                        ))
2548                        .unwrap()
2549                    );
2550                }
2551
2552                #[test]
2553                fn test_cosh() {
2554                    let value =
2555                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2556                            .unwrap();
2557                    let result = value.clone().cosh();
2558                    assert_eq!(
2559                        result,
2560                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2561                            PRECISION,
2562                            value.into_inner().cosh()
2563                        ))
2564                        .unwrap()
2565                    );
2566                }
2567
2568                #[test]
2569                fn test_exp() {
2570                    let value =
2571                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2572                            .unwrap();
2573                    let result = value.clone().exp();
2574                    println!("result = {result:?}");
2575                    assert_eq!(
2576                        result,
2577                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2578                            PRECISION,
2579                            value.into_inner().exp()
2580                        ))
2581                        .unwrap()
2582                    );
2583                }
2584
2585                #[test]
2586                fn test_is_finite() {
2587                    let value =
2588                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2589                            .unwrap();
2590                    assert!(value.is_finite());
2591
2592                    let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2593                        PRECISION,
2594                        f64::INFINITY,
2595                    ));
2596                    assert!(value.is_err());
2597                }
2598
2599                #[test]
2600                fn test_is_infinite() {
2601                    let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2602                        PRECISION,
2603                        f64::INFINITY,
2604                    ));
2605                    assert!(value.is_err());
2606
2607                    let value =
2608                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2609                            .unwrap();
2610                    assert!(!value.is_infinite());
2611                }
2612
2613                #[test]
2614                fn test_ln() {
2615                    let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2616                        PRECISION,
2617                        std::f64::consts::E,
2618                    ))
2619                    .unwrap();
2620                    let result = value.clone().ln();
2621                    println!("result = {result:?}");
2622                    assert_eq!(
2623                        result,
2624                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2625                            PRECISION,
2626                            value.into_inner().ln()
2627                        ))
2628                        .unwrap()
2629                    );
2630                }
2631
2632                #[test]
2633                fn test_log10() {
2634                    let value =
2635                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 10.0))
2636                            .unwrap();
2637                    let result = value.clone().log10();
2638                    println!("result = {result:?}");
2639                    assert_eq!(
2640                        result,
2641                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2642                            PRECISION,
2643                            value.into_inner().log10()
2644                        ))
2645                        .unwrap()
2646                    );
2647                }
2648
2649                #[test]
2650                fn test_log2() {
2651                    let value =
2652                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 8.0))
2653                            .unwrap();
2654                    let result = value.clone().log2();
2655                    println!("result = {result:?}");
2656                    assert_eq!(
2657                        result,
2658                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2659                            PRECISION,
2660                            value.into_inner().log2()
2661                        ))
2662                        .unwrap()
2663                    );
2664                }
2665
2666                #[test]
2667                fn test_recip_02() {
2668                    let value =
2669                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
2670                            .unwrap();
2671                    let result = value.clone().try_reciprocal().unwrap();
2672                    assert_eq!(
2673                        result,
2674                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2675                            PRECISION,
2676                            value.into_inner().recip()
2677                        ))
2678                        .unwrap()
2679                    );
2680                }
2681
2682                #[test]
2683                fn test_sin_02() {
2684                    let value =
2685                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2686                            .unwrap();
2687                    let result = value.clone().sin();
2688                    assert_eq!(
2689                        result,
2690                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2691                            PRECISION,
2692                            value.into_inner().sin()
2693                        ))
2694                        .unwrap()
2695                    );
2696                }
2697
2698                #[test]
2699                fn test_sinh() {
2700                    let value =
2701                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2702                            .unwrap();
2703                    let result = value.clone().sinh();
2704                    assert_eq!(
2705                        result,
2706                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2707                            PRECISION,
2708                            value.into_inner().sinh()
2709                        ))
2710                        .unwrap()
2711                    );
2712                }
2713
2714                #[test]
2715                fn sqrt() {
2716                    let value =
2717                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2718                            .unwrap();
2719                    let result = value.clone().sqrt();
2720                    assert_eq!(
2721                        result,
2722                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2723                            PRECISION,
2724                            value.into_inner().sqrt()
2725                        ))
2726                        .unwrap()
2727                    );
2728                }
2729
2730                #[test]
2731                fn try_sqrt() {
2732                    let value =
2733                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2734                            .unwrap();
2735                    let result = value.clone().try_sqrt().unwrap();
2736                    assert_eq!(
2737                        result,
2738                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2739                            PRECISION,
2740                            value.into_inner().sqrt()
2741                        ))
2742                        .unwrap()
2743                    );
2744
2745                    assert!(
2746                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -4.0))
2747                            .unwrap()
2748                            .try_sqrt()
2749                            .is_err()
2750                    )
2751                }
2752
2753                #[test]
2754                fn test_tan() {
2755                    let value =
2756                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2757                            .unwrap();
2758                    let result = value.clone().tan();
2759                    assert_eq!(
2760                        result,
2761                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2762                            PRECISION,
2763                            value.into_inner().tan()
2764                        ))
2765                        .unwrap()
2766                    );
2767                }
2768
2769                #[test]
2770                fn test_tanh() {
2771                    let value =
2772                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2773                            .unwrap();
2774                    let result = value.clone().tanh();
2775                    assert_eq!(
2776                        result,
2777                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2778                            PRECISION,
2779                            value.into_inner().tanh()
2780                        ))
2781                        .unwrap()
2782                    );
2783                }
2784
2785                #[test]
2786                fn test_mul_add() {
2787                    let a =
2788                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
2789                            .unwrap();
2790                    let b =
2791                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
2792                            .unwrap();
2793                    let c =
2794                        RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2795                            .unwrap();
2796                    let result = a.clone().mul_add_ref(&b, &c);
2797                    assert_eq!(
2798                        result,
2799                        RealRugStrictFinite::<PRECISION>::try_new(
2800                            a.into_inner() * b.as_ref() + c.as_ref()
2801                        )
2802                        .unwrap()
2803                    );
2804                }
2805            }
2806
2807            mod complex {
2808                use super::*;
2809                //use rug::Complex;
2810                use rug::Float;
2811
2812                #[test]
2813                fn add() {
2814                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2815                        .unwrap();
2816                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 4.))
2817                        .unwrap();
2818                    let c_expected =
2819                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(4., 6.))
2820                            .unwrap();
2821                    test_add(a, b, c_expected);
2822                }
2823
2824                #[test]
2825                fn sub() {
2826                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2827                        .unwrap();
2828                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2829                        .unwrap();
2830                    let c_expected =
2831                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., -2.))
2832                            .unwrap();
2833                    test_sub(a, b, c_expected);
2834                }
2835
2836                #[test]
2837                fn mul() {
2838                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2839                        .unwrap();
2840                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2841                        .unwrap();
2842                    let c_expected =
2843                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-5., 14.))
2844                            .unwrap();
2845                    test_mul(a, b, c_expected);
2846                }
2847
2848                #[test]
2849                fn div() {
2850                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-5., 14.))
2851                        .unwrap();
2852                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2853                        .unwrap();
2854                    let c_expected =
2855                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2856                            .unwrap();
2857                    test_div(a, b, c_expected);
2858                }
2859
2860                #[test]
2861                fn add_assign() {
2862                    let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2863                        .unwrap();
2864                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 4.))
2865                        .unwrap();
2866
2867                    a += &b;
2868                    let a_expected =
2869                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(4., 6.))
2870                            .unwrap();
2871                    assert_eq!(a, a_expected);
2872
2873                    a += b;
2874                    let a_expected =
2875                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(7., 10.))
2876                            .unwrap();
2877                    assert_eq!(a, a_expected);
2878                }
2879
2880                #[test]
2881                fn sub_assign() {
2882                    let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2883                        .unwrap();
2884                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2885                        .unwrap();
2886
2887                    a -= &b;
2888                    let a_expected =
2889                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., -2.))
2890                            .unwrap();
2891                    assert_eq!(a, a_expected);
2892
2893                    a -= b;
2894                    let a_expected =
2895                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., -6.))
2896                            .unwrap();
2897                    assert_eq!(a, a_expected);
2898                }
2899
2900                #[test]
2901                fn mul_assign() {
2902                    let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2903                        .unwrap();
2904                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2905                        .unwrap();
2906
2907                    a *= &b;
2908                    let a_expected =
2909                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., 16.))
2910                            .unwrap();
2911                    assert_eq!(a, a_expected);
2912
2913                    a *= b;
2914                    let a_expected =
2915                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-68., 24.))
2916                            .unwrap();
2917                    assert_eq!(a, a_expected);
2918                }
2919
2920                #[test]
2921                fn div_assign() {
2922                    let mut a =
2923                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-68., 24.))
2924                            .unwrap();
2925                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2926                        .unwrap();
2927
2928                    a /= &b;
2929                    let a_expected =
2930                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., 16.))
2931                            .unwrap();
2932                    assert_eq!(a, a_expected);
2933
2934                    a /= b;
2935                    let a_expected =
2936                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2937                            .unwrap();
2938                    assert_eq!(a, a_expected);
2939                }
2940
2941                #[test]
2942                fn from_f64() {
2943                    let v_100bits =
2944                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(16.25, 2.))
2945                            .unwrap();
2946                    assert_eq!(
2947                        ComplexRugStrictFinite::<PRECISION>::real_part(&v_100bits),
2948                        16.25
2949                    );
2950                    assert_eq!(
2951                        ComplexRugStrictFinite::<PRECISION>::imag_part(&v_100bits),
2952                        2.
2953                    );
2954
2955                    let v_53bits =
2956                        ComplexRugStrictFinite::<53>::try_from(Complex::new(16.25, 2.)).unwrap();
2957                    assert_eq!(ComplexRugStrictFinite::<53>::real_part(&v_53bits), 16.25);
2958                    assert_eq!(ComplexRugStrictFinite::<53>::imag_part(&v_53bits), 2.);
2959
2960                    // 16.25 has seven significant bits (binary 10000.01)
2961                    let v_7bits =
2962                        ComplexRugStrictFinite::<7>::try_from(Complex::new(16.25, 2.)).unwrap();
2963                    assert_eq!(ComplexRugStrictFinite::<7>::real_part(&v_7bits), 16.25);
2964                    assert_eq!(ComplexRugStrictFinite::<7>::imag_part(&v_7bits), 2.);
2965                }
2966
2967                #[test]
2968                #[should_panic]
2969                fn from_f64_failing() {
2970                    // this should fail because 16.25 has seven significant bits (binary 10000.01) and we ask a float with 6 significant bits
2971                    let _v_6bits =
2972                        ComplexRugStrictFinite::<6>::try_from(Complex::new(16.25, 2.)).unwrap();
2973                }
2974
2975                #[test]
2976                fn conj() {
2977                    let v = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(16.25, 2.))
2978                        .unwrap();
2979
2980                    let v_conj = ComplexRugStrictFinite::<PRECISION>::conjugate(v);
2981                    assert_eq!(
2982                        ComplexRugStrictFinite::<PRECISION>::real_part(&v_conj),
2983                        16.25
2984                    );
2985                    assert_eq!(ComplexRugStrictFinite::<PRECISION>::imag_part(&v_conj), -2.);
2986                }
2987
2988                #[test]
2989                fn neg_assign() {
2990                    let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2991                        .unwrap();
2992                    a.neg_assign();
2993
2994                    let a_expected =
2995                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., -2.))
2996                            .unwrap();
2997                    assert_eq!(a, a_expected);
2998                }
2999
3000                #[test]
3001                fn abs() {
3002                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-3., 4.))
3003                        .unwrap();
3004
3005                    let abs = a.abs();
3006                    let abs_expected = RealRugStrictFinite::<100>::try_from_f64(5.).unwrap();
3007                    assert_eq!(abs, abs_expected);
3008                }
3009
3010                #[test]
3011                fn mul_add_ref() {
3012                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., -3.))
3013                        .unwrap();
3014                    let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 1.))
3015                        .unwrap();
3016                    let c = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., -4.))
3017                        .unwrap();
3018
3019                    let d_expected =
3020                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(10., -11.))
3021                            .unwrap();
3022
3023                    let d = a.mul_add_ref(&b, &c);
3024                    assert_eq!(d, d_expected);
3025                }
3026
3027                #[test]
3028                fn mul_complex_with_real() {
3029                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
3030                        .unwrap();
3031                    let b = RealRugStrictFinite::<100>::try_from_f64(3.).unwrap();
3032
3033                    let a_times_b_expected =
3034                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 6.))
3035                            .unwrap();
3036
3037                    test_mul_complex_with_real(a, b, a_times_b_expected);
3038                }
3039
3040                #[test]
3041                fn mul_assign_complex_with_real() {
3042                    let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
3043                        .unwrap();
3044                    let b = RealRugStrictFinite::<100>::try_from_f64(3.).unwrap();
3045
3046                    let a_times_b_expected =
3047                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 6.))
3048                            .unwrap();
3049
3050                    test_mul_assign_complex_with_real(a, b, a_times_b_expected);
3051                }
3052
3053                #[test]
3054                fn dot_product() {
3055                    let a = &[
3056                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 3.))
3057                            .unwrap(),
3058                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
3059                            .unwrap(),
3060                    ];
3061
3062                    let b = &[
3063                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., -5.))
3064                            .unwrap(),
3065                        ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., 6.))
3066                            .unwrap(),
3067                    ];
3068
3069                    let a: Vec<_> = a.iter().map(|a_i| a_i.as_ref()).collect();
3070                    let b: Vec<_> = b.iter().map(|b_i| b_i.as_ref()).collect();
3071
3072                    // computes a * a^T
3073                    let a_times_a = ComplexRugStrictFinite::<PRECISION>::try_new(
3074                        rug::Complex::dot(a.clone().into_iter().zip(a.clone()))
3075                            .complete((100, 100)),
3076                    )
3077                    .unwrap();
3078                    assert_eq!(
3079                        a_times_a.as_ref(),
3080                        &rug::Complex::with_val(100, (-20., 22.))
3081                    );
3082
3083                    // computes a * b^T
3084                    let a_times_b = ComplexRugStrictFinite::<PRECISION>::try_new(
3085                        rug::Complex::dot(a.clone().into_iter().zip(b.clone()))
3086                            .complete((100, 100)),
3087                    )
3088                    .unwrap();
3089                    assert_eq!(
3090                        a_times_b.as_ref(),
3091                        &rug::Complex::with_val(100, (-13., -3.))
3092                    );
3093
3094                    // computes b * a^T
3095                    let b_times_a = ComplexRugStrictFinite::<PRECISION>::try_new(
3096                        rug::Complex::dot(b.into_iter().zip(a)).complete((100, 100)),
3097                    )
3098                    .unwrap();
3099                    assert_eq!(
3100                        b_times_a.as_ref(),
3101                        &rug::Complex::with_val(100, (-13., -3.))
3102                    );
3103                }
3104
3105                #[test]
3106                fn test_acos() {
3107                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3108                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3109                    )
3110                    .unwrap();
3111                    let result = value.clone().acos();
3112                    assert_eq!(
3113                        result,
3114                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3115                            PRECISION,
3116                            value.into_inner().acos()
3117                        ))
3118                        .unwrap()
3119                    );
3120                }
3121
3122                #[test]
3123                fn test_acosh() {
3124                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3125                        rug::Complex::with_val(PRECISION, (1.5, 0.5)),
3126                    )
3127                    .unwrap();
3128                    let result = value.clone().acosh();
3129                    assert_eq!(
3130                        result,
3131                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3132                            PRECISION,
3133                            value.into_inner().acosh()
3134                        ))
3135                        .unwrap()
3136                    );
3137                }
3138
3139                #[test]
3140                fn test_asin() {
3141                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3142                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3143                    )
3144                    .unwrap();
3145                    let result = value.clone().asin();
3146                    assert_eq!(
3147                        result,
3148                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3149                            PRECISION,
3150                            value.into_inner().asin()
3151                        ))
3152                        .unwrap()
3153                    );
3154                }
3155
3156                #[test]
3157                fn test_asinh() {
3158                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3159                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3160                    )
3161                    .unwrap();
3162                    let result = value.clone().asinh();
3163                    assert_eq!(
3164                        result,
3165                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3166                            PRECISION,
3167                            value.into_inner().asinh()
3168                        ))
3169                        .unwrap()
3170                    );
3171                }
3172
3173                #[test]
3174                fn test_atan() {
3175                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3176                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3177                    )
3178                    .unwrap();
3179                    let result = value.clone().atan();
3180                    assert_eq!(
3181                        result,
3182                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3183                            PRECISION,
3184                            value.into_inner().atan()
3185                        ))
3186                        .unwrap()
3187                    );
3188                }
3189
3190                #[test]
3191                fn test_atanh() {
3192                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3193                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3194                    )
3195                    .unwrap();
3196                    let result = value.clone().atanh();
3197                    assert_eq!(
3198                        result,
3199                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3200                            PRECISION,
3201                            value.into_inner().atanh()
3202                        ))
3203                        .unwrap()
3204                    );
3205                }
3206
3207                #[test]
3208                fn test_cos_01() {
3209                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3210                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3211                    )
3212                    .unwrap();
3213                    let result = value.clone().cos();
3214                    assert_eq!(
3215                        result,
3216                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3217                            PRECISION,
3218                            value.into_inner().cos()
3219                        ))
3220                        .unwrap()
3221                    );
3222                }
3223
3224                #[test]
3225                fn test_cosh() {
3226                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3227                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3228                    )
3229                    .unwrap();
3230                    let result = value.clone().cosh();
3231                    assert_eq!(
3232                        result,
3233                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3234                            PRECISION,
3235                            value.into_inner().cosh()
3236                        ))
3237                        .unwrap()
3238                    );
3239                }
3240
3241                #[test]
3242                fn test_exp() {
3243                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3244                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3245                    )
3246                    .unwrap();
3247                    let result = value.clone().exp();
3248                    println!("result = {result:?}");
3249                    assert_eq!(
3250                        result,
3251                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3252                            PRECISION,
3253                            value.into_inner().exp()
3254                        ))
3255                        .unwrap()
3256                    );
3257                }
3258
3259                #[test]
3260                fn test_is_finite() {
3261                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3262                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3263                    )
3264                    .unwrap();
3265                    assert!(value.is_finite());
3266
3267                    let value =
3268                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3269                            100,
3270                            (Float::with_val(PRECISION, f64::INFINITY), 0.5),
3271                        ));
3272                    assert!(value.is_err());
3273                }
3274
3275                #[test]
3276                fn test_is_infinite() {
3277                    let value =
3278                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3279                            100,
3280                            (Float::with_val(PRECISION, f64::INFINITY), 0.5),
3281                        ));
3282                    assert!(value.is_err());
3283
3284                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3285                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3286                    )
3287                    .unwrap();
3288                    assert!(!value.is_infinite());
3289                }
3290
3291                #[test]
3292                fn test_ln() {
3293                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3294                        rug::Complex::with_val(PRECISION, (std::f64::consts::E, 1.0)),
3295                    )
3296                    .unwrap();
3297                    let result = value.clone().ln();
3298                    println!("result = {result:?}");
3299                    assert_eq!(
3300                        result,
3301                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3302                            PRECISION,
3303                            value.into_inner().ln()
3304                        ))
3305                        .unwrap()
3306                    );
3307                }
3308
3309                #[test]
3310                fn test_log10() {
3311                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3312                        rug::Complex::with_val(PRECISION, (10.0, 1.0)),
3313                    )
3314                    .unwrap();
3315                    let result = value.clone().log10();
3316                    println!("result = {result:?}");
3317                    assert_eq!(
3318                        result,
3319                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3320                            PRECISION,
3321                            value.into_inner().log10()
3322                        ))
3323                        .unwrap()
3324                    );
3325                }
3326
3327                #[test]
3328                fn test_log2() {
3329                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3330                        rug::Complex::with_val(PRECISION, (8.0, 1.0)),
3331                    )
3332                    .unwrap();
3333                    let result = value.clone().log2();
3334                    println!("result = {result:?}");
3335                    assert_eq!(
3336                        result,
3337                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3338                            PRECISION,
3339                            value.into_inner().ln() / rug::Float::with_val(PRECISION, 2.).ln()
3340                        ))
3341                        .unwrap()
3342                    );
3343                }
3344
3345                #[test]
3346                fn test_recip() {
3347                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3348                        rug::Complex::with_val(PRECISION, (2.0, 0.0)),
3349                    )
3350                    .unwrap();
3351                    let result = value.clone().try_reciprocal().unwrap();
3352                    assert_eq!(
3353                        result,
3354                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3355                            PRECISION,
3356                            value.into_inner().recip()
3357                        ))
3358                        .unwrap()
3359                    );
3360                }
3361
3362                #[test]
3363                fn test_sin_01() {
3364                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3365                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3366                    )
3367                    .unwrap();
3368                    let result = value.clone().sin();
3369                    assert_eq!(
3370                        result,
3371                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3372                            PRECISION,
3373                            value.into_inner().sin()
3374                        ))
3375                        .unwrap()
3376                    );
3377                }
3378
3379                #[test]
3380                fn test_sinh() {
3381                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3382                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3383                    )
3384                    .unwrap();
3385                    let result = value.clone().sinh();
3386                    assert_eq!(
3387                        result,
3388                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3389                            PRECISION,
3390                            value.into_inner().sinh()
3391                        ))
3392                        .unwrap()
3393                    );
3394                }
3395
3396                #[test]
3397                fn sqrt() {
3398                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3399                        rug::Complex::with_val(PRECISION, (4.0, 1.0)),
3400                    )
3401                    .unwrap();
3402                    let result = value.clone().sqrt();
3403                    assert_eq!(
3404                        result,
3405                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3406                            PRECISION,
3407                            value.into_inner().sqrt()
3408                        ))
3409                        .unwrap()
3410                    );
3411                }
3412
3413                #[test]
3414                fn try_sqrt() {
3415                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3416                        rug::Complex::with_val(PRECISION, (4.0, 1.0)),
3417                    )
3418                    .unwrap();
3419                    let result = value.clone().try_sqrt().unwrap();
3420                    assert_eq!(
3421                        result,
3422                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3423                            PRECISION,
3424                            value.into_inner().sqrt()
3425                        ))
3426                        .unwrap()
3427                    );
3428                }
3429
3430                #[test]
3431                fn test_tan() {
3432                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3433                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3434                    )
3435                    .unwrap();
3436                    let result = value.clone().tan();
3437                    assert_eq!(
3438                        result,
3439                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3440                            PRECISION,
3441                            value.into_inner().tan()
3442                        ))
3443                        .unwrap()
3444                    );
3445                }
3446
3447                #[test]
3448                fn test_tanh() {
3449                    let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3450                        rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3451                    )
3452                    .unwrap();
3453                    let result = value.clone().tanh();
3454                    assert_eq!(
3455                        result,
3456                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3457                            PRECISION,
3458                            value.into_inner().tanh()
3459                        ))
3460                        .unwrap()
3461                    );
3462                }
3463
3464                #[test]
3465                fn test_mul_add() {
3466                    let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3467                        PRECISION,
3468                        (2.0, 1.0),
3469                    ))
3470                    .unwrap();
3471                    let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3472                        PRECISION,
3473                        (3.0, 1.0),
3474                    ))
3475                    .unwrap();
3476                    let c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3477                        PRECISION,
3478                        (4.0, 1.0),
3479                    ))
3480                    .unwrap();
3481                    let result = a.clone().mul_add_ref(&b, &c);
3482                    assert_eq!(
3483                        result,
3484                        ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3485                            PRECISION,
3486                            a.as_ref() * b.as_ref() + c.as_ref()
3487                        ))
3488                        .unwrap()
3489                    );
3490                }
3491            }
3492        }
3493    }
3494
3495    mod functions_real_type {
3496        use super::*;
3497
3498        mod native64 {
3499
3500            use super::*;
3501
3502            #[test]
3503            fn test_atan2() {
3504                let a: f64 = 27.0;
3505                let b: f64 = 13.0;
3506
3507                let result = a.atan2(b);
3508                assert_eq!(result, a.atan2(b));
3509            }
3510
3511            #[test]
3512            fn test_ceil() {
3513                let value: f64 = 3.7;
3514                let result = value.kernel_ceil();
3515                assert_eq!(result, value.ceil());
3516            }
3517
3518            #[test]
3519            fn test_clamp() {
3520                let value: f64 = 5.0;
3521                let min: f64 = 3.0;
3522                let max: f64 = 7.0;
3523                let result = value.kernel_clamp(&min, &max);
3524                assert_eq!(result, value.clamp(min, max));
3525            }
3526
3527            #[test]
3528            fn test_classify() {
3529                let value: f64 = 3.7;
3530                let result = value.kernel_classify();
3531                assert_eq!(result, value.classify());
3532            }
3533
3534            #[test]
3535            fn test_copysign() {
3536                let value: f64 = 3.5;
3537                let sign: f64 = -1.0;
3538                let result = value.kernel_copysign(&sign);
3539                assert_eq!(result, value.copysign(sign));
3540            }
3541
3542            #[test]
3543            fn test_epsilon() {
3544                let eps = f64::epsilon();
3545                assert_eq!(eps, f64::EPSILON);
3546            }
3547
3548            #[test]
3549            fn test_exp_m1() {
3550                let value: f64 = 0.5;
3551                let result = value.kernel_exp_m1();
3552                assert_eq!(result, value.exp_m1());
3553            }
3554
3555            #[test]
3556            fn test_floor() {
3557                let value: f64 = 3.7;
3558                let result = value.kernel_floor();
3559                assert_eq!(result, value.floor());
3560            }
3561
3562            #[test]
3563            fn test_fract() {
3564                let value: f64 = 3.7;
3565                let result = value.kernel_fract();
3566                assert_eq!(result, value.fract());
3567            }
3568
3569            #[test]
3570            fn test_hypot() {
3571                let a: f64 = 3.0;
3572                let b: f64 = 4.0;
3573                let result = a.kernel_hypot(&b);
3574                assert_eq!(result, a.hypot(b));
3575            }
3576
3577            #[test]
3578            fn test_is_sign_negative() {
3579                let value: f64 = -1.0;
3580                assert!(value.kernel_is_sign_negative());
3581
3582                let value: f64 = -0.0;
3583                assert!(value.kernel_is_sign_negative());
3584
3585                let value: f64 = 0.0;
3586                assert!(!value.kernel_is_sign_negative());
3587
3588                let value: f64 = 1.0;
3589                assert!(!value.kernel_is_sign_negative());
3590            }
3591
3592            #[test]
3593            fn test_is_sign_positive() {
3594                let value: f64 = -1.0;
3595                assert!(!value.kernel_is_sign_positive());
3596
3597                let value: f64 = -0.0;
3598                assert!(!value.kernel_is_sign_positive());
3599
3600                let value: f64 = 0.0;
3601                assert!(value.kernel_is_sign_positive());
3602
3603                let value: f64 = 1.0;
3604                assert!(value.kernel_is_sign_positive());
3605            }
3606
3607            #[test]
3608            fn test_ln_1p() {
3609                let value: f64 = 0.5;
3610                let result = value.kernel_ln_1p();
3611                assert_eq!(result, value.ln_1p());
3612            }
3613
3614            #[test]
3615            fn test_max() {
3616                let a: f64 = 3.0;
3617                let b: f64 = 4.0;
3618                let result = a.max(b);
3619                assert_eq!(result, a.max(b));
3620            }
3621
3622            #[test]
3623            fn test_min() {
3624                let a: f64 = 3.0;
3625                let b: f64 = 4.0;
3626                let result = a.min(b);
3627                assert_eq!(result, a.min(b));
3628            }
3629
3630            #[test]
3631            fn max_finite() {
3632                let max = f64::max_finite();
3633                assert_eq!(max, f64::MAX);
3634            }
3635
3636            #[test]
3637            fn min_finite() {
3638                let min = f64::min_finite();
3639                assert_eq!(min, f64::MIN);
3640            }
3641
3642            #[test]
3643            fn test_mul_add_mul_mut() {
3644                let mut a: f64 = 2.0;
3645                let b: f64 = 3.0;
3646                let c: f64 = 4.0;
3647                let d: f64 = -1.0;
3648                let mut result = a;
3649                result.kernel_mul_add_mul_mut(&b, &c, &d);
3650
3651                a.mul_add_assign(b, c * d);
3652                assert_eq!(result, a);
3653            }
3654
3655            #[test]
3656            fn test_mul_sub_mul_mut() {
3657                let mut a: f64 = 2.0;
3658                let b: f64 = 3.0;
3659                let c: f64 = 4.0;
3660                let d: f64 = -1.0;
3661                let mut result = a;
3662                result.kernel_mul_sub_mul_mut(&b, &c, &d);
3663
3664                a.mul_add_assign(b, -c * d);
3665                assert_eq!(result, a);
3666            }
3667
3668            #[test]
3669            fn test_negative_one() {
3670                let value = f64::negative_one();
3671                assert_eq!(value, -1.0);
3672            }
3673
3674            #[test]
3675            fn test_one() {
3676                let value = f64::one();
3677                assert_eq!(value, 1.0);
3678            }
3679
3680            #[test]
3681            fn test_round() {
3682                let value: f64 = 3.5;
3683                let result = value.kernel_round();
3684                assert_eq!(result, value.round());
3685            }
3686
3687            #[test]
3688            fn test_round_ties_even() {
3689                let value: f64 = 3.5;
3690                let result = value.kernel_round_ties_even();
3691                assert_eq!(result, value.round_ties_even());
3692            }
3693
3694            #[test]
3695            fn test_signum() {
3696                let value: f64 = -3.5;
3697                let result = value.kernel_signum();
3698                assert_eq!(result, value.signum());
3699            }
3700
3701            #[test]
3702            fn test_total_cmp() {
3703                let a: f64 = 3.0;
3704                let b: f64 = 4.0;
3705                let result = a.total_cmp(&b);
3706                assert_eq!(result, a.total_cmp(&b));
3707            }
3708
3709            #[test]
3710            fn test_try_from_64() {
3711                let result = f64::try_from_f64(3.7);
3712                assert!(result.is_ok());
3713            }
3714
3715            #[test]
3716            fn test_try_from_64_error_infinite() {
3717                let result = f64::try_from_f64(f64::INFINITY);
3718                assert!(result.is_err());
3719            }
3720
3721            #[test]
3722            fn test_try_from_64_error_nan() {
3723                let result = f64::try_from_f64(f64::NAN);
3724                assert!(result.is_err());
3725            }
3726
3727            #[test]
3728            fn test_trunc() {
3729                let value: f64 = 3.7;
3730                let result = value.kernel_trunc();
3731                assert_eq!(result, value.trunc());
3732            }
3733
3734            #[test]
3735            fn test_two() {
3736                let value = f64::two();
3737                assert_eq!(value, 2.0);
3738            }
3739        }
3740
3741        #[cfg(feature = "rug")]
3742        mod rug100 {
3743            use super::*;
3744            use crate::kernels::rug::RealRugStrictFinite;
3745            use rug::{Float, ops::CompleteRound};
3746            use try_create::{IntoInner, TryNew};
3747
3748            const PRECISION: u32 = 100;
3749
3750            #[test]
3751            fn from_f64() {
3752                let v_100bits = RealRugStrictFinite::<100>::try_from_f64(16.25).unwrap();
3753
3754                assert_eq!(v_100bits, 16.25);
3755
3756                let v_53bits = RealRugStrictFinite::<53>::try_from_f64(16.25).unwrap();
3757                assert_eq!(v_53bits, 16.25);
3758
3759                // 16.25 has seven significant bits (binary 10000.01)
3760                let v_7bits = RealRugStrictFinite::<7>::try_from_f64(16.25).unwrap();
3761                assert_eq!(v_7bits, 16.25);
3762            }
3763
3764            #[test]
3765            #[should_panic]
3766            fn from_f64_failing() {
3767                // this should fail because 16.25 has seven significant bits (binary 10000.01) and we ask a float with 6 significant bits
3768                let _v_6bits = RealRugStrictFinite::<6>::try_from_f64(16.25).unwrap();
3769            }
3770
3771            #[test]
3772            fn max_finite() {
3773                let max = RealRugStrictFinite::<53>::max_finite();
3774                assert_eq!(
3775                    max.as_ref(),
3776                    &rug::Float::with_val(
3777                        53,
3778                        rug::Float::parse("1.0492893582336937e323228496").unwrap()
3779                    )
3780                );
3781            }
3782
3783            #[test]
3784            fn min_finite() {
3785                let min = RealRugStrictFinite::<53>::min_finite();
3786                assert_eq!(
3787                    min.as_ref(),
3788                    &rug::Float::with_val(
3789                        53,
3790                        rug::Float::parse("-1.0492893582336937e323228496").unwrap()
3791                    )
3792                );
3793            }
3794
3795            #[test]
3796            fn test_atan2() {
3797                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 27.0))
3798                    .unwrap();
3799                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 13.0))
3800                    .unwrap();
3801                let result = a.clone().atan2(&b);
3802                assert_eq!(
3803                    result,
3804                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3805                        PRECISION,
3806                        a.into_inner().atan2(b.as_ref())
3807                    ))
3808                    .unwrap()
3809                );
3810            }
3811
3812            #[test]
3813            fn test_ceil() {
3814                let value =
3815                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3816                        .unwrap();
3817                let result = value.clone().kernel_ceil();
3818                assert_eq!(
3819                    result,
3820                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3821                        PRECISION,
3822                        value.into_inner().ceil()
3823                    ))
3824                    .unwrap()
3825                );
3826            }
3827
3828            #[test]
3829            fn test_clamp() {
3830                let value =
3831                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0))
3832                        .unwrap();
3833                let min =
3834                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3835                        .unwrap();
3836                let max =
3837                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 7.0))
3838                        .unwrap();
3839                let result = value.clone().kernel_clamp(&min, &max);
3840                assert_eq!(
3841                    result,
3842                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3843                        PRECISION,
3844                        value.into_inner().clamp(min.as_ref(), max.as_ref())
3845                    ))
3846                    .unwrap()
3847                );
3848            }
3849
3850            #[test]
3851            fn test_classify() {
3852                let value =
3853                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3854                        .unwrap();
3855                let result = value.kernel_classify();
3856                assert_eq!(result, value.into_inner().classify());
3857            }
3858
3859            #[test]
3860            fn test_copysign() {
3861                let value =
3862                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
3863                        .unwrap();
3864                let sign =
3865                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3866                        .unwrap();
3867                let result = value.clone().kernel_copysign(&sign);
3868                assert_eq!(
3869                    result,
3870                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3871                        PRECISION,
3872                        value.into_inner().copysign(sign.as_ref())
3873                    ))
3874                    .unwrap()
3875                );
3876            }
3877
3878            #[test]
3879            fn test_epsilon() {
3880                let rug_eps = rug::Float::u_pow_u(2, PRECISION - 1)
3881                    .complete(PRECISION)
3882                    .recip();
3883                //println!("eps: {}", rug_eps);
3884
3885                let eps = RealRugStrictFinite::<PRECISION>::epsilon();
3886                assert_eq!(
3887                    eps,
3888                    RealRugStrictFinite::<PRECISION>::try_new(rug_eps.clone()).unwrap()
3889                );
3890
3891                // here we compute new_eps as the difference between 1 and the next larger floating point number
3892                let mut new_eps = Float::with_val(PRECISION, 1.);
3893                new_eps.next_up();
3894                new_eps -= Float::with_val(PRECISION, 1.);
3895                assert_eq!(new_eps, rug_eps.clone());
3896
3897                //println!("new_eps: {new_eps}");
3898
3899                let one = RealRugStrictFinite::<PRECISION>::one();
3900                let result = RealRugStrictFinite::<PRECISION>::try_new(
3901                    new_eps / Float::with_val(PRECISION, 2.),
3902                )
3903                .unwrap()
3904                    + &one;
3905                assert_eq!(result, one);
3906            }
3907
3908            #[test]
3909            fn test_exp_m1() {
3910                let value =
3911                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
3912                        .unwrap();
3913                let result = value.clone().kernel_exp_m1();
3914                assert_eq!(
3915                    result,
3916                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3917                        PRECISION,
3918                        value.into_inner().exp_m1()
3919                    ))
3920                    .unwrap()
3921                );
3922            }
3923
3924            #[test]
3925            fn test_floor() {
3926                let value =
3927                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3928                        .unwrap();
3929                let result = value.clone().kernel_floor();
3930                assert_eq!(
3931                    result,
3932                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3933                        PRECISION,
3934                        value.into_inner().floor()
3935                    ))
3936                    .unwrap()
3937                );
3938            }
3939
3940            #[test]
3941            fn test_fract() {
3942                let value =
3943                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3944                        .unwrap();
3945                let result = value.clone().kernel_fract();
3946                assert_eq!(
3947                    result,
3948                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3949                        PRECISION,
3950                        value.into_inner().fract()
3951                    ))
3952                    .unwrap()
3953                );
3954            }
3955
3956            #[test]
3957            fn test_hypot() {
3958                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3959                    .unwrap();
3960                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3961                    .unwrap();
3962                let result = a.clone().kernel_hypot(&b);
3963                assert_eq!(
3964                    result,
3965                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3966                        PRECISION,
3967                        a.into_inner().hypot(b.as_ref())
3968                    ))
3969                    .unwrap()
3970                );
3971            }
3972
3973            #[test]
3974            fn test_is_sign_negative() {
3975                let value =
3976                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3977                        .unwrap();
3978                assert!(value.kernel_is_sign_negative());
3979
3980                let value =
3981                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -0.0))
3982                        .unwrap();
3983                assert!(value.kernel_is_sign_negative());
3984
3985                let value =
3986                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0))
3987                        .unwrap();
3988                assert!(!value.kernel_is_sign_negative());
3989
3990                let value =
3991                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
3992                        .unwrap();
3993                assert!(!value.kernel_is_sign_negative());
3994            }
3995
3996            #[test]
3997            fn test_is_sign_positive() {
3998                let value =
3999                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
4000                        .unwrap();
4001                assert!(!value.kernel_is_sign_positive());
4002
4003                let value =
4004                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -0.0))
4005                        .unwrap();
4006                assert!(!value.kernel_is_sign_positive());
4007
4008                let value =
4009                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0))
4010                        .unwrap();
4011                assert!(value.kernel_is_sign_positive());
4012
4013                let value =
4014                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
4015                        .unwrap();
4016                assert!(value.kernel_is_sign_positive());
4017            }
4018
4019            #[test]
4020            fn test_ln_1p() {
4021                let value =
4022                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
4023                        .unwrap();
4024                let result = value.clone().kernel_ln_1p();
4025                assert_eq!(
4026                    result,
4027                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4028                        PRECISION,
4029                        value.into_inner().ln_1p()
4030                    ))
4031                    .unwrap()
4032                );
4033            }
4034
4035            #[test]
4036            fn test_max() {
4037                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
4038                    .unwrap();
4039                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
4040                    .unwrap();
4041                let result = a.max(&b);
4042                assert_eq!(
4043                    result,
4044                    &RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4045                        PRECISION,
4046                        a.clone().into_inner().max(b.as_ref())
4047                    ))
4048                    .unwrap()
4049                );
4050            }
4051
4052            #[test]
4053            fn test_min() {
4054                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
4055                    .unwrap();
4056                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
4057                    .unwrap();
4058                let result = a.min(&b);
4059                assert_eq!(
4060                    result,
4061                    &RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4062                        PRECISION,
4063                        a.clone().into_inner().min(b.as_ref())
4064                    ))
4065                    .unwrap()
4066                );
4067            }
4068
4069            #[test]
4070            fn test_mul_add_mul_mut() {
4071                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
4072                    .unwrap();
4073                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
4074                    .unwrap();
4075                let c = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
4076                    .unwrap();
4077                let d = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
4078                    .unwrap();
4079                let mut result = a.clone();
4080                result.kernel_mul_add_mul_mut(&b, &c, &d);
4081                assert_eq!(
4082                    result,
4083                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4084                        PRECISION,
4085                        a.into_inner()
4086                            .mul_add_ref(b.as_ref(), &(c.into_inner() * d.as_ref()))
4087                    ))
4088                    .unwrap()
4089                );
4090            }
4091
4092            #[test]
4093            fn test_mul_sub_mul_mut() {
4094                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
4095                    .unwrap();
4096                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
4097                    .unwrap();
4098                let c = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
4099                    .unwrap();
4100                let d = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
4101                    .unwrap();
4102                let mut result = a.clone();
4103                result.kernel_mul_sub_mul_mut(&b, &c, &d);
4104                assert_eq!(
4105                    result,
4106                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4107                        PRECISION,
4108                        a.into_inner()
4109                            .mul_add_ref(b.as_ref(), &(-c.into_inner() * d.as_ref()))
4110                    ))
4111                    .unwrap()
4112                );
4113            }
4114
4115            #[test]
4116            fn test_negative_one() {
4117                let value = RealRugStrictFinite::<PRECISION>::negative_one();
4118                assert_eq!(
4119                    value,
4120                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
4121                        .unwrap()
4122                );
4123            }
4124
4125            #[test]
4126            fn test_one() {
4127                let value = RealRugStrictFinite::<PRECISION>::one();
4128                assert_eq!(
4129                    value,
4130                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
4131                        .unwrap()
4132                );
4133            }
4134
4135            #[test]
4136            fn test_round() {
4137                let value =
4138                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
4139                        .unwrap();
4140                let result = value.clone().kernel_round();
4141                assert_eq!(
4142                    result,
4143                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4144                        PRECISION,
4145                        value.into_inner().round()
4146                    ))
4147                    .unwrap()
4148                );
4149            }
4150
4151            #[test]
4152            fn test_round_ties_even() {
4153                let value =
4154                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
4155                        .unwrap();
4156                let result = value.clone().kernel_round_ties_even();
4157                assert_eq!(
4158                    result,
4159                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4160                        PRECISION,
4161                        value.into_inner().round_even()
4162                    ))
4163                    .unwrap()
4164                );
4165            }
4166
4167            #[test]
4168            fn test_signum() {
4169                let value =
4170                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.5))
4171                        .unwrap();
4172                let result = value.clone().kernel_signum();
4173                assert_eq!(
4174                    result,
4175                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4176                        PRECISION,
4177                        value.into_inner().signum()
4178                    ))
4179                    .unwrap()
4180                );
4181            }
4182
4183            #[test]
4184            fn test_total_cmp() {
4185                let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
4186                    .unwrap();
4187                let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
4188                    .unwrap();
4189                let result = a.total_cmp(&b);
4190                assert_eq!(result, a.into_inner().total_cmp(b.as_ref()));
4191            }
4192
4193            #[test]
4194            fn test_try_from_64() {
4195                let result = RealRugStrictFinite::<PRECISION>::try_from_f64(3.7);
4196                assert!(result.is_ok());
4197            }
4198
4199            #[test]
4200            fn test_try_from_64_error_infinite() {
4201                let result = RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY);
4202                assert!(result.is_err());
4203            }
4204
4205            #[test]
4206            fn test_try_from_64_error_nan() {
4207                let result = RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN);
4208                assert!(result.is_err());
4209            }
4210
4211            #[test]
4212            fn test_trunc() {
4213                let value =
4214                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
4215                        .unwrap();
4216                let result = value.clone().kernel_trunc();
4217                assert_eq!(
4218                    result,
4219                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
4220                        PRECISION,
4221                        value.into_inner().trunc()
4222                    ))
4223                    .unwrap()
4224                );
4225            }
4226
4227            #[test]
4228            fn test_two() {
4229                let value = RealRugStrictFinite::<PRECISION>::two();
4230                assert_eq!(
4231                    value,
4232                    RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
4233                        .unwrap()
4234                );
4235            }
4236        }
4237    }
4238
4239    mod util_funcs {
4240        use crate::{
4241            kernels::native64_validated::RealNative64StrictFinite, new_random_vec,
4242            try_vec_f64_into_vec_real,
4243        };
4244        use rand::{SeedableRng, distr::Uniform, rngs::StdRng};
4245
4246        #[test]
4247        fn test_new_random_vec_deterministic() {
4248            let seed = [42; 32];
4249            let mut rng1 = StdRng::from_seed(seed);
4250            let mut rng2 = StdRng::from_seed(seed);
4251            let uniform = Uniform::new(-1.0, 1.0).unwrap();
4252
4253            let vec1: Vec<f64> = new_random_vec(10, &uniform, &mut rng1);
4254            let vec2: Vec<RealNative64StrictFinite> = new_random_vec(10, &uniform, &mut rng2);
4255
4256            assert_eq!(vec1.len(), 10);
4257            assert_eq!(vec2.len(), 10);
4258            for i in 0..10 {
4259                assert_eq!(&vec1[i], vec2[i].as_ref());
4260            }
4261        }
4262
4263        #[test]
4264        fn test_try_vec_f64_into_vec_real_success() {
4265            let input = vec![1.0, -2.5, 1e10];
4266            let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
4267            assert!(result.is_ok());
4268            let output = result.unwrap();
4269            assert_eq!(output[0].as_ref(), &1.0);
4270            assert_eq!(output[1].as_ref(), &-2.5);
4271        }
4272
4273        #[test]
4274        fn test_try_vec_f64_into_vec_real_fail() {
4275            let input = vec![1.0, f64::NAN, 3.0];
4276            let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
4277            assert!(result.is_err());
4278        }
4279    }
4280}