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