num_valid/
lib.rs

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