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