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