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