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