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