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