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