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** ([`validation`] 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::validation::StrictFinitePolicy)
54//! vs. [`DebugValidationPolicy`](crate::validation::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//! - **Layer 3: Validated Wrappers**:
59//! - [`RealValidated<K>`] and [`ComplexValidated<K>`]
60//! are the primary user-facing types.
61//! - 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).
62//! - They use extensive macros to implement high-level traits. The logic is clean: perform a check (if necessary) on the input value,
63//! then call the corresponding `unchecked_*` method from the raw trait, and then perform a check on the output value before returning it.
64//! This ensures safety and correctness.
65//!
66//! 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
67//! of [`RealValidated`] is guaranteed to contain a value that has passed the validation policy, eliminating entire
68//! classes of errors (like `NaN` propagation) in user code.
69//!
70//! - **Layer 4: High-Level Abstraction Traits**:
71//! - The [`FpScalar`] trait is the central abstraction, defining a common interface for all scalar types. It uses an associated type sealed type (`Kind`),
72//! to enforce that a scalar is either real or complex, but not both.
73//! - [`RealScalar`] and [`ComplexScalar`] are specialized sub-traits of [`FpScalar`] that serve as markers for real and complex numbers, respectively.
74//! - Generic code in a consumer crate is written against these high-level traits.
75//! - The [`RealValidated`] and [`ComplexValidated`] structs from Layer 3 are the concrete implementors of these traits.
76//!
77//! These traits provide the final, safe, and generic public API. Library consumers write their algorithms
78//! against these traits, making their code independent of the specific numerical kernel being used.
79//!
80//! This layered approach is powerful, providing both high performance (by using unchecked methods internally) and safety
81//! (through the validated wrappers). The use of generics and traits makes it extensible to new numerical backends (as demonstrated by the rug implementation).
82//!
83//! - **Multiple Numerical Backends**. At the time of writing, 2 numerical backends can be used:
84//! - the standard (high-performance) numerical backend is the one in which the raw floating point and complex numbers are
85//! described by the Rust's native [`f64`] and [`Complex<f64>`](num::Complex) types, as described by the ANSI/IEEE Std 754-1985;
86//! - an optional (high-precision) numerical backend is available if the library is compiled with the optional flag `--features=rug`,
87//! and uses the arbitrary precision raw types `rug::Float` and `rug::Complex` from the Rust library [`rug`](https://crates.io/crates/rug).
88//! - **Comprehensive Mathematical Library**. It includes a wide range of mathematical functions for
89//! trigonometry, logarithms, exponentials, and more, all implemented as traits (e.g., [`functions::Sin`], [`functions::Cos`], [`functions::Sqrt`]) and available on the validated types.
90//! - **Numerically Robust Implementations**. The library commits to numerical accuracy. As an example,
91//! by using `NeumaierSum` for its default [`std::iter::Sum`] implementation to minimize precision loss.
92//! - **Robust Error Handling:** The library defines detailed error types for various numerical operations,
93//! ensuring that invalid inputs and outputs are properly handled and reported.
94//! Errors are categorized into input and output errors, with specific variants for different types of numerical
95//! issues such as division by zero, invalid values, and subnormal numbers.
96//! - **Comprehensive Documentation:** The library includes detailed documentation for each struct, trait, method,
97//! and error type, making it easy for users to understand and utilize the provided functionality.
98//! Examples are provided for key functions to demonstrate their usage and expected behavior.
99//!
100//! # Compiler Requirement: Rust Nightly
101//! This library currently requires the **nightly** toolchain because it uses some unstable Rust features which,
102//! at the time of writing (September 2025), are not yet available in stable or beta releases. These features are:
103//! - `trait_alias`: For ergonomic trait combinations
104//! - `associated_const_equality`: For rug precision safety
105//! - `error_generic_member_access`: For advanced error handling
106//!
107//! If these features are stabilized in a future Rust release, the library will be updated to support the stable compiler.
108//!
109//! To use the nightly toolchain, please run:
110//!
111//! ```bash
112//! rustup install nightly
113//! rustup override set nightly
114//! ```
115//!
116//! This will set your environment to use the nightly compiler, enabling compatibility with the current version of the
117//! library.
118//!
119//! # Getting Started
120//!
121//! This guide will walk you through the basics of using [`num-valid`](crate).
122//!
123//! ## 1. Add [`num-valid`](crate) to your Project
124//!
125//! Add the following to your `Cargo.toml` (change the versions to the latest ones):
126//!
127//! ```toml
128//! [dependencies]
129//! num-valid = "0.2.0" # Change to the latest version
130//! try_create = "0.1.2" # Needed for the TryNew trait
131//! num = "0.4" # For basic numeric traits
132//! ```
133//!
134//! To enable the arbitrary-precision backend, use the `rug` feature:
135//!
136//! ```toml
137//! [dependencies]
138//! num-valid = { version = "0.2.0", features = ["rug"] } # Change to the latest version
139//! try_create = "0.1.2" # Needed for the TryNew trait
140//! num = "0.4" # For basic numeric traits
141//! ```
142//!
143//! ## 2. Core Concept: Validated Types
144//!
145//! The central idea in [`num-valid`](crate) is to use **validated types** instead of raw primitives like [`f64`].
146//! These are wrappers that guarantee their inner value is always valid (e.g., not `NaN` or `Infinity`) according to
147//! a specific policy.
148//!
149//! The most common type you'll use is [`RealNative64StrictFinite`], which wraps an [`f64`] and ensures it's always finite,
150//! both in Debug and Release mode. For a similar type wrapping an [`f64`] that ensures it's always finite, but with the
151//! validity checks executed only in Debug mode (providing performance equal to the raw [`f64`] type), you can use
152//! [`RealNative64StrictFiniteInDebug`].
153//!
154//! ## 3. Your First Calculation
155//!
156//! Let's perform a square root calculation. You'll need to bring the necessary traits into scope.
157//!
158//! ```rust
159//! // Import the validated type and necessary traits
160//! use num_valid::{
161//! RealNative64StrictFinite,
162//! functions::{Sqrt, SqrtRealInputErrors, SqrtRealErrors},
163//! };
164//! use try_create::TryNew;
165//!
166//! // 1. Create a validated number. try_new() returns a Result.
167//! let x = RealNative64StrictFinite::try_new(4.0).unwrap();
168//!
169//! // 2. Use the direct method for operations.
170//! // This will panic if the operation is invalid (e.g., sqrt of a negative).
171//! let sqrt_x = x.sqrt();
172//! assert_eq!(*sqrt_x.as_ref(), 2.0);
173//!
174//! // 3. Use the `try_*` methods for error handling.
175//! // This is the safe way to handle inputs that might be out of the function's domain.
176//! let neg_x = RealNative64StrictFinite::try_new(-4.0).unwrap();
177//! let sqrt_neg_x_result = neg_x.try_sqrt();
178//!
179//! // The operation fails gracefully, returning an Err.
180//! assert!(sqrt_neg_x_result.is_err());
181//!
182//! // The error gives information about the problem that occurred
183//! if let Err(SqrtRealErrors::Input { source }) = sqrt_neg_x_result {
184//! assert!(matches!(source, SqrtRealInputErrors::NegativeValue { .. }));
185//! }
186//! ```
187//!
188//! ## 4. Writing Generic Functions
189//!
190//! The real power of [`num-valid`](crate) comes from writing generic functions that work with any
191//! supported numerical type. You can do this by using the [`FpScalar`] and [`RealScalar`] traits as bounds.
192//!
193//! ```rust
194//! use num_valid::{
195//! RealScalar, RealNative64StrictFinite, FpScalar,
196//! functions::{Abs, Sin, Cos},
197//! };
198//! use num::One;
199//! use try_create::TryNew;
200//!
201//! // This function works for any type that implements RealScalar,
202//! // including f64, RealNative64StrictFinite, and RealRugStrictFinite.
203//! fn verify_trig_identity<T: RealScalar>(angle: T) -> T {
204//! // We can use .sin(), .cos(), and arithmetic ops because they are
205//! // required by the RealScalar trait.
206//! let sin_x = angle.clone().sin();
207//! let cos_x = angle.cos();
208//! (sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
209//! }
210//!
211//! // Define a type alias for convenience
212//! type MyReal = RealNative64StrictFinite;
213//!
214//! // Call it with a validated f64 type.
215//! let angle = MyReal::try_from_f64(0.5).unwrap();
216//! let identity = verify_trig_identity(angle);
217//!
218//! // The result should be very close to 1.0.
219//! let one = MyReal::one();
220//! assert!((identity - one).abs() < MyReal::try_from_f64(1e-15).unwrap());
221//! ```
222//!
223//! If the `rug` feature is enabled, you could call the exact same
224//! function with a high-precision number changing only the definition
225//! of the alias type `MyReal`. For example, for real numbers with precision of 100 bits:
226//! ```rust
227//! # #[cfg(feature = "rug")] {
228//! // Import the rug-based types
229//! use num_valid::{
230//! RealScalar, RealRugStrictFinite, FpScalar,
231//! functions::{Abs, Sin, Cos},
232//! };
233//! use num::One;
234//! use try_create::TryNew;
235//!
236//! // This function works for any type that implements RealScalar,
237//! // including f64, RealNative64StrictFinite, and RealRugStrictFinite.
238//! fn verify_trig_identity<T: RealScalar>(angle: T) -> T {
239//! // We can use .sin(), .cos(), and arithmetic ops because they are
240//! // required by the RealScalar trait.
241//! let sin_x = angle.clone().sin();
242//! let cos_x = angle.cos();
243//! (sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
244//! }
245//!
246//! // Define a type alias for convenience - real number with precision of 100 bits
247//! type MyReal = RealRugStrictFinite<100>;
248//!
249//! // Initialize it with an f64 value.
250//! let angle = MyReal::try_from_f64(0.5).unwrap();
251//! let identity = verify_trig_identity(angle);
252//!
253//! // The result should be very close to 1.0.
254//! let one = MyReal::one();
255//! assert!((identity - one).abs() < MyReal::try_from_f64(1e-15).unwrap());
256//! # }
257//! ```
258//!
259//! ## 5. Working with Complex Numbers
260//!
261//! The library also provides validated complex number types:
262//!
263//! ```rust
264//! use num_valid::{ComplexNative64StrictFinite, functions::Abs};
265//! use num::Complex;
266//! use try_create::TryNew;
267//!
268//! // Create a validated complex number
269//! let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
270//!
271//! // Complex operations work the same way
272//! let magnitude = z.abs();
273//! assert_eq!(*magnitude.as_ref(), 5.0); // |3 + 4i| = 5
274//! ```
275//!
276//! # License
277//! Copyright 2023-2025, C.N.R. - Consiglio Nazionale delle Ricerche
278//!
279//! Licensed under either of
280//! - Apache License, Version 2.0
281//! - MIT license
282//!
283//! at your option.
284//!
285//! Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you,
286//! as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
287//!
288//! ## License Notice for Optional Feature Dependencies (LGPL-3.0 Compliance)
289//! If you enable the `rug` feature, this project will depend on the [`rug`](https://crates.io/crates/rug) library,
290//! which is licensed under the LGPL-3.0 license. Activating this feature may introduce LGPL-3.0 requirements to your
291//! project. Please review the terms of the LGPL-3.0 license to ensure compliance.
292
293pub mod functions;
294pub mod kernels;
295pub mod neumaier_compensated_sum;
296pub mod validation;
297
298use crate::{
299 functions::{
300 ACos, ACosH, ASin, ASinH, ATan, ATan2, ATanH, Abs, Arg, Arithmetic, Clamp, Classify,
301 ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
302 ComplexScalarSetParts, Conjugate, Cos, CosH, Exp, ExpM1, HyperbolicFunctions, Hypot, Ln,
303 Ln1p, Log2, Log10, LogarithmFunctions, Max, Min, MulAddRef, NegAssign, Pow,
304 PowComplexBaseRealExponentErrors, PowIntExponent, PowRealBaseRealExponentErrors,
305 Reciprocal, Rounding, Sign, Sin, SinH, Sqrt, Tan, TanH, TotalCmp, TrigonometricFunctions,
306 },
307 kernels::{RawRealTrait, RawScalarTrait},
308 neumaier_compensated_sum::NeumaierAddable,
309 validation::{ErrorsRawRealToInteger, ErrorsTryFromf64, FpChecks},
310};
311use num::{Complex, One, Zero};
312use rand::{Rng, distr::Distribution};
313use std::{
314 fmt::{Debug, Display},
315 ops::{Mul, MulAssign, Neg},
316};
317use try_create::IntoInner;
318
319pub use crate::kernels::{
320 ComplexValidated, NumKernel, RawKernel, RealValidated,
321 native64::Native64,
322 native64_validated::{
323 ComplexNative64StrictFinite, ComplexNative64StrictFiniteInDebug, Native64StrictFinite,
324 Native64StrictFiniteInDebug, RealNative64StrictFinite, RealNative64StrictFiniteInDebug,
325 },
326};
327
328#[cfg(feature = "rug")]
329pub use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite, RugStrictFinite};
330
331//------------------------------------------------------------------------------------------------
332// Private module to encapsulate implementation details of the scalar kind for the mutual exclusion.
333pub(crate) mod scalar_kind {
334 /// A sealed trait to mark the "kind" of a scalar.
335 /// External users cannot implement this trait.
336 pub trait Sealed {}
337
338 /// A marker for real scalar types.
339 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
340 pub struct Real;
341 impl Sealed for Real {}
342
343 /// A marker for complex scalar types.
344 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
345 pub struct Complex;
346 impl Sealed for Complex {}
347}
348//------------------------------------------------------------------------------------------------
349
350//------------------------------------------------------------------------------------------------
351
352/// # Core trait for a floating-point scalar number (real or complex)
353///
354/// [`FpScalar`] is a fundamental trait in [`num-valid`](crate) that provides a common interface
355/// for all floating-point scalar types, whether they are real or complex, and regardless
356/// of their underlying numerical kernel (e.g., native [`f64`] or arbitrary-precision [`rug`](https://docs.rs/rug/latest/rug/index.html) types).
357///
358/// This trait serves as a primary bound for generic functions and structures that need to
359/// operate on scalar values capable of floating-point arithmetic. It aggregates a large
360/// number of mathematical function traits (e.g., [`Sin`], [`Cos`], [`Exp`], [`Sqrt`]) and
361/// core properties.
362///
363/// ## Key Responsibilities and Associated Types:
364///
365/// - **Scalar Kind (`FpScalar::Kind`):**
366/// This associated type specifies the fundamental nature of the scalar, which can be
367/// either `scalar_kind::Real` or `scalar_kind::Complex`. It is bound by the private,
368/// sealed trait `scalar_kind::Sealed`. This design enforces **mutual exclusion**:
369/// since a type can only implement [`FpScalar`] once, it can only have one `Kind`,
370/// making it impossible for a type to be both a `RealScalar` and a `ComplexScalar` simultaneously.
371///
372/// - **Real Type Component ([`FpScalar::RealType`]):**
373/// Specifies the real number type corresponding to this scalar via [`RealType`](FpScalar::RealType).
374/// - For real scalars (e.g., [`f64`], [`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`],
375/// `RealRugStrictFinite`, etc.), [`FpScalar::RealType`] is `Self`.
376/// - For complex scalars (e.g., [`Complex<f64>`](num::Complex), [`ComplexNative64StrictFinite`], [`ComplexNative64StrictFiniteInDebug`],
377/// `ComplexRugStrictFinite`, etc.), [`FpScalar::RealType`] is their underlying real component type
378/// (e.g., [`f64`], [`RealNative64StrictFinite`], [`RealNative64StrictFiniteInDebug`], `RealRugStrictFinite`, etc.).
379///
380/// Crucially, this [`FpScalar::RealType`] is constrained to implement [`RealScalar`], ensuring consistency.
381///
382/// - **Core Floating-Point Properties:**
383/// [`FpScalar`] requires implementations of the trait [`FpChecks`], which provides fundamental floating-point checks:
384/// - [`is_finite()`](FpChecks::is_finite): Checks if the number is finite.
385/// - [`is_infinite()`](FpChecks::is_infinite): Checks if the number is positive or negative infinity.
386/// - [`is_nan()`](FpChecks::is_nan): Checks if the number is "Not a Number".
387/// - [`is_normal()`](FpChecks::is_normal): Checks if the number is a normal (not zero, subnormal, infinite, or NaN).
388///
389/// ## Trait Bounds:
390///
391/// [`FpScalar`] itself has several important trait bounds:
392/// - `Sized + Clone + Debug + Display + PartialEq`: Standard utility traits. Note that scalar
393/// types are [`Clone`] but not necessarily [`Copy`].
394/// - [`Zero`] + [`One`]: From `num_traits`, ensuring the type has additive and multiplicative identities.
395/// - [`Neg<Output = Self>`](Neg): Ensures the type can be negated.
396/// - [`Arithmetic`]: A custom aggregate trait in [`num-valid`](crate) that bundles standard
397/// arithmetic operator traits (like [`Add`](std::ops::Add), [`Sub`](std::ops::Sub), [`Mul`], [`Div`](std::ops::Div)).
398/// - [`RandomSampleFromF64`]: Allows the type to be randomly generated from any distribution
399/// that produces `f64`, integrating with the [`rand`] crate.
400/// - `Send + Sync + 'static`: Makes the scalar types suitable for use in concurrent contexts.
401/// - A comprehensive suite of mathematical function traits like [`Sin`], [`Cos`], [`Exp`], [`Ln`], [`Sqrt`], etc.
402///
403/// ## Relationship to Other Traits:
404///
405/// - [`RealScalar`]: A sub-trait of [`FpScalar`] for real numbers, defined by the constraint `FpScalar<Kind = scalar_kind::Real>`.
406/// - [`ComplexScalar`]: A sub-trait of [`FpScalar`] for complex numbers, defined by the constraint `FpScalar<Kind = scalar_kind::Complex>`.
407/// - [`NumKernel`]: Policies like [`Native64StrictFinite`]
408/// are used to validate the raw values that are wrapped inside types implementing `FpScalar`.
409///
410/// ## Example: Generic Function
411///
412/// Here is how you can write a generic function that works with any scalar type
413/// implementing `FpScalar`.
414///
415/// ```rust
416/// use num_valid::{FpScalar, functions::{MulAddRef, Sqrt}, RealNative64StrictFinite};
417/// use num::Zero;
418/// use try_create::TryNew;
419///
420/// // This function works with any FpScalar type.
421/// fn norm_and_sqrt<T: FpScalar>(a: T, b: T) -> T {
422/// let val = a.clone().mul_add_ref(&a, &(b.clone() * b)); // a*a + b*b
423/// val.sqrt()
424/// }
425///
426/// // Also this function works with any FpScalar type.
427/// fn multiply_if_not_zero<T: FpScalar>(a: T, b: T) -> T {
428/// if !a.is_zero() && !b.is_zero() {
429/// a * b
430/// } else {
431/// T::zero()
432/// }
433/// }
434///
435/// // Example usage
436/// let a = RealNative64StrictFinite::try_new(3.0).unwrap();
437/// let b = RealNative64StrictFinite::try_new(4.0).unwrap();
438/// let result = norm_and_sqrt(a, b);
439/// assert_eq!(*result.as_ref(), 5.0);
440/// ```
441pub trait FpScalar:
442 Sized
443 + Clone
444 + Send
445 + Sync
446 + Debug
447 + Display
448 + IntoInner<InnerType: RawScalarTrait>
449 + PartialEq
450 + Arithmetic
451 + Abs<Output = Self::RealType>
452 + Sqrt
453 + PowIntExponent<RawType = Self::InnerType>
454 + TrigonometricFunctions
455 + HyperbolicFunctions
456 + LogarithmFunctions
457 + Exp
458 + Zero
459 + One
460 + FpChecks
461 + Neg<Output = Self>
462 + MulAddRef
463 + Reciprocal
464 + NeumaierAddable
465 + RandomSampleFromF64
466 + 'static
467{
468 /// The kind of scalar this is, e.g., `Real` or `Complex`.
469 /// This is a sealed trait to prevent external implementations.
470 type Kind: scalar_kind::Sealed;
471
472 /// The real number type corresponding to this scalar.
473 ///
474 /// - For real scalars (e.g., `f64`), `RealType` is `Self`.
475 /// - For complex scalars (e.g., `Complex<f64>`), `RealType` is their underlying
476 /// real component type (e.g., `f64`).
477 ///
478 /// This `RealType` is guaranteed to implement [`RealScalar`] and belong to the
479 /// same numerical kernel as `Self`.
480 type RealType: RealScalar<RealType = Self::RealType>;
481
482 /// Returns a reference to the underlying raw scalar value.
483 fn as_raw_ref(&self) -> &Self::InnerType;
484}
485//-------------------------------------------------------------------------------------------------------------
486
487//-------------------------------------------------------------------------------------------------------------
488
489/// Provides fundamental mathematical constants.
490pub trait Constants: Sized {
491 /// [Machine epsilon] value for `Self`.
492 ///
493 /// This is the difference between `1.0` and the next larger representable number.
494 ///
495 /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
496 fn epsilon() -> Self;
497
498 /// Build and return the (floating point) value -1. represented by the proper type.
499 fn negative_one() -> Self;
500
501 /// Build and return the (floating point) value 0.5 represented by the proper type.
502 fn one_div_2() -> Self;
503
504 /// Build and return the (floating point) value `Ï€` represented by the proper type.
505 fn pi() -> Self;
506
507 /// Build and return the (floating point) value `2 π` represented by the proper type.
508 fn two_pi() -> Self;
509
510 /// Build and return the (floating point) value `Ï€/2` represented by the proper type.
511 fn pi_div_2() -> Self;
512
513 /// Build and return the (floating point) value 2. represented by the proper type.
514 fn two() -> Self;
515
516 /// Build and return the maximum finite value allowed by the current floating point representation.
517 fn max_finite() -> Self;
518
519 /// Build and return the minimum finite (i.e., the most negative) value allowed by the current floating point representation.
520 fn min_finite() -> Self;
521
522 /// Build and return the natural logarithm of 2, i.e. the (floating point) value `ln(2)`, represented by the proper type.
523 fn ln_2() -> Self;
524
525 /// Build and return the natural logarithm of 10, i.e. the (floating point) value `ln(10)`, represented by the proper type.
526 fn ln_10() -> Self;
527
528 /// Build and return the base-10 logarithm of 2, i.e. the (floating point) value `Log_10(2)`, represented by the proper type.
529 fn log10_2() -> Self;
530
531 /// Build and return the base-2 logarithm of 10, i.e. the (floating point) value `Log_2(10)`, represented by the proper type.
532 fn log2_10() -> Self;
533
534 /// Build and return the base-2 logarithm of `e`, i.e. the (floating point) value `Log_2(e)`, represented by the proper type.
535 fn log2_e() -> Self;
536
537 /// Build and return the base-10 logarithm of `e`, i.e. the (floating point) value `Log_10(e)`, represented by the proper type.
538 fn log10_e() -> Self;
539
540 /// Build and return the (floating point) value `e` represented by the proper type.
541 fn e() -> Self;
542}
543
544/// # Trait for scalar real numbers
545///
546/// [`RealScalar`] extends the fundamental [`FpScalar`] trait, providing an interface
547/// specifically for real (non-complex) floating-point numbers. It introduces
548/// operations and properties that are unique to real numbers, such as ordering,
549/// rounding, and clamping.
550///
551/// This trait is implemented by real scalar types within each numerical kernel,
552/// for example, [`f64`] for the native kernel,
553/// and `RealRugStrictFinite` for the `rug` kernel (when the `rug` feature is enabled).
554///
555/// ## Key Design Principles
556///
557/// - **Inheritance from [`FpScalar`]:** As a sub-trait of [`FpScalar`], any `RealScalar`
558/// type automatically gains all the capabilities of a general floating-point number,
559/// including basic arithmetic and standard mathematical functions (e.g., `sin`, `exp`, `sqrt`).
560/// - **Raw Underlying Type ([`RawReal`](Self::RawReal)):**
561/// This associated type specifies the most fundamental, "raw" representation of the real number,
562/// which implements the [`RawRealTrait`]. This is the type used for low-level, unchecked
563/// operations within the library's internal implementation.
564/// - For [`f64`], [`RealNative64StrictFinite`] and [`RealNative64StrictFiniteInDebug`], `RawReal` is [`f64`].
565/// - For `RealRugStrictFinite<P>`, `RawReal` is [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
566/// - **Reference-Based Operations**: Many operations take arguments by reference (`&Self`)
567/// to avoid unnecessary clones of potentially expensive arbitrary-precision numbers.
568/// - **Fallible Constructors**: [`try_from_f64()`](Self::try_from_f64) validates inputs
569/// and ensures exact representability for arbitrary-precision types.
570///
571/// ## Type Safety with Validated Types
572///
573/// Real scalars that use validation policies implementing finite value guarantees
574/// automatically gain:
575/// - **Full Equality ([`Eq`])**: Well-defined, symmetric equality comparisons
576/// - **Hashing ([`Hash`])**: Use as keys in [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet)
577/// - **No Total Ordering**: The library intentionally avoids [`Ord`] in favor of
578/// more efficient reference-based [`Max`]/[`Min`] operations
579///
580/// ## Mathematical Operations
581///
582/// ### Core Arithmetic
583/// All standard arithmetic operations are available through the [`Arithmetic`] trait,
584/// supporting both value and reference semantics:
585/// ```rust
586/// use num_valid::RealNative64StrictFinite;
587/// use try_create::TryNew;
588///
589/// let a = RealNative64StrictFinite::try_new(2.0).unwrap();
590/// let b = RealNative64StrictFinite::try_new(3.0).unwrap();
591///
592/// // All combinations supported: T op T, T op &T, &T op T, &T op &T
593/// let sum1 = a.clone() + b.clone();
594/// let sum2 = &a + &b;
595/// let sum3 = a.clone() + &b;
596/// let sum4 = &a + b.clone();
597///
598/// assert_eq!(sum1, sum2);
599/// assert_eq!(sum2, sum3);
600/// assert_eq!(sum3, sum4);
601/// ```
602///
603/// ### Advanced Functions
604///
605/// In addition to the functions from [`FpScalar`], `RealScalar` provides a suite of methods common in real number arithmetic.
606/// Methods prefixed with `kernel_` provide direct access to underlying mathematical operations with minimal overhead:
607///
608/// - **Rounding ([`Rounding`]):**
609/// [`kernel_ceil()`](Rounding::kernel_ceil), [`kernel_floor()`](Rounding::kernel_floor),
610/// [`kernel_round()`](Rounding::kernel_round), [`kernel_round_ties_even()`](Rounding::kernel_round_ties_even),
611/// [`kernel_trunc()`](Rounding::kernel_trunc), and [`kernel_fract()`](Rounding::kernel_fract).
612///
613/// - **Sign Manipulation ([`Sign`]):**
614/// [`kernel_copysign()`](Sign::kernel_copysign), [`kernel_signum()`](Sign::kernel_signum),
615/// [`kernel_is_sign_positive()`](Sign::kernel_is_sign_positive), and [`kernel_is_sign_negative()`](Sign::kernel_is_sign_negative).
616///
617/// - **Comparison and Ordering:**
618/// - From [`Max`]/[`Min`]: [`max()`](Max::max) and [`min()`](Min::min).
619/// - From [`TotalCmp`]: [`total_cmp()`](TotalCmp::total_cmp) for a total ordering compliant with IEEE 754.
620/// - From [`Clamp`]: [`kernel_clamp()`](Clamp::kernel_clamp).
621///
622/// - **Specialized Functions:**
623/// - From [`ATan2`]: [`atan2()`](ATan2::atan2).
624/// - From [`ExpM1`]/[`Ln1p`]: [`kernel_exp_m1()`](ExpM1::kernel_exp_m1) and [`kernel_ln_1p()`](Ln1p::kernel_ln_1p).
625/// - From [`Hypot`]: [`kernel_hypot()`](Hypot::kernel_hypot) for computing sqrt(a² + b²).
626/// - From [`Classify`]: [`kernel_classify()`](Classify::kernel_classify).
627///
628/// - **Fused Multiply-Add Variants:**
629/// [`kernel_mul_add_mul_mut()`](Self::kernel_mul_add_mul_mut) and
630/// [`kernel_mul_sub_mul_mut()`](Self::kernel_mul_sub_mul_mut).
631///
632/// ### Constants and Utilities
633///
634/// ```rust
635/// use num_valid::{RealNative64StrictFinite, Constants};
636///
637/// let pi = RealNative64StrictFinite::pi();
638/// let e = RealNative64StrictFinite::e();
639/// let eps = RealNative64StrictFinite::epsilon();
640/// let max_val = RealNative64StrictFinite::max_finite();
641/// ```
642///
643/// ## Naming Convention for `kernel_*` Methods
644///
645/// Methods prefixed with `kernel_` (e.g., `kernel_ceil`, `kernel_copysign`) are
646/// part of the low-level kernel interface. They typically delegate directly to the
647/// most efficient implementation for the underlying type (like `f64::ceil`) without
648/// adding extra validation layers. They are intended to be fast primitives upon which
649/// safer, higher-level abstractions can be built.
650///
651/// ## Critical Trait Bounds
652///
653/// - `Self: FpScalar<RealType = Self>`: This is the defining constraint. It ensures that the type
654/// has all basic floating-point capabilities and confirms that its associated real type is itself.
655/// - `Self: PartialOrd + PartialOrd<f64>`: These bounds are essential for comparison operations,
656/// allowing instances to be compared both with themselves and with native `f64` constants.
657///
658/// ## Backend-Specific Behavior
659///
660/// ### Native `f64` Backend
661/// - Direct delegation to standard library functions
662/// - IEEE 754 compliance
663/// - Maximum performance
664///
665/// ### Arbitrary-Precision (`rug`) Backend
666/// - Configurable precision at compile-time
667/// - Exact arithmetic within precision limits
668/// - [`try_from_f64()`](Self::try_from_f64) validates exact representability
669///
670/// ## Error Handling
671///
672/// Operations that can fail provide both panicking and non-panicking variants:
673/// ```rust
674/// use num_valid::{RealNative64StrictFinite, functions::Sqrt};
675/// use try_create::TryNew;
676///
677/// let positive = RealNative64StrictFinite::try_new(4.0).unwrap();
678/// let negative = RealNative64StrictFinite::try_new(-4.0).unwrap();
679///
680/// // Panicking version (use when input validity is guaranteed)
681/// let sqrt_pos = positive.sqrt();
682/// assert_eq!(*sqrt_pos.as_ref(), 2.0);
683///
684/// // Non-panicking version (use for potentially invalid inputs)
685/// let sqrt_neg_result = negative.try_sqrt();
686/// assert!(sqrt_neg_result.is_err());
687/// ```
688pub trait RealScalar:
689 FpScalar<RealType = Self, InnerType = Self::RawReal>
690 + Sign
691 + Rounding
692 + Constants
693 + PartialEq<f64>
694 + PartialOrd
695 + PartialOrd<f64>
696 + Max
697 + Min
698 + ATan2
699 + for<'a> Pow<&'a Self, Error = PowRealBaseRealExponentErrors<Self::RawReal>>
700 + Clamp
701 + Classify
702 + ExpM1
703 + Hypot
704 + Ln1p
705 + TotalCmp
706{
707 /// The most fundamental, "raw" representation of this real number.
708 ///
709 /// This type provides the foundation for all mathematical operations and
710 /// is used to parameterize error types for this scalar.
711 ///
712 /// # Examples
713 /// - For [`f64`]: `RawReal = f64`
714 /// - For [`RealNative64StrictFinite`]: `RawReal = f64`
715 /// - For `RealRugStrictFinite<P>`: `RawReal = rug::Float`
716 type RawReal: RawRealTrait;
717
718 /// Multiplies two products and adds them in one fused operation, rounding to the nearest with only one rounding error.
719 /// `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.
720 fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self);
721
722 /// Multiplies two products and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
723 /// `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.
724 fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self);
725
726 /// Tries to create an instance of `Self` from a [`f64`].
727 ///
728 /// This conversion is fallible and validates the input `value`. For `rug`-based types,
729 /// it also ensures that the `f64` can be represented exactly at the target precision.
730 ///
731 /// # Errors
732 /// Returns [`ErrorsTryFromf64`] if the `value` is not finite or cannot be
733 /// represented exactly by `Self`.
734 fn try_from_f64(value: f64) -> Result<Self, ErrorsTryFromf64<Self::RawReal>>;
735
736 /// Safely truncates the real number and converts it to a `usize`.
737 ///
738 /// This method first truncates the floating-point number towards zero (discarding any
739 /// fractional part) and then attempts to convert the result to a `usize`. The conversion
740 /// is fallible and returns a detailed error if the value cannot be represented as a `usize`.
741 ///
742 /// ## Behavior
743 ///
744 /// 1. **Truncation**: The fractional part is discarded, moving the value towards zero:
745 /// - `3.7` becomes `3`
746 /// - `-2.9` becomes `-2`
747 /// - `0.9` becomes `0`
748 ///
749 /// 2. **Conversion**: The truncated integer is then converted to `usize`:
750 /// - Must be non-negative (≥ 0)
751 /// - Must not exceed `usize::MAX`
752 /// - Must be finite (not NaN or infinity)
753 ///
754 /// ## Return Value
755 ///
756 /// - **`Ok(usize)`**: If the truncated value is within the valid range of `usize`
757 /// (i.e., `0 ≤ truncated_value ≤ usize::MAX`).
758 /// - **`Err(ErrorsRawRealToInteger)`**: If the conversion fails, with specific error variants:
759 /// - [`NotFinite`](ErrorsRawRealToInteger::NotFinite): The original value is `NaN` or `±∞`
760 /// - [`OutOfRange`](ErrorsRawRealToInteger::OutOfRange): The truncated value is negative or exceeds `usize::MAX`
761 ///
762 /// ## Use Cases
763 ///
764 /// This method is particularly useful for:
765 /// - Converting floating-point indices to array indices
766 /// - Converting floating-point sizes to collection capacities
767 /// - Interfacing with APIs that require `usize` parameters
768 /// - Safe downcasting from floating-point calculations to integer contexts
769 ///
770 /// ## Examples
771 ///
772 /// ### Successful Conversions
773 ///
774 /// ```rust
775 /// use num_valid::{RealNative64StrictFinite, RealScalar};
776 /// use try_create::TryNew;
777 ///
778 /// // Positive values with fractional parts
779 /// let value = RealNative64StrictFinite::try_new(42.9).unwrap();
780 /// assert_eq!(value.truncate_to_usize().unwrap(), 42);
781 ///
782 /// // Zero
783 /// let zero = RealNative64StrictFinite::try_new(0.0).unwrap();
784 /// assert_eq!(zero.truncate_to_usize().unwrap(), 0);
785 ///
786 /// // Large but valid values
787 /// let large = RealNative64StrictFinite::try_new(1_000_000.7).unwrap();
788 /// assert_eq!(large.truncate_to_usize().unwrap(), 1_000_000);
789 ///
790 /// // Positive fractional values less than 1
791 /// let small = RealNative64StrictFinite::try_new(0.9).unwrap();
792 /// assert_eq!(small.truncate_to_usize().unwrap(), 0);
793 /// ```
794 ///
795 /// ### Error Cases
796 ///
797 /// ```rust
798 /// use num_valid::{RealNative64StrictFinite, RealScalar, validation::ErrorsRawRealToInteger};
799 /// use try_create::TryNew;
800 ///
801 /// // Negative values are not valid for usize
802 /// let negative = RealNative64StrictFinite::try_new(-10.5).unwrap();
803 /// let result = negative.truncate_to_usize();
804 /// assert!(matches!(result, Err(ErrorsRawRealToInteger::OutOfRange { .. })));
805 ///
806 /// // Values that are too large for usize
807 /// let too_large = RealNative64StrictFinite::try_new(1e20).unwrap();
808 /// let result = too_large.truncate_to_usize();
809 /// assert!(matches!(result, Err(ErrorsRawRealToInteger::OutOfRange { .. })));
810 /// ```
811 ///
812 /// ### Practical Usage Example
813 ///
814 /// ```rust
815 /// use num_valid::{RealNative64StrictFinite, RealScalar};
816 /// use try_create::TryNew;
817 ///
818 /// fn create_vector_with_calculated_size<T: Default + Clone>(
819 /// size_float: RealNative64StrictFinite
820 /// ) -> Result<Vec<T>, Box<dyn std::error::Error>> {
821 /// // Safely convert the floating-point size to usize
822 /// let size = size_float.truncate_to_usize()?;
823 ///
824 /// // Create vector with the calculated size
825 /// Ok(vec![T::default(); size])
826 /// }
827 ///
828 /// // Usage
829 /// let calculated_size = RealNative64StrictFinite::try_new(10.7).unwrap();
830 /// let vec: Vec<i32> = create_vector_with_calculated_size(calculated_size).unwrap();
831 /// assert_eq!(vec.len(), 10); // Truncated from 10.7
832 /// ```
833 ///
834 /// ## Comparison with Other Conversion Methods
835 ///
836 /// | Method | Behavior | Range Check | Fractional Handling |
837 /// |--------|----------|-------------|-------------------|
838 /// | `truncate_to_usize()` | Towards zero | ✓ | Discarded |
839 /// | `as usize` (raw cast) | Undefined for out-of-range | ✗ | Undefined |
840 /// | `round().as usize` | Nearest integer | ✗ | Rounded |
841 /// | `floor().as usize` | Towards -∞ | ✗ | Discarded |
842 /// | `ceil().as usize` | Towards +∞ | ✗ | Discarded |
843 ///
844 /// ## Performance Notes
845 ///
846 /// - This method is optimized for safety over performance
847 /// - The finite check is performed first, avoiding unnecessary conversions for invalid inputs
848 /// - For performance-critical code where inputs are guaranteed to be valid, consider using
849 /// unchecked casting methods (but only after careful validation)
850 ///
851 /// ## Backend-Specific Behavior
852 ///
853 /// ### Native `f64` Backend
854 /// - Uses `az::CheckedAs` for safe conversion with overflow detection
855 /// - Leverages hardware floating-point classification
856 /// - Direct delegation to standard library truncation
857 ///
858 /// ### Arbitrary-Precision (`rug`) Backend
859 /// - Conversion respects the current precision setting
860 /// - May involve internal precision adjustments for very large numbers
861 /// - Exact integer detection when possible
862 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<Self::RawReal, usize>> {
863 let raw: Self::RawReal = self.into_inner();
864 raw.truncate_to_usize()
865 }
866}
867
868/// # Trait for scalar complex numbers
869pub trait ComplexScalar:
870 ComplexScalarMutateParts
871 + Conjugate
872 + Arg<Output = Self::RealType>
873 + for<'a> Mul<&'a Self::RealType, Output = Self>
874 + for<'a> MulAssign<&'a Self::RealType>
875 + for<'a> Pow<&'a Self::RealType, Error = PowComplexBaseRealExponentErrors<Self::RawComplex>>
876{
877 /// Scale the complex number `self` by the real coefficient `c`.
878 #[inline(always)]
879 fn scale(self, c: &Self::RealType) -> Self {
880 self * c
881 }
882
883 /// Scale (in-place) the complex number `self` by the real coefficient `c`.
884 #[inline(always)]
885 fn scale_mut(&mut self, c: &Self::RealType) {
886 *self *= c;
887 }
888}
889
890//------------------------------------------------------------------------------------------------------------
891
892//------------------------------------------------------------------------------------------------------------
893#[inline(always)]
894pub fn try_vec_f64_into_vec_real<RealType: RealScalar>(
895 vec: Vec<f64>,
896) -> Result<Vec<RealType>, ErrorsTryFromf64<RealType::RawReal>> {
897 vec.into_iter().map(|v| RealType::try_from_f64(v)).collect()
898}
899
900/// Converts the input `vec` of [`f64`] values into a vector of floating point number, as described by the generic numerical kernel `T`.
901///
902/// # Panics
903/// In debug and release mode a `panic!` will be emitted if the conversion from `f64` to `T::RealType` causes
904/// some loss of information (e.g. if the type `T` has less precision of `f64` then there is the possbility
905/// that some `f64` values cannot be exactly represented by a `T::RealType`).
906/// # Example
907/// ```
908/// use num_valid::{Native64, vec_f64_into_vec_real};
909///
910/// // Conditional compilation for the `rug` feature
911/// #[cfg(feature = "rug")]
912/// use num_valid::RealRugStrictFinite;
913///
914/// // vector of f64 values
915/// let a = vec![0., 1.];
916///
917/// let b: Vec<f64> = vec_f64_into_vec_real(a.clone());
918/// assert_eq!(b[0], 0.);
919/// assert_eq!(b[1], 1.);
920///
921///
922/// // Conditional compilation for the `rug` feature
923/// #[cfg(feature = "rug")]
924/// {
925/// const PRECISION: u32 = 100;
926/// let b: Vec<RealRugStrictFinite<PRECISION>> = vec_f64_into_vec_real(a);
927/// assert_eq!(b[0].as_ref(), &rug::Float::with_val(PRECISION, 0.));
928/// assert_eq!(b[1].as_ref(), &rug::Float::with_val(PRECISION, 1.));
929/// }
930/// ```
931#[inline(always)]
932pub fn vec_f64_into_vec_real<RealType: RealScalar>(vec: Vec<f64>) -> Vec<RealType> {
933 try_vec_f64_into_vec_real(vec).expect(
934 "The conversion from f64 to RealType failed, which should not happen in a well-defined numerical kernel."
935 )
936}
937//------------------------------------------------------------------------------------------------------------
938
939//------------------------------------------------------------------------------------------------------------
940/// A trait for types that can be randomly generated from a distribution over `f64`.
941///
942/// This trait provides a universal dispatch mechanism for generating random scalar values,
943/// allowing a single generic API to work for primitive types like [`f64`] and
944/// [`Complex<f64>`], as well as custom validated types like [`RealValidated`] and
945/// [`ComplexValidated`].
946///
947/// ## Purpose
948///
949/// The primary goal of [`RandomSampleFromF64`] is to abstract the process of creating a random
950/// scalar. Many random number distributions in the [`rand`] crate are defined to produce
951/// primitive types like `f64`. This trait acts as a bridge, allowing those same
952/// distributions to be used to generate more complex or validated types.
953///
954/// ## How It Works
955///
956/// The trait defines a single required method, [`RandomSampleFromF64::sample_from()`], which takes a reference
957/// to any distribution that implements [`rand::distr::Distribution<f64>`] and a
958/// random number generator (RNG). Each implementing type provides its own logic for
959/// this method:
960///
961/// - For `f64`, it simply samples directly from the distribution.
962/// - For `Complex<f64>`, it samples twice to create the real and imaginary parts.
963/// - For [`RealValidated<K>`], it samples an `f64` and then passes it through the
964/// validation and conversion logic of [`RealValidated::try_from_f64`].
965/// - For [`ComplexValidated<K>`], it reuses the logic for `RealValidated<K>` to sample
966/// the real and imaginary components.
967///
968/// ## Example
969///
970/// Here is how you can write a generic function that creates a vector of random numbers
971/// for any type that implements [`RandomSampleFromF64`].
972///
973/// ```rust
974/// use num_valid::{RealNative64StrictFinite, RealScalar, new_random_vec};
975/// use rand::{distr::Uniform, rngs::StdRng, Rng, SeedableRng};
976/// use try_create::IntoInner;
977///
978/// let seed = [42; 32]; // Example seed for reproducibility
979/// let mut rng = StdRng::from_seed(seed);
980/// let uniform = Uniform::new(-10.0, 10.0).unwrap();
981///
982/// // Create a vector of random f64 values.
983/// let f64_vec: Vec<f64> = new_random_vec(3, &uniform, &mut rng);
984/// assert_eq!(f64_vec.len(), 3);
985///
986/// // Create a vector of random validated real numbers using the same function.
987/// // Reset RNG to get same sequence
988/// let mut rng = StdRng::from_seed(seed);
989/// let validated_vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &uniform, &mut rng);
990/// assert_eq!(validated_vec.len(), 3);
991///
992/// // The underlying numerical values should be identical because the RNG was seeded the same.
993/// assert_eq!(&f64_vec[0], validated_vec[0].as_ref());
994/// assert_eq!(&f64_vec[1], validated_vec[1].as_ref());
995/// assert_eq!(&f64_vec[2], validated_vec[2].as_ref());
996/// ```
997pub trait RandomSampleFromF64: Sized + Clone {
998 /// Samples a single value of `Self` using the given `f64` distribution.
999 fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1000 where
1001 D: Distribution<f64>,
1002 R: Rng + ?Sized;
1003
1004 fn sample_iter_from<D, R>(dist: &D, rng: &mut R, n: usize) -> impl Iterator<Item = Self>
1005 where
1006 D: Distribution<f64>,
1007 R: Rng + ?Sized,
1008 {
1009 // Create an iterator that samples `n` values from the distribution.
1010 (0..n).map(move |_| Self::sample_from(dist, rng))
1011 }
1012}
1013
1014impl RandomSampleFromF64 for f64 {
1015 #[inline]
1016 fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1017 where
1018 D: Distribution<f64>,
1019 R: Rng + ?Sized,
1020 {
1021 // Straightforward implementation: sample a f64.
1022 dist.sample(rng)
1023 }
1024}
1025impl RandomSampleFromF64 for Complex<f64> {
1026 #[inline]
1027 fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1028 where
1029 D: Distribution<f64>,
1030 R: Rng + ?Sized,
1031 {
1032 // Sample two f64 for the real and imaginary parts.
1033 let re = dist.sample(rng);
1034 let im = dist.sample(rng);
1035 Complex::new(re, im)
1036 }
1037}
1038
1039impl<K> RandomSampleFromF64 for RealValidated<K>
1040where
1041 K: NumKernel,
1042{
1043 #[inline]
1044 fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1045 where
1046 D: Distribution<f64>,
1047 R: Rng + ?Sized,
1048 {
1049 loop {
1050 // Sample a f64 and then convert/validate it.
1051 // The loop ensures that a valid value is returned
1052 let value_f64 = dist.sample(rng);
1053 let value = RealValidated::try_from_f64(value_f64);
1054 if let Ok(validated_value) = value {
1055 return validated_value;
1056 }
1057 }
1058 }
1059}
1060
1061impl<K> RandomSampleFromF64 for ComplexValidated<K>
1062where
1063 K: NumKernel,
1064{
1065 #[inline]
1066 fn sample_from<D, R>(dist: &D, rng: &mut R) -> Self
1067 where
1068 D: Distribution<f64>,
1069 R: Rng + ?Sized,
1070 {
1071 // Reuse the RealValidated sampling logic for both parts.
1072 let re = RealValidated::<K>::sample_from(dist, rng);
1073 let im = RealValidated::<K>::sample_from(dist, rng);
1074 ComplexValidated::new_complex(re, im)
1075 }
1076}
1077
1078//------------------------------------------------------------------------------------------------------------
1079
1080//------------------------------------------------------------------------------------------------------------
1081/// Generates a `Vec<T>` of a specified length with random values.
1082///
1083/// This function leverages the [`RandomSampleFromF64`] trait to provide a universal way
1084/// to create a vector of random numbers for any supported scalar type, including
1085/// primitive types like `f64` and `Complex<f64>`, as well as validated types
1086/// like [`RealValidated`] and [`ComplexValidated`].
1087///
1088/// # Parameters
1089///
1090/// * `n`: The number of random values to generate in the vector.
1091/// * `distribution`: A reference to any distribution from the `rand` crate that
1092/// implements `Distribution<f64>` (e.g., `Uniform`, `StandardNormal`).
1093/// * `rng`: A mutable reference to a random number generator that implements `Rng`.
1094///
1095/// # Type Parameters
1096///
1097/// * `T`: The scalar type of the elements in the returned vector. Must implement [`RandomSampleFromF64`].
1098/// * `D`: The type of the distribution.
1099/// * `R`: The type of the random number generator.
1100///
1101/// # Example
1102///
1103/// # Example
1104///
1105/// ```rust
1106/// use num_valid::{new_random_vec, RealNative64StrictFinite};
1107/// use rand::{distr::Uniform, rngs::StdRng, SeedableRng};
1108/// use try_create::IntoInner;
1109///
1110/// let seed = [42; 32]; // Use a fixed seed for a reproducible example
1111///
1112/// // Generate a vector of random f64 values.
1113/// let mut rng_f64 = StdRng::from_seed(seed);
1114/// let uniform = Uniform::new(-10.0, 10.0).unwrap();
1115/// let f64_vec: Vec<f64> = new_random_vec(3, &uniform, &mut rng_f64);
1116///
1117/// // Generate a vector of random validated real numbers using the same seed.
1118/// let mut rng_validated = StdRng::from_seed(seed);
1119/// let validated_vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &uniform, &mut rng_validated);
1120///
1121/// assert_eq!(f64_vec.len(), 3);
1122/// assert_eq!(validated_vec.len(), 3);
1123///
1124/// // The underlying numerical values should be identical because the RNG was seeded the same.
1125/// assert_eq!(&f64_vec[0], validated_vec[0].as_ref());
1126/// assert_eq!(&f64_vec[1], validated_vec[1].as_ref());
1127/// assert_eq!(&f64_vec[2], validated_vec[2].as_ref());
1128/// ```
1129pub fn new_random_vec<T, D, R>(n: usize, distribution: &D, rng: &mut R) -> Vec<T>
1130where
1131 T: RandomSampleFromF64,
1132 D: Distribution<f64>,
1133 R: Rng + ?Sized,
1134{
1135 T::sample_iter_from(distribution, rng, n).collect()
1136}
1137//------------------------------------------------------------------------------------------------------------
1138
1139//------------------------------------------------------------------------------------------------------------
1140#[cfg(test)]
1141mod tests {
1142 use super::*;
1143 use num::Complex;
1144 use num_traits::MulAddAssign;
1145 use std::ops::{Add, Div, Sub};
1146
1147 mod functions_general_type {
1148 use super::*;
1149
1150 fn test_recip<RealType: RealScalar>() {
1151 let a = RealType::two();
1152
1153 let a = a.try_reciprocal().unwrap();
1154 let expected = RealType::one_div_2();
1155 assert_eq!(a, expected);
1156 }
1157
1158 fn test_zero<RealType: RealScalar>() {
1159 let a = RealType::zero();
1160
1161 assert_eq!(a, 0.0);
1162 }
1163
1164 fn test_one<RealType: RealScalar>() {
1165 let a = RealType::one();
1166
1167 assert_eq!(a, 1.0);
1168 }
1169
1170 fn test_add<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1171 where
1172 for<'a> &'a ScalarType:
1173 Add<ScalarType, Output = ScalarType> + Add<&'a ScalarType, Output = ScalarType>,
1174 {
1175 let c = a.clone() + &b;
1176 assert_eq!(c, c_expected);
1177
1178 let c = &a + b.clone();
1179 assert_eq!(c, c_expected);
1180
1181 let c = a.clone() + b.clone();
1182 assert_eq!(c, c_expected);
1183
1184 let c = &a + &b;
1185 assert_eq!(c, c_expected);
1186 }
1187
1188 fn test_sub<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1189 where
1190 for<'a> &'a ScalarType:
1191 Sub<ScalarType, Output = ScalarType> + Sub<&'a ScalarType, Output = ScalarType>,
1192 {
1193 let c = a.clone() - &b;
1194 assert_eq!(c, c_expected);
1195
1196 let c = &a - b.clone();
1197 assert_eq!(c, c_expected);
1198
1199 let c = a.clone() - b.clone();
1200 assert_eq!(c, c_expected);
1201
1202 let c = &a - &b;
1203 assert_eq!(c, c_expected);
1204 }
1205
1206 fn test_mul<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1207 where
1208 for<'a> &'a ScalarType:
1209 Mul<ScalarType, Output = ScalarType> + Mul<&'a ScalarType, Output = ScalarType>,
1210 {
1211 let c = a.clone() * &b;
1212 assert_eq!(c, c_expected);
1213
1214 let c = &a * b.clone();
1215 assert_eq!(c, c_expected);
1216
1217 let c = a.clone() * b.clone();
1218 assert_eq!(c, c_expected);
1219
1220 let c = &a * &b;
1221 assert_eq!(c, c_expected);
1222 }
1223
1224 fn test_div<ScalarType: FpScalar>(a: ScalarType, b: ScalarType, c_expected: ScalarType)
1225 where
1226 for<'a> &'a ScalarType:
1227 Div<ScalarType, Output = ScalarType> + Div<&'a ScalarType, Output = ScalarType>,
1228 {
1229 let c = a.clone() / &b;
1230 assert_eq!(c, c_expected);
1231
1232 let c = &a / b.clone();
1233 assert_eq!(c, c_expected);
1234
1235 let c = a.clone() / b.clone();
1236 assert_eq!(c, c_expected);
1237
1238 let c = &a / &b;
1239 assert_eq!(c, c_expected);
1240 }
1241
1242 fn test_mul_complex_with_real<ComplexType: ComplexScalar>(
1243 a: ComplexType,
1244 b: ComplexType::RealType,
1245 a_times_b_expected: ComplexType,
1246 ) {
1247 let a_times_b = a.clone().scale(&b);
1248 assert_eq!(a_times_b, a_times_b_expected);
1249
1250 let a_times_b = a.clone() * &b;
1251 assert_eq!(a_times_b, a_times_b_expected);
1252
1253 /*
1254 let b_times_a_expected = a_times_b_expected.clone();
1255
1256 let b_times_a = &b * a.clone();
1257 assert_eq!(b_times_a, b_times_a_expected);
1258
1259 let b_times_a = b.clone() * a.clone();
1260 assert_eq!(b_times_a, b_times_a_expected);
1261 */
1262 }
1263
1264 fn test_mul_assign_complex_with_real<ComplexType: ComplexScalar>(
1265 a: ComplexType,
1266 b: ComplexType::RealType,
1267 a_times_b_expected: ComplexType,
1268 ) {
1269 let mut a_times_b = a.clone();
1270 a_times_b.scale_mut(&b);
1271 assert_eq!(a_times_b, a_times_b_expected);
1272
1273 // let mut a_times_b = a.clone();
1274 // a_times_b *= b;
1275 // assert_eq!(a_times_b, a_times_b_expected);
1276 }
1277
1278 fn test_neg_assign_real<RealType: RealScalar>() {
1279 let mut a = RealType::one();
1280 a.neg_assign();
1281
1282 let a_expected = RealType::try_from_f64(-1.).unwrap();
1283 assert_eq!(a, a_expected);
1284 }
1285
1286 fn test_add_assign_real<RealType: RealScalar>() {
1287 let mut a = RealType::try_from_f64(1.0).unwrap();
1288 let b = RealType::try_from_f64(2.0).unwrap();
1289
1290 a += &b;
1291 let a_expected = RealType::try_from_f64(3.0).unwrap();
1292 assert_eq!(a, a_expected);
1293
1294 a += b;
1295 let a_expected = RealType::try_from_f64(5.0).unwrap();
1296 assert_eq!(a, a_expected);
1297 }
1298
1299 fn test_sub_assign_real<RealType: RealScalar>() {
1300 let mut a = RealType::try_from_f64(1.0).unwrap();
1301 let b = RealType::try_from_f64(2.0).unwrap();
1302
1303 a -= &b;
1304 let a_expected = RealType::try_from_f64(-1.0).unwrap();
1305 assert_eq!(a, a_expected);
1306
1307 a -= b;
1308 let a_expected = RealType::try_from_f64(-3.0).unwrap();
1309 assert_eq!(a, a_expected);
1310 }
1311
1312 fn test_mul_assign_real<RealType: RealScalar>() {
1313 let mut a = RealType::try_from_f64(1.0).unwrap();
1314 let b = RealType::try_from_f64(2.0).unwrap();
1315
1316 a *= &b;
1317 let a_expected = RealType::try_from_f64(2.0).unwrap();
1318 assert_eq!(a, a_expected);
1319
1320 a *= b;
1321 let a_expected = RealType::try_from_f64(4.0).unwrap();
1322 assert_eq!(a, a_expected);
1323 }
1324
1325 fn test_div_assign_real<RealType: RealScalar>() {
1326 let mut a = RealType::try_from_f64(4.0).unwrap();
1327 let b = RealType::try_from_f64(2.0).unwrap();
1328
1329 a /= &b;
1330 let a_expected = RealType::try_from_f64(2.0).unwrap();
1331 assert_eq!(a, a_expected);
1332
1333 a /= b;
1334 let a_expected = RealType::try_from_f64(1.0).unwrap();
1335 assert_eq!(a, a_expected);
1336 }
1337
1338 fn test_mul_add_ref_real<RealType: RealScalar>() {
1339 let a = RealType::try_from_f64(2.0).unwrap();
1340 let b = RealType::try_from_f64(3.0).unwrap();
1341 let c = RealType::try_from_f64(1.0).unwrap();
1342
1343 let d_expected = RealType::try_from_f64(7.0).unwrap();
1344
1345 let d = a.mul_add_ref(&b, &c);
1346 assert_eq!(d, d_expected);
1347 }
1348
1349 fn test_sin_real<RealType: RealScalar>() {
1350 let a = RealType::zero();
1351
1352 let a = a.sin();
1353 let expected = RealType::zero();
1354 assert_eq!(a, expected);
1355 }
1356
1357 fn test_cos_real<RealType: RealScalar>() {
1358 let a = RealType::zero();
1359
1360 let a = a.cos();
1361 let expected = RealType::one();
1362 assert_eq!(a, expected);
1363 }
1364
1365 fn test_abs_real<RealType: RealScalar>() {
1366 let a = RealType::try_from_f64(-1.).unwrap();
1367
1368 let abs: RealType = a.abs();
1369 let expected = RealType::one();
1370 assert_eq!(abs, expected);
1371 }
1372
1373 mod native64 {
1374 use super::*;
1375
1376 mod real {
1377 use super::*;
1378
1379 #[test]
1380 fn zero() {
1381 test_zero::<f64>();
1382 }
1383
1384 #[test]
1385 fn one() {
1386 test_one::<f64>();
1387 }
1388
1389 #[test]
1390 fn recip() {
1391 test_recip::<f64>();
1392 }
1393
1394 #[test]
1395 fn add() {
1396 let a = 1.0;
1397 let b = 2.0;
1398 let c_expected = 3.0;
1399 test_add(a, b, c_expected);
1400 }
1401
1402 #[test]
1403 fn sub() {
1404 let a = 1.0;
1405 let b = 2.0;
1406 let c_expected = -1.0;
1407 test_sub(a, b, c_expected);
1408 }
1409
1410 #[test]
1411 fn mul() {
1412 let a = 2.0;
1413 let b = 3.0;
1414 let c_expected = 6.0;
1415 test_mul(a, b, c_expected);
1416 }
1417
1418 #[test]
1419 fn div() {
1420 let a = 6.;
1421 let b = 2.;
1422 let c_expected = 3.;
1423 test_div(a, b, c_expected);
1424 }
1425
1426 #[test]
1427 fn neg_assign() {
1428 test_neg_assign_real::<f64>();
1429 }
1430
1431 #[test]
1432 fn add_assign() {
1433 test_add_assign_real::<f64>();
1434 }
1435
1436 #[test]
1437 fn sub_assign() {
1438 test_sub_assign_real::<f64>();
1439 }
1440
1441 #[test]
1442 fn mul_assign() {
1443 test_mul_assign_real::<f64>();
1444 }
1445
1446 #[test]
1447 fn div_assign() {
1448 test_div_assign_real::<f64>();
1449 }
1450 #[test]
1451 fn mul_add_ref() {
1452 test_mul_add_ref_real::<f64>();
1453 }
1454
1455 #[test]
1456 fn from_f64() {
1457 let v_native64 = f64::try_from_f64(16.25).unwrap();
1458 assert_eq!(v_native64, 16.25);
1459 }
1460
1461 #[test]
1462 fn abs() {
1463 test_abs_real::<f64>();
1464 }
1465
1466 #[test]
1467 fn acos() {
1468 let a = 0.;
1469
1470 let pi_over_2 = a.acos();
1471 let expected = std::f64::consts::FRAC_PI_2;
1472 assert_eq!(pi_over_2, expected);
1473 }
1474
1475 #[test]
1476 fn asin() {
1477 let a = 1.;
1478
1479 let pi_over_2 = a.asin();
1480 let expected = std::f64::consts::FRAC_PI_2;
1481 assert_eq!(pi_over_2, expected);
1482 }
1483
1484 #[test]
1485 fn cos() {
1486 test_cos_real::<f64>();
1487 }
1488
1489 #[test]
1490 fn sin() {
1491 test_sin_real::<f64>();
1492 }
1493
1494 #[test]
1495 fn test_acos() {
1496 let value: f64 = 0.5;
1497 let result = value.acos();
1498 assert_eq!(result, value.acos());
1499 }
1500
1501 #[test]
1502 fn test_acosh() {
1503 let value: f64 = 1.5;
1504 let result = value.acosh();
1505 assert_eq!(result, value.acosh());
1506 }
1507
1508 #[test]
1509 fn test_asin() {
1510 let value: f64 = 0.5;
1511 let result = value.asin();
1512 assert_eq!(result, value.asin());
1513 }
1514
1515 #[test]
1516 fn test_asinh() {
1517 let value: f64 = 0.5;
1518 let result = value.asinh();
1519 assert_eq!(result, value.asinh());
1520 }
1521
1522 #[test]
1523 fn test_atan() {
1524 let value: f64 = 0.5;
1525 let result = value.atan();
1526 assert_eq!(result, value.atan());
1527 }
1528
1529 #[test]
1530 fn test_atanh() {
1531 let value: f64 = 0.5;
1532 let result = value.atanh();
1533 assert_eq!(result, value.atanh());
1534 }
1535
1536 #[test]
1537 fn test_cos_02() {
1538 let value: f64 = 0.5;
1539 let result = value.cos();
1540 assert_eq!(result, value.cos());
1541 }
1542
1543 #[test]
1544 fn test_cosh() {
1545 let value: f64 = 0.5;
1546 let result = value.cosh();
1547 assert_eq!(result, value.cosh());
1548 }
1549
1550 #[test]
1551 fn test_exp() {
1552 let value: f64 = 0.5;
1553 let result = value.exp();
1554 println!("result = {result:?}");
1555
1556 assert_eq!(result, value.exp());
1557 }
1558
1559 #[test]
1560 fn test_is_finite() {
1561 let value: f64 = 0.5;
1562 assert!(value.is_finite());
1563
1564 let value: f64 = f64::INFINITY;
1565 assert!(!value.is_finite());
1566 }
1567
1568 #[test]
1569 fn test_is_infinite() {
1570 let value: f64 = f64::INFINITY;
1571 assert!(value.is_infinite());
1572
1573 let value: f64 = 0.5;
1574 assert!(!value.is_infinite());
1575 }
1576
1577 #[test]
1578 fn test_ln() {
1579 let value: f64 = std::f64::consts::E;
1580 let result = value.ln();
1581 println!("result = {result:?}");
1582 assert_eq!(result, value.ln());
1583 }
1584
1585 #[test]
1586 fn test_log10() {
1587 let value: f64 = 10.0;
1588 let result = value.log10();
1589 println!("result = {result:?}");
1590 assert_eq!(result, value.log10());
1591 }
1592
1593 #[test]
1594 fn test_log2() {
1595 let value: f64 = 8.0;
1596 let result = value.log2();
1597 println!("result = {result:?}");
1598 assert_eq!(result, value.log2());
1599 }
1600
1601 #[test]
1602 fn test_recip_02() {
1603 let value: f64 = 2.0;
1604 let result = value.try_reciprocal().unwrap();
1605 assert_eq!(result, value.recip());
1606 }
1607
1608 #[test]
1609 fn test_sin_02() {
1610 let value: f64 = 0.5;
1611 let result = value.sin();
1612 assert_eq!(result, value.sin());
1613 }
1614
1615 #[test]
1616 fn test_sinh() {
1617 let value: f64 = 0.5;
1618 let result = value.sinh();
1619 assert_eq!(result, value.sinh());
1620 }
1621
1622 #[test]
1623 fn sqrt() {
1624 let value: f64 = 4.0;
1625 let result = value.sqrt();
1626 assert_eq!(result, value.sqrt());
1627 }
1628
1629 #[test]
1630 fn try_sqrt() {
1631 let value: f64 = 4.0;
1632 let result = value.try_sqrt().unwrap();
1633 assert_eq!(result, value.sqrt());
1634
1635 assert!((-1.0).try_sqrt().is_err());
1636 }
1637
1638 #[test]
1639 fn test_tan() {
1640 let value: f64 = 0.5;
1641 let result = value.tan();
1642 assert_eq!(result, value.tan());
1643 }
1644
1645 #[test]
1646 fn test_tanh() {
1647 let value: f64 = 0.5;
1648 let result = value.tanh();
1649 assert_eq!(result, value.tanh());
1650 }
1651 }
1652
1653 mod complex {
1654 use super::*;
1655
1656 #[test]
1657 fn add() {
1658 let a = Complex::new(1., 2.);
1659 let b = Complex::new(3., 4.);
1660
1661 let c_expected = Complex::new(4., 6.);
1662
1663 test_add(a, b, c_expected);
1664 }
1665
1666 #[test]
1667 fn sub() {
1668 let a = Complex::new(3., 2.);
1669 let b = Complex::new(1., 4.);
1670
1671 let c_expected = Complex::new(2., -2.);
1672
1673 test_sub(a, b, c_expected);
1674 }
1675
1676 #[test]
1677 fn mul() {
1678 let a = Complex::new(3., 2.);
1679 let b = Complex::new(1., 4.);
1680 let c_expected = Complex::new(-5., 14.);
1681 test_mul(a, b, c_expected);
1682 }
1683
1684 #[test]
1685 fn div() {
1686 let a = Complex::new(-5., 14.);
1687 let b = Complex::new(1., 4.);
1688
1689 let c_expected = Complex::new(3., 2.);
1690
1691 test_div(a, b, c_expected);
1692 }
1693
1694 #[test]
1695 fn add_assign() {
1696 let mut a = Complex::new(1., 2.);
1697 let b = Complex::new(3., 4.);
1698
1699 a += &b;
1700 let a_expected = Complex::new(4., 6.);
1701 assert_eq!(a, a_expected);
1702
1703 a += b;
1704 let a_expected = Complex::new(7., 10.);
1705 assert_eq!(a, a_expected);
1706 }
1707
1708 #[test]
1709 fn sub_assign() {
1710 let mut a = Complex::new(3., 2.);
1711 let b = Complex::new(2., 4.);
1712
1713 a -= &b;
1714 let a_expected = Complex::new(1., -2.);
1715 assert_eq!(a, a_expected);
1716
1717 a -= b;
1718 let a_expected = Complex::new(-1., -6.);
1719 assert_eq!(a, a_expected);
1720 }
1721
1722 #[test]
1723 fn mul_assign() {
1724 let mut a = Complex::new(3., 2.);
1725 let b = Complex::new(2., 4.);
1726
1727 a *= &b;
1728 let a_expected = Complex::new(-2., 16.);
1729 assert_eq!(a, a_expected);
1730
1731 a *= b;
1732 let a_expected = Complex::new(-68., 24.);
1733 assert_eq!(a, a_expected);
1734 }
1735
1736 #[test]
1737 fn div_assign() {
1738 let mut a = Complex::new(-68., 24.);
1739 let b = Complex::new(2., 4.);
1740
1741 a /= &b;
1742 let a_expected = Complex::new(-2., 16.);
1743 assert_eq!(a, a_expected);
1744
1745 a /= b;
1746 let a_expected = Complex::new(3., 2.);
1747 assert_eq!(a, a_expected);
1748 }
1749
1750 #[test]
1751 fn from_f64() {
1752 let v = Complex::new(16.25, 2.);
1753 assert_eq!(v.real_part(), 16.25);
1754 assert_eq!(v.imag_part(), 2.);
1755 }
1756
1757 #[test]
1758 fn conj() {
1759 let v = Complex::new(16.25, 2.);
1760
1761 let v_conj = v.conjugate();
1762 assert_eq!(v_conj.real_part(), 16.25);
1763 assert_eq!(v_conj.imag_part(), -2.);
1764 }
1765
1766 #[test]
1767 fn neg_assign() {
1768 let mut a = Complex::new(1., 2.);
1769 a.neg_assign();
1770
1771 let a_expected = Complex::new(-1., -2.);
1772 assert_eq!(a, a_expected);
1773 }
1774
1775 #[test]
1776 fn abs() {
1777 let a = Complex::new(-3., 4.);
1778
1779 let abs = a.abs();
1780 let expected = 5.;
1781 assert_eq!(abs, expected);
1782 }
1783
1784 #[test]
1785 fn mul_add_ref() {
1786 let a = Complex::new(2., -3.);
1787 let b = Complex::new(3., 1.);
1788 let c = Complex::new(1., -4.);
1789
1790 let d_expected = Complex::new(10., -11.);
1791
1792 let d = a.mul_add_ref(&b, &c);
1793 assert_eq!(d, d_expected);
1794 }
1795
1796 #[test]
1797 fn mul_complex_with_real() {
1798 let a = Complex::new(1., 2.);
1799 let b = 3.;
1800
1801 let a_times_b_expected = Complex::new(3., 6.);
1802
1803 test_mul_complex_with_real(a, b, a_times_b_expected);
1804 }
1805
1806 #[test]
1807 fn mul_assign_complex_with_real() {
1808 let a = Complex::new(1., 2.);
1809 let b = 3.;
1810
1811 let a_times_b_expected = Complex::new(3., 6.);
1812
1813 test_mul_assign_complex_with_real(a, b, a_times_b_expected);
1814 }
1815
1816 #[test]
1817 fn test_acos() {
1818 let value: Complex<f64> = Complex::new(0.5, 0.5);
1819 let result = value.acos();
1820 assert_eq!(result, value.acos());
1821 }
1822
1823 #[test]
1824 fn test_acosh() {
1825 let value: Complex<f64> = Complex::new(1.5, 0.5);
1826 let result = value.acosh();
1827 assert_eq!(result, value.acosh());
1828 }
1829
1830 #[test]
1831 fn test_asin() {
1832 let value: Complex<f64> = Complex::new(0.5, 0.5);
1833 let result = value.asin();
1834 assert_eq!(result, value.asin());
1835 }
1836
1837 #[test]
1838 fn test_asinh() {
1839 let value: Complex<f64> = Complex::new(0.5, 0.5);
1840 let result = value.asinh();
1841 assert_eq!(result, value.asinh());
1842 }
1843
1844 #[test]
1845 fn test_atan() {
1846 let value: Complex<f64> = Complex::new(0.5, 0.5);
1847 let result = value.atan();
1848 assert_eq!(result, value.atan());
1849 }
1850
1851 #[test]
1852 fn test_atanh() {
1853 let value: Complex<f64> = Complex::new(0.5, 0.5);
1854 let result = value.atanh();
1855 assert_eq!(result, value.atanh());
1856 }
1857
1858 #[test]
1859 fn test_cos_01() {
1860 let value: Complex<f64> = Complex::new(0.5, 0.5);
1861 let result = value.cos();
1862 assert_eq!(result, value.cos());
1863 }
1864
1865 #[test]
1866 fn test_cosh() {
1867 let value: Complex<f64> = Complex::new(0.5, 0.5);
1868 let result = value.cosh();
1869 assert_eq!(result, value.cosh());
1870 }
1871
1872 #[test]
1873 fn test_exp() {
1874 let value: Complex<f64> = Complex::new(0.5, 0.5);
1875 let result = value.exp();
1876 println!("result = {result:?}");
1877 assert_eq!(result, value.exp());
1878 }
1879
1880 /*
1881 #[test]
1882 fn test_is_finite() {
1883 let value: Complex<f64> = Complex::new(0.5, 0.5);
1884 assert!(value.is_finite());
1885
1886 let value: Complex<f64> = Complex::new(f64::INFINITY, 0.5);
1887 assert!(!value.is_finite());
1888 }
1889
1890 #[test]
1891 fn test_is_infinite() {
1892 let value: Complex<f64> = Complex::new(f64::INFINITY, 0.5);
1893 assert!(value.is_infinite());
1894
1895 let value: Complex<f64> = Complex::new(0.5, 0.5);
1896 assert!(!value.is_infinite());
1897 }
1898 */
1899
1900 #[test]
1901 fn test_ln() {
1902 let value: Complex<f64> = Complex::new(std::f64::consts::E, 1.0);
1903 let result = value.ln();
1904 println!("result = {result:?}");
1905 assert_eq!(result, value.ln());
1906 }
1907
1908 #[test]
1909 fn test_log10() {
1910 let value: Complex<f64> = Complex::new(10.0, 1.0);
1911 let result = value.log10();
1912 println!("result = {result:?}");
1913 assert_eq!(result, value.log10());
1914 }
1915
1916 #[test]
1917 fn test_log2() {
1918 let value: Complex<f64> = Complex::new(8.0, 1.0);
1919 let result = value.log2();
1920 println!("result = {result:?}");
1921 assert_eq!(result, value.log2());
1922 }
1923
1924 #[test]
1925 fn test_recip() {
1926 let value: Complex<f64> = Complex::new(2.0, 0.0);
1927 let result = value.try_reciprocal().unwrap();
1928 assert_eq!(result, value.finv());
1929 }
1930
1931 #[test]
1932 fn test_sin_01() {
1933 let value: Complex<f64> = Complex::new(0.5, 0.5);
1934 let result = value.sin();
1935 assert_eq!(result, value.sin());
1936 }
1937
1938 #[test]
1939 fn test_sinh() {
1940 let value: Complex<f64> = Complex::new(0.5, 0.5);
1941 let result = value.sinh();
1942 assert_eq!(result, value.sinh());
1943 }
1944
1945 #[test]
1946 fn sqrt() {
1947 let value: Complex<f64> = Complex::new(4.0, 1.0);
1948 let result = value.sqrt();
1949 assert_eq!(result, value.sqrt());
1950 }
1951
1952 #[test]
1953 fn try_sqrt() {
1954 let value: Complex<f64> = Complex::new(4.0, 1.0);
1955 let result = value.try_sqrt().unwrap();
1956 assert_eq!(result, value.sqrt());
1957 }
1958
1959 #[test]
1960 fn test_tan() {
1961 let value: Complex<f64> = Complex::new(0.5, 0.5);
1962 let result = value.tan();
1963 assert_eq!(result, value.tan());
1964 }
1965
1966 #[test]
1967 fn test_tanh() {
1968 let value: Complex<f64> = Complex::new(0.5, 0.5);
1969 let result = value.tanh();
1970 assert_eq!(result, value.tanh());
1971 }
1972 }
1973 }
1974
1975 #[cfg(feature = "rug")]
1976 mod rug_ {
1977 use super::*;
1978 use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite};
1979 use rug::ops::CompleteRound;
1980 use try_create::{IntoInner, TryNew};
1981
1982 const PRECISION: u32 = 100;
1983
1984 mod real {
1985 use super::*;
1986 use rug::Float;
1987
1988 #[test]
1989 fn zero() {
1990 test_zero::<RealRugStrictFinite<64>>();
1991 test_zero::<RealRugStrictFinite<PRECISION>>();
1992 }
1993
1994 #[test]
1995 fn one() {
1996 test_one::<RealRugStrictFinite<64>>();
1997 test_one::<RealRugStrictFinite<PRECISION>>();
1998 }
1999
2000 #[test]
2001 fn recip() {
2002 test_recip::<RealRugStrictFinite<64>>();
2003 test_recip::<RealRugStrictFinite<PRECISION>>();
2004 }
2005
2006 #[test]
2007 fn add() {
2008 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
2009 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2010 let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
2011 test_add(a, b, c_expected);
2012 }
2013
2014 #[test]
2015 fn sub() {
2016 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
2017 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2018 let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
2019 test_sub(a, b, c_expected);
2020 }
2021
2022 #[test]
2023 fn mul() {
2024 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2025 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
2026 let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(6.0).unwrap();
2027 test_mul(a, b, c_expected);
2028 }
2029
2030 #[test]
2031 fn div() {
2032 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(6.).unwrap();
2033 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.).unwrap();
2034 let c_expected = RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap();
2035
2036 test_div(a, b, c_expected);
2037 }
2038
2039 #[test]
2040 fn neg_assign() {
2041 test_neg_assign_real::<RealRugStrictFinite<PRECISION>>();
2042 }
2043
2044 #[test]
2045 fn add_assign() {
2046 test_add_assign_real::<RealRugStrictFinite<PRECISION>>();
2047 }
2048
2049 #[test]
2050 fn sub_assign() {
2051 test_sub_assign_real::<RealRugStrictFinite<PRECISION>>();
2052 }
2053
2054 #[test]
2055 fn mul_assign() {
2056 test_mul_assign_real::<RealRugStrictFinite<PRECISION>>();
2057 }
2058
2059 #[test]
2060 fn div_assign() {
2061 test_div_assign_real::<RealRugStrictFinite<PRECISION>>();
2062 }
2063
2064 #[test]
2065 fn mul_add_ref() {
2066 test_mul_add_ref_real::<RealRugStrictFinite<PRECISION>>();
2067 }
2068
2069 #[test]
2070 fn abs() {
2071 test_abs_real::<RealRugStrictFinite<PRECISION>>();
2072 }
2073
2074 #[test]
2075 fn acos() {
2076 {
2077 let a = RealRugStrictFinite::<53>::zero();
2078 let pi_over_2 = RealRugStrictFinite::<53>::acos(a);
2079 let expected = rug::Float::with_val(53, std::f64::consts::FRAC_PI_2);
2080 assert_eq!(pi_over_2.as_ref(), &expected);
2081 }
2082 {
2083 let a = RealRugStrictFinite::<100>::zero();
2084 let pi_over_2 = RealRugStrictFinite::<100>::acos(a);
2085 let expected = rug::Float::with_val(
2086 100,
2087 rug::Float::parse("1.5707963267948966192313216916397").unwrap(),
2088 );
2089 assert_eq!(pi_over_2.as_ref(), &expected);
2090 }
2091 }
2092
2093 #[test]
2094 fn asin() {
2095 {
2096 let a = RealRugStrictFinite::<53>::one();
2097 let pi_over_2 = RealRugStrictFinite::<53>::asin(a);
2098 let expected = rug::Float::with_val(53, std::f64::consts::FRAC_PI_2);
2099 assert_eq!(pi_over_2.as_ref(), &expected);
2100 }
2101 {
2102 let a = RealRugStrictFinite::<100>::one();
2103 let pi_over_2 = RealRugStrictFinite::<100>::asin(a);
2104 let expected = rug::Float::with_val(
2105 100,
2106 rug::Float::parse("1.5707963267948966192313216916397").unwrap(),
2107 );
2108 assert_eq!(pi_over_2.as_ref(), &expected);
2109 }
2110 }
2111
2112 #[test]
2113 fn cos() {
2114 test_cos_real::<RealRugStrictFinite<64>>();
2115 test_cos_real::<RealRugStrictFinite<PRECISION>>();
2116 }
2117
2118 #[test]
2119 fn sin() {
2120 test_sin_real::<RealRugStrictFinite<64>>();
2121 test_sin_real::<RealRugStrictFinite<PRECISION>>();
2122 }
2123
2124 #[test]
2125 fn dot_product() {
2126 let a = &[
2127 RealRugStrictFinite::<100>::one(),
2128 RealRugStrictFinite::<100>::try_from_f64(2.).unwrap(),
2129 ];
2130
2131 let b = &[
2132 RealRugStrictFinite::<100>::try_from_f64(2.).unwrap(),
2133 RealRugStrictFinite::<100>::try_from_f64(-1.).unwrap(),
2134 ];
2135
2136 let a: Vec<_> = a.iter().map(|a_i| a_i.as_ref()).collect();
2137 let b: Vec<_> = b.iter().map(|b_i| b_i.as_ref()).collect();
2138
2139 let value = RealRugStrictFinite::<100>::try_new(
2140 rug::Float::dot(a.into_iter().zip(b)).complete(100),
2141 )
2142 .unwrap();
2143
2144 assert_eq!(value.as_ref(), &rug::Float::with_val(100, 0.));
2145 }
2146 #[test]
2147 fn test_acos() {
2148 let value =
2149 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2150 .unwrap();
2151 let result = value.clone().acos();
2152 assert_eq!(
2153 result,
2154 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2155 PRECISION,
2156 value.into_inner().acos()
2157 ))
2158 .unwrap()
2159 );
2160 }
2161
2162 #[test]
2163 fn test_acosh() {
2164 let value =
2165 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.5))
2166 .unwrap();
2167 let result = value.clone().acosh();
2168 assert_eq!(
2169 result,
2170 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2171 PRECISION,
2172 value.into_inner().acosh()
2173 ))
2174 .unwrap()
2175 );
2176 }
2177
2178 #[test]
2179 fn test_asin() {
2180 let value =
2181 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2182 .unwrap();
2183 let result = value.clone().asin();
2184 assert_eq!(
2185 result,
2186 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2187 PRECISION,
2188 value.into_inner().asin()
2189 ))
2190 .unwrap()
2191 );
2192 }
2193
2194 #[test]
2195 fn test_asinh() {
2196 let value =
2197 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2198 .unwrap();
2199 let result = value.clone().asinh();
2200 assert_eq!(
2201 result,
2202 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2203 PRECISION,
2204 value.into_inner().asinh()
2205 ))
2206 .unwrap()
2207 );
2208 }
2209
2210 #[test]
2211 fn test_atan() {
2212 let value =
2213 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2214 .unwrap();
2215 let result = value.clone().atan();
2216 assert_eq!(
2217 result,
2218 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2219 PRECISION,
2220 value.into_inner().atan()
2221 ))
2222 .unwrap()
2223 );
2224 }
2225
2226 #[test]
2227 fn test_atanh() {
2228 let value =
2229 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2230 .unwrap();
2231 let result = value.clone().atanh();
2232 assert_eq!(
2233 result,
2234 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2235 PRECISION,
2236 value.into_inner().atanh()
2237 ))
2238 .unwrap()
2239 );
2240 }
2241
2242 #[test]
2243 fn test_cos_02() {
2244 let value =
2245 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2246 .unwrap();
2247 let result = value.clone().cos();
2248 assert_eq!(
2249 result,
2250 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2251 PRECISION,
2252 value.into_inner().cos()
2253 ))
2254 .unwrap()
2255 );
2256 }
2257
2258 #[test]
2259 fn test_cosh() {
2260 let value =
2261 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2262 .unwrap();
2263 let result = value.clone().cosh();
2264 assert_eq!(
2265 result,
2266 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2267 PRECISION,
2268 value.into_inner().cosh()
2269 ))
2270 .unwrap()
2271 );
2272 }
2273
2274 #[test]
2275 fn test_exp() {
2276 let value =
2277 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2278 .unwrap();
2279 let result = value.clone().exp();
2280 println!("result = {result:?}");
2281 assert_eq!(
2282 result,
2283 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2284 PRECISION,
2285 value.into_inner().exp()
2286 ))
2287 .unwrap()
2288 );
2289 }
2290
2291 #[test]
2292 fn test_is_finite() {
2293 let value =
2294 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2295 .unwrap();
2296 assert!(value.is_finite());
2297
2298 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2299 PRECISION,
2300 f64::INFINITY,
2301 ));
2302 assert!(value.is_err());
2303 }
2304
2305 #[test]
2306 fn test_is_infinite() {
2307 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2308 PRECISION,
2309 f64::INFINITY,
2310 ));
2311 assert!(value.is_err());
2312
2313 let value =
2314 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2315 .unwrap();
2316 assert!(!value.is_infinite());
2317 }
2318
2319 #[test]
2320 fn test_ln() {
2321 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2322 PRECISION,
2323 std::f64::consts::E,
2324 ))
2325 .unwrap();
2326 let result = value.clone().ln();
2327 println!("result = {result:?}");
2328 assert_eq!(
2329 result,
2330 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2331 PRECISION,
2332 value.into_inner().ln()
2333 ))
2334 .unwrap()
2335 );
2336 }
2337
2338 #[test]
2339 fn test_log10() {
2340 let value =
2341 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 10.0))
2342 .unwrap();
2343 let result = value.clone().log10();
2344 println!("result = {result:?}");
2345 assert_eq!(
2346 result,
2347 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2348 PRECISION,
2349 value.into_inner().log10()
2350 ))
2351 .unwrap()
2352 );
2353 }
2354
2355 #[test]
2356 fn test_log2() {
2357 let value =
2358 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 8.0))
2359 .unwrap();
2360 let result = value.clone().log2();
2361 println!("result = {result:?}");
2362 assert_eq!(
2363 result,
2364 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2365 PRECISION,
2366 value.into_inner().log2()
2367 ))
2368 .unwrap()
2369 );
2370 }
2371
2372 #[test]
2373 fn test_recip_02() {
2374 let value =
2375 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
2376 .unwrap();
2377 let result = value.clone().try_reciprocal().unwrap();
2378 assert_eq!(
2379 result,
2380 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2381 PRECISION,
2382 value.into_inner().recip()
2383 ))
2384 .unwrap()
2385 );
2386 }
2387
2388 #[test]
2389 fn test_sin_02() {
2390 let value =
2391 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2392 .unwrap();
2393 let result = value.clone().sin();
2394 assert_eq!(
2395 result,
2396 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2397 PRECISION,
2398 value.into_inner().sin()
2399 ))
2400 .unwrap()
2401 );
2402 }
2403
2404 #[test]
2405 fn test_sinh() {
2406 let value =
2407 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2408 .unwrap();
2409 let result = value.clone().sinh();
2410 assert_eq!(
2411 result,
2412 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2413 PRECISION,
2414 value.into_inner().sinh()
2415 ))
2416 .unwrap()
2417 );
2418 }
2419
2420 #[test]
2421 fn sqrt() {
2422 let value =
2423 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2424 .unwrap();
2425 let result = value.clone().sqrt();
2426 assert_eq!(
2427 result,
2428 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2429 PRECISION,
2430 value.into_inner().sqrt()
2431 ))
2432 .unwrap()
2433 );
2434 }
2435
2436 #[test]
2437 fn try_sqrt() {
2438 let value =
2439 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2440 .unwrap();
2441 let result = value.clone().try_sqrt().unwrap();
2442 assert_eq!(
2443 result,
2444 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2445 PRECISION,
2446 value.into_inner().sqrt()
2447 ))
2448 .unwrap()
2449 );
2450
2451 assert!(
2452 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -4.0))
2453 .unwrap()
2454 .try_sqrt()
2455 .is_err()
2456 )
2457 }
2458
2459 #[test]
2460 fn test_tan() {
2461 let value =
2462 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2463 .unwrap();
2464 let result = value.clone().tan();
2465 assert_eq!(
2466 result,
2467 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2468 PRECISION,
2469 value.into_inner().tan()
2470 ))
2471 .unwrap()
2472 );
2473 }
2474
2475 #[test]
2476 fn test_tanh() {
2477 let value =
2478 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
2479 .unwrap();
2480 let result = value.clone().tanh();
2481 assert_eq!(
2482 result,
2483 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
2484 PRECISION,
2485 value.into_inner().tanh()
2486 ))
2487 .unwrap()
2488 );
2489 }
2490
2491 #[test]
2492 fn test_mul_add() {
2493 let a =
2494 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
2495 .unwrap();
2496 let b =
2497 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
2498 .unwrap();
2499 let c =
2500 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
2501 .unwrap();
2502 let result = a.clone().mul_add_ref(&b, &c);
2503 assert_eq!(
2504 result,
2505 RealRugStrictFinite::<PRECISION>::try_new(
2506 a.into_inner() * b.as_ref() + c.as_ref()
2507 )
2508 .unwrap()
2509 );
2510 }
2511 }
2512
2513 mod complex {
2514 use super::*;
2515 //use rug::Complex;
2516 use rug::Float;
2517
2518 #[test]
2519 fn add() {
2520 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2521 .unwrap();
2522 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 4.))
2523 .unwrap();
2524 let c_expected =
2525 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(4., 6.))
2526 .unwrap();
2527 test_add(a, b, c_expected);
2528 }
2529
2530 #[test]
2531 fn sub() {
2532 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2533 .unwrap();
2534 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2535 .unwrap();
2536 let c_expected =
2537 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., -2.))
2538 .unwrap();
2539 test_sub(a, b, c_expected);
2540 }
2541
2542 #[test]
2543 fn mul() {
2544 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2545 .unwrap();
2546 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2547 .unwrap();
2548 let c_expected =
2549 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-5., 14.))
2550 .unwrap();
2551 test_mul(a, b, c_expected);
2552 }
2553
2554 #[test]
2555 fn div() {
2556 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-5., 14.))
2557 .unwrap();
2558 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 4.))
2559 .unwrap();
2560 let c_expected =
2561 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2562 .unwrap();
2563 test_div(a, b, c_expected);
2564 }
2565
2566 #[test]
2567 fn add_assign() {
2568 let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2569 .unwrap();
2570 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 4.))
2571 .unwrap();
2572
2573 a += &b;
2574 let a_expected =
2575 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(4., 6.))
2576 .unwrap();
2577 assert_eq!(a, a_expected);
2578
2579 a += b;
2580 let a_expected =
2581 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(7., 10.))
2582 .unwrap();
2583 assert_eq!(a, a_expected);
2584 }
2585
2586 #[test]
2587 fn sub_assign() {
2588 let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2589 .unwrap();
2590 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2591 .unwrap();
2592
2593 a -= &b;
2594 let a_expected =
2595 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., -2.))
2596 .unwrap();
2597 assert_eq!(a, a_expected);
2598
2599 a -= b;
2600 let a_expected =
2601 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., -6.))
2602 .unwrap();
2603 assert_eq!(a, a_expected);
2604 }
2605
2606 #[test]
2607 fn mul_assign() {
2608 let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2609 .unwrap();
2610 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2611 .unwrap();
2612
2613 a *= &b;
2614 let a_expected =
2615 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., 16.))
2616 .unwrap();
2617 assert_eq!(a, a_expected);
2618
2619 a *= b;
2620 let a_expected =
2621 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-68., 24.))
2622 .unwrap();
2623 assert_eq!(a, a_expected);
2624 }
2625
2626 #[test]
2627 fn div_assign() {
2628 let mut a =
2629 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-68., 24.))
2630 .unwrap();
2631 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2632 .unwrap();
2633
2634 a /= &b;
2635 let a_expected =
2636 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., 16.))
2637 .unwrap();
2638 assert_eq!(a, a_expected);
2639
2640 a /= b;
2641 let a_expected =
2642 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 2.))
2643 .unwrap();
2644 assert_eq!(a, a_expected);
2645 }
2646
2647 #[test]
2648 fn from_f64() {
2649 let v_100bits =
2650 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(16.25, 2.))
2651 .unwrap();
2652 assert_eq!(
2653 ComplexRugStrictFinite::<PRECISION>::real_part(&v_100bits),
2654 16.25
2655 );
2656 assert_eq!(
2657 ComplexRugStrictFinite::<PRECISION>::imag_part(&v_100bits),
2658 2.
2659 );
2660
2661 let v_53bits =
2662 ComplexRugStrictFinite::<53>::try_from(Complex::new(16.25, 2.)).unwrap();
2663 assert_eq!(ComplexRugStrictFinite::<53>::real_part(&v_53bits), 16.25);
2664 assert_eq!(ComplexRugStrictFinite::<53>::imag_part(&v_53bits), 2.);
2665
2666 // 16.25 has seven significant bits (binary 10000.01)
2667 let v_7bits =
2668 ComplexRugStrictFinite::<7>::try_from(Complex::new(16.25, 2.)).unwrap();
2669 assert_eq!(ComplexRugStrictFinite::<7>::real_part(&v_7bits), 16.25);
2670 assert_eq!(ComplexRugStrictFinite::<7>::imag_part(&v_7bits), 2.);
2671 }
2672
2673 #[test]
2674 #[should_panic]
2675 fn from_f64_failing() {
2676 // this should fail because 16.25 has seven significant bits (binary 10000.01) and we ask a float with 6 significant bits
2677 let _v_6bits =
2678 ComplexRugStrictFinite::<6>::try_from(Complex::new(16.25, 2.)).unwrap();
2679 }
2680
2681 #[test]
2682 fn conj() {
2683 let v = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(16.25, 2.))
2684 .unwrap();
2685
2686 let v_conj = ComplexRugStrictFinite::<PRECISION>::conjugate(v);
2687 assert_eq!(
2688 ComplexRugStrictFinite::<PRECISION>::real_part(&v_conj),
2689 16.25
2690 );
2691 assert_eq!(ComplexRugStrictFinite::<PRECISION>::imag_part(&v_conj), -2.);
2692 }
2693
2694 #[test]
2695 fn neg_assign() {
2696 let mut a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2697 .unwrap();
2698 a.neg_assign();
2699
2700 let a_expected =
2701 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., -2.))
2702 .unwrap();
2703 assert_eq!(a, a_expected);
2704 }
2705
2706 #[test]
2707 fn abs() {
2708 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-3., 4.))
2709 .unwrap();
2710
2711 let abs = a.abs();
2712 let abs_expected = RealRugStrictFinite::<100>::try_from_f64(5.).unwrap();
2713 assert_eq!(abs, abs_expected);
2714 }
2715
2716 #[test]
2717 fn mul_add_ref() {
2718 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., -3.))
2719 .unwrap();
2720 let b = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 1.))
2721 .unwrap();
2722 let c = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., -4.))
2723 .unwrap();
2724
2725 let d_expected =
2726 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(10., -11.))
2727 .unwrap();
2728
2729 let d = a.mul_add_ref(&b, &c);
2730 assert_eq!(d, d_expected);
2731 }
2732
2733 #[test]
2734 fn mul_complex_with_real() {
2735 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2736 .unwrap();
2737 let b = RealRugStrictFinite::<100>::try_from_f64(3.).unwrap();
2738
2739 let a_times_b_expected =
2740 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 6.))
2741 .unwrap();
2742
2743 test_mul_complex_with_real(a, b, a_times_b_expected);
2744 }
2745
2746 #[test]
2747 fn mul_assign_complex_with_real() {
2748 let a = ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 2.))
2749 .unwrap();
2750 let b = RealRugStrictFinite::<100>::try_from_f64(3.).unwrap();
2751
2752 let a_times_b_expected =
2753 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(3., 6.))
2754 .unwrap();
2755
2756 test_mul_assign_complex_with_real(a, b, a_times_b_expected);
2757 }
2758
2759 #[test]
2760 fn dot_product() {
2761 let a = &[
2762 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(1., 3.))
2763 .unwrap(),
2764 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(2., 4.))
2765 .unwrap(),
2766 ];
2767
2768 let b = &[
2769 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-2., -5.))
2770 .unwrap(),
2771 ComplexRugStrictFinite::<PRECISION>::try_from(Complex::new(-1., 6.))
2772 .unwrap(),
2773 ];
2774
2775 let a: Vec<_> = a.iter().map(|a_i| a_i.as_ref()).collect();
2776 let b: Vec<_> = b.iter().map(|b_i| b_i.as_ref()).collect();
2777
2778 // computes a * a^T
2779 let a_times_a = ComplexRugStrictFinite::<PRECISION>::try_new(
2780 rug::Complex::dot(a.clone().into_iter().zip(a.clone()))
2781 .complete((100, 100)),
2782 )
2783 .unwrap();
2784 assert_eq!(
2785 a_times_a.as_ref(),
2786 &rug::Complex::with_val(100, (-20., 22.))
2787 );
2788
2789 // computes a * b^T
2790 let a_times_b = ComplexRugStrictFinite::<PRECISION>::try_new(
2791 rug::Complex::dot(a.clone().into_iter().zip(b.clone()))
2792 .complete((100, 100)),
2793 )
2794 .unwrap();
2795 assert_eq!(
2796 a_times_b.as_ref(),
2797 &rug::Complex::with_val(100, (-13., -3.))
2798 );
2799
2800 // computes b * a^T
2801 let b_times_a = ComplexRugStrictFinite::<PRECISION>::try_new(
2802 rug::Complex::dot(b.into_iter().zip(a)).complete((100, 100)),
2803 )
2804 .unwrap();
2805 assert_eq!(
2806 b_times_a.as_ref(),
2807 &rug::Complex::with_val(100, (-13., -3.))
2808 );
2809 }
2810
2811 #[test]
2812 fn test_acos() {
2813 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2814 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2815 )
2816 .unwrap();
2817 let result = value.clone().acos();
2818 assert_eq!(
2819 result,
2820 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2821 PRECISION,
2822 value.into_inner().acos()
2823 ))
2824 .unwrap()
2825 );
2826 }
2827
2828 #[test]
2829 fn test_acosh() {
2830 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2831 rug::Complex::with_val(PRECISION, (1.5, 0.5)),
2832 )
2833 .unwrap();
2834 let result = value.clone().acosh();
2835 assert_eq!(
2836 result,
2837 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2838 PRECISION,
2839 value.into_inner().acosh()
2840 ))
2841 .unwrap()
2842 );
2843 }
2844
2845 #[test]
2846 fn test_asin() {
2847 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2848 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2849 )
2850 .unwrap();
2851 let result = value.clone().asin();
2852 assert_eq!(
2853 result,
2854 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2855 PRECISION,
2856 value.into_inner().asin()
2857 ))
2858 .unwrap()
2859 );
2860 }
2861
2862 #[test]
2863 fn test_asinh() {
2864 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2865 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2866 )
2867 .unwrap();
2868 let result = value.clone().asinh();
2869 assert_eq!(
2870 result,
2871 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2872 PRECISION,
2873 value.into_inner().asinh()
2874 ))
2875 .unwrap()
2876 );
2877 }
2878
2879 #[test]
2880 fn test_atan() {
2881 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2882 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2883 )
2884 .unwrap();
2885 let result = value.clone().atan();
2886 assert_eq!(
2887 result,
2888 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2889 PRECISION,
2890 value.into_inner().atan()
2891 ))
2892 .unwrap()
2893 );
2894 }
2895
2896 #[test]
2897 fn test_atanh() {
2898 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2899 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2900 )
2901 .unwrap();
2902 let result = value.clone().atanh();
2903 assert_eq!(
2904 result,
2905 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2906 PRECISION,
2907 value.into_inner().atanh()
2908 ))
2909 .unwrap()
2910 );
2911 }
2912
2913 #[test]
2914 fn test_cos_01() {
2915 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2916 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2917 )
2918 .unwrap();
2919 let result = value.clone().cos();
2920 assert_eq!(
2921 result,
2922 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2923 PRECISION,
2924 value.into_inner().cos()
2925 ))
2926 .unwrap()
2927 );
2928 }
2929
2930 #[test]
2931 fn test_cosh() {
2932 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2933 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2934 )
2935 .unwrap();
2936 let result = value.clone().cosh();
2937 assert_eq!(
2938 result,
2939 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2940 PRECISION,
2941 value.into_inner().cosh()
2942 ))
2943 .unwrap()
2944 );
2945 }
2946
2947 #[test]
2948 fn test_exp() {
2949 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2950 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2951 )
2952 .unwrap();
2953 let result = value.clone().exp();
2954 println!("result = {result:?}");
2955 assert_eq!(
2956 result,
2957 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2958 PRECISION,
2959 value.into_inner().exp()
2960 ))
2961 .unwrap()
2962 );
2963 }
2964
2965 #[test]
2966 fn test_is_finite() {
2967 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2968 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2969 )
2970 .unwrap();
2971 assert!(value.is_finite());
2972
2973 let value =
2974 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2975 100,
2976 (Float::with_val(PRECISION, f64::INFINITY), 0.5),
2977 ));
2978 assert!(value.is_err());
2979 }
2980
2981 #[test]
2982 fn test_is_infinite() {
2983 let value =
2984 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
2985 100,
2986 (Float::with_val(PRECISION, f64::INFINITY), 0.5),
2987 ));
2988 assert!(value.is_err());
2989
2990 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
2991 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
2992 )
2993 .unwrap();
2994 assert!(!value.is_infinite());
2995 }
2996
2997 #[test]
2998 fn test_ln() {
2999 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3000 rug::Complex::with_val(PRECISION, (std::f64::consts::E, 1.0)),
3001 )
3002 .unwrap();
3003 let result = value.clone().ln();
3004 println!("result = {result:?}");
3005 assert_eq!(
3006 result,
3007 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3008 PRECISION,
3009 value.into_inner().ln()
3010 ))
3011 .unwrap()
3012 );
3013 }
3014
3015 #[test]
3016 fn test_log10() {
3017 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3018 rug::Complex::with_val(PRECISION, (10.0, 1.0)),
3019 )
3020 .unwrap();
3021 let result = value.clone().log10();
3022 println!("result = {result:?}");
3023 assert_eq!(
3024 result,
3025 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3026 PRECISION,
3027 value.into_inner().log10()
3028 ))
3029 .unwrap()
3030 );
3031 }
3032
3033 #[test]
3034 fn test_log2() {
3035 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3036 rug::Complex::with_val(PRECISION, (8.0, 1.0)),
3037 )
3038 .unwrap();
3039 let result = value.clone().log2();
3040 println!("result = {result:?}");
3041 assert_eq!(
3042 result,
3043 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3044 PRECISION,
3045 value.into_inner().ln() / rug::Float::with_val(PRECISION, 2.).ln()
3046 ))
3047 .unwrap()
3048 );
3049 }
3050
3051 #[test]
3052 fn test_recip() {
3053 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3054 rug::Complex::with_val(PRECISION, (2.0, 0.0)),
3055 )
3056 .unwrap();
3057 let result = value.clone().try_reciprocal().unwrap();
3058 assert_eq!(
3059 result,
3060 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3061 PRECISION,
3062 value.into_inner().recip()
3063 ))
3064 .unwrap()
3065 );
3066 }
3067
3068 #[test]
3069 fn test_sin_01() {
3070 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3071 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3072 )
3073 .unwrap();
3074 let result = value.clone().sin();
3075 assert_eq!(
3076 result,
3077 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3078 PRECISION,
3079 value.into_inner().sin()
3080 ))
3081 .unwrap()
3082 );
3083 }
3084
3085 #[test]
3086 fn test_sinh() {
3087 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3088 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3089 )
3090 .unwrap();
3091 let result = value.clone().sinh();
3092 assert_eq!(
3093 result,
3094 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3095 PRECISION,
3096 value.into_inner().sinh()
3097 ))
3098 .unwrap()
3099 );
3100 }
3101
3102 #[test]
3103 fn sqrt() {
3104 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3105 rug::Complex::with_val(PRECISION, (4.0, 1.0)),
3106 )
3107 .unwrap();
3108 let result = value.clone().sqrt();
3109 assert_eq!(
3110 result,
3111 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3112 PRECISION,
3113 value.into_inner().sqrt()
3114 ))
3115 .unwrap()
3116 );
3117 }
3118
3119 #[test]
3120 fn try_sqrt() {
3121 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3122 rug::Complex::with_val(PRECISION, (4.0, 1.0)),
3123 )
3124 .unwrap();
3125 let result = value.clone().try_sqrt().unwrap();
3126 assert_eq!(
3127 result,
3128 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3129 PRECISION,
3130 value.into_inner().sqrt()
3131 ))
3132 .unwrap()
3133 );
3134 }
3135
3136 #[test]
3137 fn test_tan() {
3138 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3139 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3140 )
3141 .unwrap();
3142 let result = value.clone().tan();
3143 assert_eq!(
3144 result,
3145 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3146 PRECISION,
3147 value.into_inner().tan()
3148 ))
3149 .unwrap()
3150 );
3151 }
3152
3153 #[test]
3154 fn test_tanh() {
3155 let value = ComplexRugStrictFinite::<PRECISION>::try_new(
3156 rug::Complex::with_val(PRECISION, (0.5, 0.5)),
3157 )
3158 .unwrap();
3159 let result = value.clone().tanh();
3160 assert_eq!(
3161 result,
3162 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3163 PRECISION,
3164 value.into_inner().tanh()
3165 ))
3166 .unwrap()
3167 );
3168 }
3169
3170 #[test]
3171 fn test_mul_add() {
3172 let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3173 PRECISION,
3174 (2.0, 1.0),
3175 ))
3176 .unwrap();
3177 let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3178 PRECISION,
3179 (3.0, 1.0),
3180 ))
3181 .unwrap();
3182 let c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3183 PRECISION,
3184 (4.0, 1.0),
3185 ))
3186 .unwrap();
3187 let result = a.clone().mul_add_ref(&b, &c);
3188 assert_eq!(
3189 result,
3190 ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
3191 PRECISION,
3192 a.as_ref() * b.as_ref() + c.as_ref()
3193 ))
3194 .unwrap()
3195 );
3196 }
3197 }
3198 }
3199 }
3200
3201 mod functions_real_type {
3202 use super::*;
3203
3204 mod native64 {
3205
3206 use super::*;
3207
3208 #[test]
3209 fn test_atan2() {
3210 let a: f64 = 27.0;
3211 let b: f64 = 13.0;
3212
3213 let result = a.atan2(b);
3214 assert_eq!(result, a.atan2(b));
3215 }
3216
3217 #[test]
3218 fn test_ceil() {
3219 let value: f64 = 3.7;
3220 let result = value.kernel_ceil();
3221 assert_eq!(result, value.ceil());
3222 }
3223
3224 #[test]
3225 fn test_clamp() {
3226 let value: f64 = 5.0;
3227 let min: f64 = 3.0;
3228 let max: f64 = 7.0;
3229 let result = value.kernel_clamp(&min, &max);
3230 assert_eq!(result, value.clamp(min, max));
3231 }
3232
3233 #[test]
3234 fn test_classify() {
3235 let value: f64 = 3.7;
3236 let result = value.kernel_classify();
3237 assert_eq!(result, value.classify());
3238 }
3239
3240 #[test]
3241 fn test_copysign() {
3242 let value: f64 = 3.5;
3243 let sign: f64 = -1.0;
3244 let result = value.kernel_copysign(&sign);
3245 assert_eq!(result, value.copysign(sign));
3246 }
3247
3248 #[test]
3249 fn test_epsilon() {
3250 let eps = f64::epsilon();
3251 assert_eq!(eps, f64::EPSILON);
3252 }
3253
3254 #[test]
3255 fn test_exp_m1() {
3256 let value: f64 = 0.5;
3257 let result = value.kernel_exp_m1();
3258 assert_eq!(result, value.exp_m1());
3259 }
3260
3261 #[test]
3262 fn test_floor() {
3263 let value: f64 = 3.7;
3264 let result = value.kernel_floor();
3265 assert_eq!(result, value.floor());
3266 }
3267
3268 #[test]
3269 fn test_fract() {
3270 let value: f64 = 3.7;
3271 let result = value.kernel_fract();
3272 assert_eq!(result, value.fract());
3273 }
3274
3275 #[test]
3276 fn test_hypot() {
3277 let a: f64 = 3.0;
3278 let b: f64 = 4.0;
3279 let result = a.kernel_hypot(&b);
3280 assert_eq!(result, a.hypot(b));
3281 }
3282
3283 #[test]
3284 fn test_is_sign_negative() {
3285 let value: f64 = -1.0;
3286 assert!(value.kernel_is_sign_negative());
3287
3288 let value: f64 = -0.0;
3289 assert!(value.kernel_is_sign_negative());
3290
3291 let value: f64 = 0.0;
3292 assert!(!value.kernel_is_sign_negative());
3293
3294 let value: f64 = 1.0;
3295 assert!(!value.kernel_is_sign_negative());
3296 }
3297
3298 #[test]
3299 fn test_is_sign_positive() {
3300 let value: f64 = -1.0;
3301 assert!(!value.kernel_is_sign_positive());
3302
3303 let value: f64 = -0.0;
3304 assert!(!value.kernel_is_sign_positive());
3305
3306 let value: f64 = 0.0;
3307 assert!(value.kernel_is_sign_positive());
3308
3309 let value: f64 = 1.0;
3310 assert!(value.kernel_is_sign_positive());
3311 }
3312
3313 #[test]
3314 fn test_ln_1p() {
3315 let value: f64 = 0.5;
3316 let result = value.kernel_ln_1p();
3317 assert_eq!(result, value.ln_1p());
3318 }
3319
3320 #[test]
3321 fn test_max() {
3322 let a: f64 = 3.0;
3323 let b: f64 = 4.0;
3324 let result = a.max(b);
3325 assert_eq!(result, a.max(b));
3326 }
3327
3328 #[test]
3329 fn test_min() {
3330 let a: f64 = 3.0;
3331 let b: f64 = 4.0;
3332 let result = a.min(b);
3333 assert_eq!(result, a.min(b));
3334 }
3335
3336 #[test]
3337 fn max_finite() {
3338 let max = f64::max_finite();
3339 assert_eq!(max, f64::MAX);
3340 }
3341
3342 #[test]
3343 fn min_finite() {
3344 let min = f64::min_finite();
3345 assert_eq!(min, f64::MIN);
3346 }
3347
3348 #[test]
3349 fn test_mul_add_mul_mut() {
3350 let mut a: f64 = 2.0;
3351 let b: f64 = 3.0;
3352 let c: f64 = 4.0;
3353 let d: f64 = -1.0;
3354 let mut result = a;
3355 result.kernel_mul_add_mul_mut(&b, &c, &d);
3356
3357 a.mul_add_assign(b, c * d);
3358 assert_eq!(result, a);
3359 }
3360
3361 #[test]
3362 fn test_mul_sub_mul_mut() {
3363 let mut a: f64 = 2.0;
3364 let b: f64 = 3.0;
3365 let c: f64 = 4.0;
3366 let d: f64 = -1.0;
3367 let mut result = a;
3368 result.kernel_mul_sub_mul_mut(&b, &c, &d);
3369
3370 a.mul_add_assign(b, -c * d);
3371 assert_eq!(result, a);
3372 }
3373
3374 #[test]
3375 fn test_negative_one() {
3376 let value = f64::negative_one();
3377 assert_eq!(value, -1.0);
3378 }
3379
3380 #[test]
3381 fn test_one() {
3382 let value = f64::one();
3383 assert_eq!(value, 1.0);
3384 }
3385
3386 #[test]
3387 fn test_round() {
3388 let value: f64 = 3.5;
3389 let result = value.kernel_round();
3390 assert_eq!(result, value.round());
3391 }
3392
3393 #[test]
3394 fn test_round_ties_even() {
3395 let value: f64 = 3.5;
3396 let result = value.kernel_round_ties_even();
3397 assert_eq!(result, value.round_ties_even());
3398 }
3399
3400 #[test]
3401 fn test_signum() {
3402 let value: f64 = -3.5;
3403 let result = value.kernel_signum();
3404 assert_eq!(result, value.signum());
3405 }
3406
3407 #[test]
3408 fn test_total_cmp() {
3409 let a: f64 = 3.0;
3410 let b: f64 = 4.0;
3411 let result = a.total_cmp(&b);
3412 assert_eq!(result, a.total_cmp(&b));
3413 }
3414
3415 #[test]
3416 fn test_try_from_64() {
3417 let result = f64::try_from_f64(3.7);
3418 assert!(result.is_ok());
3419 }
3420
3421 #[test]
3422 fn test_try_from_64_error_infinite() {
3423 let result = f64::try_from_f64(f64::INFINITY);
3424 assert!(result.is_err());
3425 }
3426
3427 #[test]
3428 fn test_try_from_64_error_nan() {
3429 let result = f64::try_from_f64(f64::NAN);
3430 assert!(result.is_err());
3431 }
3432
3433 #[test]
3434 fn test_trunc() {
3435 let value: f64 = 3.7;
3436 let result = value.kernel_trunc();
3437 assert_eq!(result, value.trunc());
3438 }
3439
3440 #[test]
3441 fn test_two() {
3442 let value = f64::two();
3443 assert_eq!(value, 2.0);
3444 }
3445 }
3446
3447 #[cfg(feature = "rug")]
3448 mod rug100 {
3449 use super::*;
3450 use crate::kernels::rug::RealRugStrictFinite;
3451 use rug::{Float, ops::CompleteRound};
3452 use try_create::{IntoInner, TryNew};
3453
3454 const PRECISION: u32 = 100;
3455
3456 #[test]
3457 fn from_f64() {
3458 let v_100bits = RealRugStrictFinite::<100>::try_from_f64(16.25).unwrap();
3459
3460 assert_eq!(v_100bits, 16.25);
3461
3462 let v_53bits = RealRugStrictFinite::<53>::try_from_f64(16.25).unwrap();
3463 assert_eq!(v_53bits, 16.25);
3464
3465 // 16.25 has seven significant bits (binary 10000.01)
3466 let v_7bits = RealRugStrictFinite::<7>::try_from_f64(16.25).unwrap();
3467 assert_eq!(v_7bits, 16.25);
3468 }
3469
3470 #[test]
3471 #[should_panic]
3472 fn from_f64_failing() {
3473 // this should fail because 16.25 has seven significant bits (binary 10000.01) and we ask a float with 6 significant bits
3474 let _v_6bits = RealRugStrictFinite::<6>::try_from_f64(16.25).unwrap();
3475 }
3476
3477 #[test]
3478 fn max_finite() {
3479 let max = RealRugStrictFinite::<53>::max_finite();
3480 assert_eq!(
3481 max.as_ref(),
3482 &rug::Float::with_val(
3483 53,
3484 rug::Float::parse("1.0492893582336937e323228496").unwrap()
3485 )
3486 );
3487 }
3488
3489 #[test]
3490 fn min_finite() {
3491 let min = RealRugStrictFinite::<53>::min_finite();
3492 assert_eq!(
3493 min.as_ref(),
3494 &rug::Float::with_val(
3495 53,
3496 rug::Float::parse("-1.0492893582336937e323228496").unwrap()
3497 )
3498 );
3499 }
3500
3501 #[test]
3502 fn test_atan2() {
3503 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 27.0))
3504 .unwrap();
3505 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 13.0))
3506 .unwrap();
3507 let result = a.clone().atan2(&b);
3508 assert_eq!(
3509 result,
3510 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3511 PRECISION,
3512 a.into_inner().atan2(b.as_ref())
3513 ))
3514 .unwrap()
3515 );
3516 }
3517
3518 #[test]
3519 fn test_ceil() {
3520 let value =
3521 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3522 .unwrap();
3523 let result = value.clone().kernel_ceil();
3524 assert_eq!(
3525 result,
3526 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3527 PRECISION,
3528 value.into_inner().ceil()
3529 ))
3530 .unwrap()
3531 );
3532 }
3533
3534 #[test]
3535 fn test_clamp() {
3536 let value =
3537 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0))
3538 .unwrap();
3539 let min =
3540 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3541 .unwrap();
3542 let max =
3543 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 7.0))
3544 .unwrap();
3545 let result = value.clone().kernel_clamp(&min, &max);
3546 assert_eq!(
3547 result,
3548 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3549 PRECISION,
3550 value.into_inner().clamp(min.as_ref(), max.as_ref())
3551 ))
3552 .unwrap()
3553 );
3554 }
3555
3556 #[test]
3557 fn test_classify() {
3558 let value =
3559 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3560 .unwrap();
3561 let result = value.kernel_classify();
3562 assert_eq!(result, value.into_inner().classify());
3563 }
3564
3565 #[test]
3566 fn test_copysign() {
3567 let value =
3568 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
3569 .unwrap();
3570 let sign =
3571 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3572 .unwrap();
3573 let result = value.clone().kernel_copysign(&sign);
3574 assert_eq!(
3575 result,
3576 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3577 PRECISION,
3578 value.into_inner().copysign(sign.as_ref())
3579 ))
3580 .unwrap()
3581 );
3582 }
3583
3584 #[test]
3585 fn test_epsilon() {
3586 let rug_eps = rug::Float::u_pow_u(2, PRECISION - 1)
3587 .complete(PRECISION)
3588 .recip();
3589 //println!("eps: {}", rug_eps);
3590
3591 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
3592 assert_eq!(
3593 eps,
3594 RealRugStrictFinite::<PRECISION>::try_new(rug_eps.clone()).unwrap()
3595 );
3596
3597 // here we compute new_eps as the difference between 1 and the next larger floating point number
3598 let mut new_eps = Float::with_val(PRECISION, 1.);
3599 new_eps.next_up();
3600 new_eps -= Float::with_val(PRECISION, 1.);
3601 assert_eq!(new_eps, rug_eps.clone());
3602
3603 //println!("new_eps: {new_eps}");
3604
3605 let one = RealRugStrictFinite::<PRECISION>::one();
3606 let result = RealRugStrictFinite::<PRECISION>::try_new(
3607 new_eps / Float::with_val(PRECISION, 2.),
3608 )
3609 .unwrap()
3610 + &one;
3611 assert_eq!(result, one);
3612 }
3613
3614 #[test]
3615 fn test_exp_m1() {
3616 let value =
3617 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
3618 .unwrap();
3619 let result = value.clone().kernel_exp_m1();
3620 assert_eq!(
3621 result,
3622 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3623 PRECISION,
3624 value.into_inner().exp_m1()
3625 ))
3626 .unwrap()
3627 );
3628 }
3629
3630 #[test]
3631 fn test_floor() {
3632 let value =
3633 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3634 .unwrap();
3635 let result = value.clone().kernel_floor();
3636 assert_eq!(
3637 result,
3638 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3639 PRECISION,
3640 value.into_inner().floor()
3641 ))
3642 .unwrap()
3643 );
3644 }
3645
3646 #[test]
3647 fn test_fract() {
3648 let value =
3649 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3650 .unwrap();
3651 let result = value.clone().kernel_fract();
3652 assert_eq!(
3653 result,
3654 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3655 PRECISION,
3656 value.into_inner().fract()
3657 ))
3658 .unwrap()
3659 );
3660 }
3661
3662 #[test]
3663 fn test_hypot() {
3664 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3665 .unwrap();
3666 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3667 .unwrap();
3668 let result = a.clone().kernel_hypot(&b);
3669 assert_eq!(
3670 result,
3671 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3672 PRECISION,
3673 a.into_inner().hypot(b.as_ref())
3674 ))
3675 .unwrap()
3676 );
3677 }
3678
3679 #[test]
3680 fn test_is_sign_negative() {
3681 let value =
3682 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3683 .unwrap();
3684 assert!(value.kernel_is_sign_negative());
3685
3686 let value =
3687 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -0.0))
3688 .unwrap();
3689 assert!(value.kernel_is_sign_negative());
3690
3691 let value =
3692 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0))
3693 .unwrap();
3694 assert!(!value.kernel_is_sign_negative());
3695
3696 let value =
3697 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
3698 .unwrap();
3699 assert!(!value.kernel_is_sign_negative());
3700 }
3701
3702 #[test]
3703 fn test_is_sign_positive() {
3704 let value =
3705 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3706 .unwrap();
3707 assert!(!value.kernel_is_sign_positive());
3708
3709 let value =
3710 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -0.0))
3711 .unwrap();
3712 assert!(!value.kernel_is_sign_positive());
3713
3714 let value =
3715 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0))
3716 .unwrap();
3717 assert!(value.kernel_is_sign_positive());
3718
3719 let value =
3720 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
3721 .unwrap();
3722 assert!(value.kernel_is_sign_positive());
3723 }
3724
3725 #[test]
3726 fn test_ln_1p() {
3727 let value =
3728 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.5))
3729 .unwrap();
3730 let result = value.clone().kernel_ln_1p();
3731 assert_eq!(
3732 result,
3733 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3734 PRECISION,
3735 value.into_inner().ln_1p()
3736 ))
3737 .unwrap()
3738 );
3739 }
3740
3741 #[test]
3742 fn test_max() {
3743 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3744 .unwrap();
3745 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3746 .unwrap();
3747 let result = a.max(&b);
3748 assert_eq!(
3749 result,
3750 &RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3751 PRECISION,
3752 a.clone().into_inner().max(b.as_ref())
3753 ))
3754 .unwrap()
3755 );
3756 }
3757
3758 #[test]
3759 fn test_min() {
3760 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3761 .unwrap();
3762 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3763 .unwrap();
3764 let result = a.min(&b);
3765 assert_eq!(
3766 result,
3767 &RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3768 PRECISION,
3769 a.clone().into_inner().min(b.as_ref())
3770 ))
3771 .unwrap()
3772 );
3773 }
3774
3775 #[test]
3776 fn test_mul_add_mul_mut() {
3777 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
3778 .unwrap();
3779 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3780 .unwrap();
3781 let c = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3782 .unwrap();
3783 let d = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3784 .unwrap();
3785 let mut result = a.clone();
3786 result.kernel_mul_add_mul_mut(&b, &c, &d);
3787 assert_eq!(
3788 result,
3789 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3790 PRECISION,
3791 a.into_inner()
3792 .mul_add_ref(b.as_ref(), &(c.into_inner() * d.as_ref()))
3793 ))
3794 .unwrap()
3795 );
3796 }
3797
3798 #[test]
3799 fn test_mul_sub_mul_mut() {
3800 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
3801 .unwrap();
3802 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3803 .unwrap();
3804 let c = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3805 .unwrap();
3806 let d = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3807 .unwrap();
3808 let mut result = a.clone();
3809 result.kernel_mul_sub_mul_mut(&b, &c, &d);
3810 assert_eq!(
3811 result,
3812 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3813 PRECISION,
3814 a.into_inner()
3815 .mul_add_ref(b.as_ref(), &(-c.into_inner() * d.as_ref()))
3816 ))
3817 .unwrap()
3818 );
3819 }
3820
3821 #[test]
3822 fn test_negative_one() {
3823 let value = RealRugStrictFinite::<PRECISION>::negative_one();
3824 assert_eq!(
3825 value,
3826 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3827 .unwrap()
3828 );
3829 }
3830
3831 #[test]
3832 fn test_one() {
3833 let value = RealRugStrictFinite::<PRECISION>::one();
3834 assert_eq!(
3835 value,
3836 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0))
3837 .unwrap()
3838 );
3839 }
3840
3841 #[test]
3842 fn test_round() {
3843 let value =
3844 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
3845 .unwrap();
3846 let result = value.clone().kernel_round();
3847 assert_eq!(
3848 result,
3849 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3850 PRECISION,
3851 value.into_inner().round()
3852 ))
3853 .unwrap()
3854 );
3855 }
3856
3857 #[test]
3858 fn test_round_ties_even() {
3859 let value =
3860 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.5))
3861 .unwrap();
3862 let result = value.clone().kernel_round_ties_even();
3863 assert_eq!(
3864 result,
3865 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3866 PRECISION,
3867 value.into_inner().round_even()
3868 ))
3869 .unwrap()
3870 );
3871 }
3872
3873 #[test]
3874 fn test_signum() {
3875 let value =
3876 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.5))
3877 .unwrap();
3878 let result = value.clone().kernel_signum();
3879 assert_eq!(
3880 result,
3881 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3882 PRECISION,
3883 value.into_inner().signum()
3884 ))
3885 .unwrap()
3886 );
3887 }
3888
3889 #[test]
3890 fn test_total_cmp() {
3891 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0))
3892 .unwrap();
3893 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 4.0))
3894 .unwrap();
3895 let result = a.total_cmp(&b);
3896 assert_eq!(result, a.into_inner().total_cmp(b.as_ref()));
3897 }
3898
3899 #[test]
3900 fn test_try_from_64() {
3901 let result = RealRugStrictFinite::<PRECISION>::try_from_f64(3.7);
3902 assert!(result.is_ok());
3903 }
3904
3905 #[test]
3906 fn test_try_from_64_error_infinite() {
3907 let result = RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY);
3908 assert!(result.is_err());
3909 }
3910
3911 #[test]
3912 fn test_try_from_64_error_nan() {
3913 let result = RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN);
3914 assert!(result.is_err());
3915 }
3916
3917 #[test]
3918 fn test_trunc() {
3919 let value =
3920 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.7))
3921 .unwrap();
3922 let result = value.clone().kernel_trunc();
3923 assert_eq!(
3924 result,
3925 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(
3926 PRECISION,
3927 value.into_inner().trunc()
3928 ))
3929 .unwrap()
3930 );
3931 }
3932
3933 #[test]
3934 fn test_two() {
3935 let value = RealRugStrictFinite::<PRECISION>::two();
3936 assert_eq!(
3937 value,
3938 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0))
3939 .unwrap()
3940 );
3941 }
3942 }
3943 }
3944
3945 mod util_funcs {
3946 use crate::{
3947 kernels::native64_validated::RealNative64StrictFinite, new_random_vec,
3948 try_vec_f64_into_vec_real,
3949 };
3950 use rand::{SeedableRng, distr::Uniform, rngs::StdRng};
3951
3952 #[test]
3953 fn test_new_random_vec_deterministic() {
3954 let seed = [42; 32];
3955 let mut rng1 = StdRng::from_seed(seed);
3956 let mut rng2 = StdRng::from_seed(seed);
3957 let uniform = Uniform::new(-1.0, 1.0).unwrap();
3958
3959 let vec1: Vec<f64> = new_random_vec(10, &uniform, &mut rng1);
3960 let vec2: Vec<RealNative64StrictFinite> = new_random_vec(10, &uniform, &mut rng2);
3961
3962 assert_eq!(vec1.len(), 10);
3963 assert_eq!(vec2.len(), 10);
3964 for i in 0..10 {
3965 assert_eq!(&vec1[i], vec2[i].as_ref());
3966 }
3967 }
3968
3969 #[test]
3970 fn test_try_vec_f64_into_vec_real_success() {
3971 let input = vec![1.0, -2.5, 1e10];
3972 let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
3973 assert!(result.is_ok());
3974 let output = result.unwrap();
3975 assert_eq!(output[0].as_ref(), &1.0);
3976 assert_eq!(output[1].as_ref(), &-2.5);
3977 }
3978
3979 #[test]
3980 fn test_try_vec_f64_into_vec_real_fail() {
3981 let input = vec![1.0, f64::NAN, 3.0];
3982 let result = try_vec_f64_into_vec_real::<RealNative64StrictFinite>(input);
3983 assert!(result.is_err());
3984 }
3985 }
3986}