Skip to main content

num_valid/
lib.rs

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