Skip to main content

num_valid/
lib.rs

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