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