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