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