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