num_valid/
lib.rs

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