Skip to main content

num_valid/
lib.rs

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