Skip to main content

num_valid/backends/native/
raw.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Native Floating-Point Kernels
4//!
5//! This module provides a numerical kernel implementation based on Rust's native
6//! floating-point numbers ([`f32`] and [`f64`]) and complex numbers ([`num::Complex<T>`](num::Complex)).
7//! It serves as the standard, high-performance native backend for the
8//! [`num-valid`](crate) library.
9//!
10//! ## Purpose and Role
11//!
12//! The primary role of this module is to act as a **bridge** between the abstract traits
13//! defined by [`num-valid`](crate) (like [`RealScalar`](crate::RealScalar) and [`ComplexScalar`](crate::ComplexScalar)) and Rust's
14//! concrete, hardware-accelerated numeric types. It adapts [`f32`], [`f64`], and their complex counterparts
15//! so they can be used seamlessly in generic code written against the library's traits.
16//!
17//! ### Native floats as `RealScalar`
18//!
19//! By implementing [`RealScalar`](crate::RealScalar) for [`f32`] and [`f64`], this module makes Rust's native floats
20//! a "first-class citizen" in the [`num-valid`](crate) ecosystem. This implementation
21//! provides concrete logic for all the operations required by [`RealScalar`](crate::RealScalar) and its
22//! super-traits (e.g., [`FpScalar`](crate::FpScalar), [`Rounding`](crate::functions::Rounding), [`Sign`](crate::functions::Sign), [`Constants`](crate::Constants)).
23//! Most of these implementations simply delegate to the highly optimized methods
24//! available in Rust's standard library (e.g., `<f32 as Float>::sin` and `<f64 as Float>::sqrt`).
25//!
26//! This allows generic functions bounded by `T: RealScalar` to be instantiated with `f32` or `f64`,
27//! leveraging direct CPU floating-point support for maximum performance.
28//!
29//! ### Native complex floats as `ComplexScalar`
30//!
31//! Similarly, this module implements [`ComplexScalar`](crate::ComplexScalar) for [`num::Complex<f32>`](num::Complex) and [`num::Complex<f64>`](num::Complex). This
32//! makes the standard complex number type from the `num` crate compatible with the
33//! [`num-valid`](crate) abstraction for complex numbers. It implements all required traits,
34//! including [`FpScalar`](crate::FpScalar), [`ComplexScalarGetParts`](crate::functions::ComplexScalarGetParts), [`ComplexScalarSetParts`](crate::functions::ComplexScalarSetParts), and
35//! [`ComplexScalarMutateParts`](crate::functions::ComplexScalarMutateParts), by delegating to the methods of `num::Complex`.
36//!
37//! This enables generic code written against `T: ComplexScalar` to operate on
38//! `Complex<f32>` and `Complex<f64>` values, providing a performant backend for complex arithmetic.
39//!
40//! ## Core Components
41//!
42//! - **`Native<T>`**: A marker struct that implements the [`RawKernel`](crate::core::traits::RawKernel) trait. It is used
43//!   in generic contexts to select this native kernel, specifying `T` as its
44//!   [`RawReal`](crate::core::traits::RawKernel::RawReal) type and `num::Complex<T>` as its
45//!   [`RawComplex`](crate::core::traits::RawKernel::RawComplex) type.
46//! - **Trait Implementations**: This module is primarily composed of `impl` blocks that
47//!   satisfy the contracts of core traits ([`FpScalar`](crate::FpScalar), [`RealScalar`](crate::RealScalar), [`ComplexScalar`](crate::ComplexScalar),
48//!   [`Arithmetic`](crate::functions::Arithmetic), [`MulAddRef`](crate::MulAddRef), etc.) for `f32`/`f64` and their complex counterparts.
49//!
50//! ## Validation
51//!
52//! It is crucial to understand that the base types `f64` and `Complex<f64>` do not
53//! inherently enforce properties like finiteness (they can be `NaN` or `Infinity`).
54//!
55//! The [`num-valid`](crate) library introduces validation at the **trait and wrapper level**,
56//! not at the base type level. For instance, [`RealScalar::try_from_f64`](crate::RealScalar::try_from_f64) for `f64`
57//! uses a [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy) to ensure the input is finite before creating an instance.
58//! This design separates the raw, high-performance types from the validated, safer
59//! abstractions built on top of them.
60//!
61//! For scenarios requiring types that are guaranteed to be valid by construction,
62//! consider using the validated wrappers from the [`validated`](crate::backends::native::validated) module.
63
64use crate::{
65    ComplexScalar, Constants, FpScalar, IntegerScalar, MulAddRef, RealScalar, ScalarCore,
66    core::{
67        errors::{
68            ErrorsRawRealToInteger, ErrorsValidationRawComplex, ErrorsValidationRawReal,
69            capture_backtrace,
70        },
71        policies::validate_complex_from_parts,
72        traits::{RawKernel, raw::RawScalarValidate, validation::sealed::NativeReal},
73    },
74    functions::{
75        Clamp, Classify, ExpM1, Hypot, Ln1p, Rounding, Sign, TotalCmp,
76        complex::{
77            ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
78            ComplexScalarSetParts,
79        },
80    },
81    kernels::{
82        PrecisionBits, RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow,
83        RawScalarTrait, RawScalarTrigonometric,
84    },
85    scalar_kind,
86};
87use az::CheckedAs;
88use duplicate::duplicate_item;
89use num::{Complex, Zero};
90use num_traits::{Float, FloatConst, MulAdd, MulAddAssign};
91use std::{
92    cmp::Ordering,
93    hash::{Hash, Hasher},
94    num::FpCategory,
95};
96use try_create::IntoInner;
97
98//----------------------------------------------------------------------------------------------
99/// Numerical kernel specifier for Rust's native floating-point type `T` (i.e., `f64` or `f32`).
100///
101/// This struct is used as a generic argument or associated type to indicate
102/// that the floating-point values for computations should be `T` for real numbers
103/// and `num::Complex<T>` for complex numbers.
104///
105/// It implements the [`RawKernel`] trait, bridging the native raw types to the
106/// [`num-valid`](crate)'s generic numerical abstraction.
107#[derive(Debug, Clone, PartialEq, PartialOrd)]
108pub struct Native<T: NativeReal> {
109    _marker: std::marker::PhantomData<T>,
110}
111
112impl<T: NativeReal> RawKernel for Native<T>
113where
114    T: RawRealTrait<RawComplex = Complex<T>>,
115    Complex<T>: RawComplexTrait<RawReal = T>,
116{
117    /// The type for a real scalar value in this numerical kernel.
118    type RawReal = T;
119
120    /// The type for a complex scalar value in this numerical kernel.
121    type RawComplex = Complex<T>;
122}
123
124pub type Native64 = Native<f64>;
125pub type Native32 = Native<f32>;
126
127//----------------------------------------------------------------------------------------------
128
129//----------------------------------------------------------------------------------------------
130/// Implements the [`FpScalar`] trait for [`prim@f64`].
131///
132/// This trait provides a common interface for floating-point scalar types within
133/// the [`num-valid`](crate) ecosystem.
134#[duplicate_item(
135    T;
136    [f64];
137    [f32];
138)]
139impl FpScalar for T {
140    type Kind = scalar_kind::Real;
141
142    /// Defines the associated real type, which is [`prim@f64`] itself.
143    type RealType = T;
144}
145
146/// Implements the [`FpScalar`] trait for [`num::Complex<f64>`].
147///
148/// This trait provides a common interface for floating-point scalar types within
149/// the [`num-valid`](crate) ecosystem.
150impl<T> FpScalar for Complex<T>
151where
152    Self: RawComplexTrait<RawReal = T>
153        + IntoInner<InnerType = Self>
154        + ScalarCore<RawScalarType = Self>,
155    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar,
156{
157    type Kind = scalar_kind::Complex;
158
159    /// Defines the associated real type for complex numbers, which is [`prim@f64`].
160    type RealType = T;
161}
162//----------------------------------------------------------------------------------------------
163
164//----------------------------------------------------------------------------------------------
165impl<T: NativeReal> Sign for T {
166    /// Returns a number with the magnitude of `self` and the sign of `sign`.
167    #[inline(always)]
168    fn kernel_copysign(self, sign: &Self) -> Self {
169        self.copysign(*sign)
170    }
171
172    /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
173    #[inline(always)]
174    fn kernel_is_sign_negative(&self) -> bool {
175        self.is_sign_negative()
176    }
177
178    /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
179    #[inline(always)]
180    fn kernel_is_sign_positive(&self) -> bool {
181        self.is_sign_positive()
182    }
183
184    /// Computes the signum.
185    ///
186    /// The returned value is:
187    /// - `1.0` if the value is positive, +0.0 or +∞
188    /// - `−1.0` if the value is negative, −0.0 or −∞
189    /// - `NaN` if the value is NaN
190    #[inline(always)]
191    fn kernel_signum(self) -> Self {
192        self.signum()
193    }
194}
195
196impl<T: NativeReal> Rounding for T {
197    /// Returns the smallest integer greater than or equal to `self`.
198    #[inline(always)]
199    fn kernel_ceil(self) -> Self {
200        self.ceil()
201    }
202
203    /// Returns the largest integer smaller than or equal to `self`.
204    #[inline(always)]
205    fn kernel_floor(self) -> Self {
206        self.floor()
207    }
208
209    /// Returns the fractional part of `self`.
210    #[inline(always)]
211    fn kernel_fract(self) -> Self {
212        self.fract()
213    }
214
215    /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
216    #[inline(always)]
217    fn kernel_round(self) -> Self {
218        self.round()
219    }
220
221    /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
222    ///
223    /// This function always returns the precise result.
224    ///
225    /// # Examples
226    /// ```
227    /// use num_valid::{RealScalar, functions::Rounding};
228    ///
229    /// let f = 3.3_f64;
230    /// let g = -3.3_f64;
231    /// let h = 3.5_f64;
232    /// let i = 4.5_f64;
233    ///
234    /// assert_eq!(f.kernel_round_ties_even(), 3.0);
235    /// assert_eq!(g.kernel_round_ties_even(), -3.0);
236    /// assert_eq!(h.kernel_round_ties_even(), 4.0);
237    /// assert_eq!(i.kernel_round_ties_even(), 4.0);
238    /// ```
239    #[inline(always)]
240    fn kernel_round_ties_even(self) -> Self {
241        self.round_ties_even_native_real()
242    }
243
244    /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
245    ///    
246    /// # Examples
247    /// ```
248    /// use num_valid::{RealScalar, functions::Rounding};
249    ///
250    /// let f = 3.7_f64;
251    /// let g = 3.0_f64;
252    /// let h = -3.7_f64;
253    ///
254    /// assert_eq!(f.kernel_trunc(), 3.0);
255    /// assert_eq!(g.kernel_trunc(), 3.0);
256    /// assert_eq!(h.kernel_trunc(), -3.0);
257    /// ```
258    #[inline(always)]
259    fn kernel_trunc(self) -> Self {
260        self.trunc()
261    }
262}
263
264impl<T: NativeReal> Constants for T {
265    /// [Machine epsilon] value for `f64`.
266    ///
267    /// This is the difference between `1.0` and the next larger representable number.
268    ///
269    /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
270    #[inline(always)]
271    fn epsilon() -> Self {
272        <T as Float>::epsilon()
273    }
274
275    /// Build and return the (floating point) value -1. represented by a `f64`.
276    #[inline(always)]
277    fn negative_one() -> Self {
278        T::raw_negative_one(T::MANTISSA_DIGITS)
279    }
280
281    /// Build and return the (floating point) value 0.5 represented by the proper type.
282    #[inline(always)]
283    fn one_div_2() -> Self {
284        T::raw_one_div_2(T::MANTISSA_DIGITS)
285    }
286
287    /// Build and return the (floating point) value `2.0`.
288    #[inline(always)]
289    fn two() -> Self {
290        T::raw_two(T::MANTISSA_DIGITS)
291    }
292
293    /// Build and return the maximum finite value allowed by the current floating point representation.
294    #[inline(always)]
295    fn max_finite() -> Self {
296        <T as Float>::max_value()
297    }
298
299    /// Build and return the minimum finite (i.e., the most negative) value allowed by the current floating point representation.
300    #[inline(always)]
301    fn min_finite() -> Self {
302        <T as Float>::min_value()
303    }
304
305    /// Build and return the (floating point) value `π`.
306    #[inline(always)]
307    fn pi() -> Self {
308        <T as FloatConst>::PI()
309    }
310
311    /// Build and return the (floating point) value `2 π`.
312    #[inline(always)]
313    fn two_pi() -> Self {
314        <T as FloatConst>::TAU()
315    }
316
317    /// Build and return the (floating point) value `π/2`.
318    #[inline(always)]
319    fn pi_div_2() -> Self {
320        <T as FloatConst>::FRAC_PI_2()
321    }
322
323    /// Build and return the natural logarithm of 2, i.e. the (floating point) value `ln(2)`.
324    #[inline(always)]
325    fn ln_2() -> Self {
326        <T as FloatConst>::LN_2()
327    }
328
329    /// Build and return the natural logarithm of 10, i.e. the (floating point) value `ln(10)`.
330    #[inline(always)]
331    fn ln_10() -> Self {
332        <T as FloatConst>::LN_10()
333    }
334
335    /// Build and return the base-10 logarithm of 2, i.e. the (floating point) value `Log_10(2)`.
336    #[inline(always)]
337    fn log10_2() -> Self {
338        <T as FloatConst>::LOG10_2()
339    }
340
341    /// Build and return the base-2 logarithm of 10, i.e. the (floating point) value `Log_2(10)`.
342    #[inline(always)]
343    fn log2_10() -> Self {
344        <T as FloatConst>::LOG2_10()
345    }
346
347    /// Build and return the base-2 logarithm of `e`, i.e. the (floating point) value `Log_2(e)`.
348    #[inline(always)]
349    fn log2_e() -> Self {
350        <T as FloatConst>::LOG2_E()
351    }
352
353    /// Build and return the base-10 logarithm of `e`, i.e. the (floating point) value `Log_10(e)`.
354    #[inline(always)]
355    fn log10_e() -> Self {
356        <T as FloatConst>::LOG10_E()
357    }
358
359    /// Build and return the (floating point) value `e` represented by the proper type.
360    #[inline(always)]
361    fn e() -> Self {
362        <T as FloatConst>::E()
363    }
364}
365
366impl<T: NativeReal> Clamp for T {
367    /// Clamp the value within the specified bounds.
368    ///
369    /// Returns `max` if `self` is greater than `max`, and `min` if `self` is less than `min`.
370    /// Otherwise this returns `self`.
371    ///
372    /// Note that this function returns `NaN` if the initial value was `NaN` as well.
373    ///
374    /// # Panics
375    /// Panics if `min` > `max`, `min` is `NaN`, or `max` is `NaN`.
376    /// ```
377    /// use num_valid::functions::Clamp;
378    ///
379    /// assert!(Clamp::clamp_ref(-3.0f64, &-2.0, &1.0) == -2.0);
380    /// assert!(Clamp::clamp_ref(0.0f64, &-2.0, &1.0) == 0.0);
381    /// assert!(Clamp::clamp_ref(2.0f64, &-2.0, &1.0) == 1.0);
382    /// assert!(Clamp::clamp_ref(f64::NAN, &-2.0, &1.0).is_nan());
383    /// ```
384    #[inline(always)]
385    fn clamp_ref(self, min: &Self, max: &Self) -> Self {
386        <T as Float>::clamp(self, *min, *max)
387    }
388}
389
390impl<T: NativeReal> Classify for T {
391    /// Returns the floating point category of the number. If only one property is going to be tested,
392    /// it is generally faster to use the specific predicate instead.
393    /// ```
394    /// use num_valid::functions::Classify;
395    /// use std::num::FpCategory;
396    ///
397    /// let num = 12.4_f64;
398    /// let inf = f64::INFINITY;
399    ///
400    /// assert_eq!(Classify::classify(&num), FpCategory::Normal);
401    /// assert_eq!(Classify::classify(&inf), FpCategory::Infinite);
402    /// ```
403    #[inline(always)]
404    fn classify(&self) -> FpCategory {
405        <T as Float>::classify(*self)
406    }
407}
408
409impl<T: NativeReal> ExpM1 for T {
410    /// Returns `e^(self) - 1`` in a way that is accurate even if the number is close to zero.
411    #[inline(always)]
412    fn exp_m1(self) -> Self {
413        <T as Float>::exp_m1(self)
414    }
415}
416
417impl<T: NativeReal> Hypot for T {
418    /// Compute the distance between the origin and a point (`self`, `other`) on the Euclidean plane.
419    /// Equivalently, compute the length of the hypotenuse of a right-angle triangle with other sides having length `self.abs()` and `other.abs()`.
420    #[inline(always)]
421    fn hypot(self, other: &Self) -> Self {
422        <T as Float>::hypot(self, *other)
423    }
424}
425
426impl<T: NativeReal> Ln1p for T {
427    /// Returns `ln(1. + self)` (natural logarithm) more accurately than if the operations were performed separately.
428    #[inline(always)]
429    fn ln_1p(self) -> Self {
430        <T as Float>::ln_1p(self)
431    }
432}
433
434impl<T: NativeReal> TotalCmp for T {
435    #[inline(always)]
436    fn total_cmp(&self, other: &Self) -> Ordering {
437        self.raw_total_cmp(other)
438    }
439}
440
441impl<T: NativeReal> PrecisionBits for T {
442    #[inline(always)]
443    fn precision_bits(&self) -> u32 {
444        T::MANTISSA_DIGITS
445    }
446}
447
448#[duplicate_item(
449    T;
450    [f64];
451    [f32];
452)]
453impl RealScalar for T {
454    type RawReal = T;
455
456    /// Multiplies two products and adds them in one fused operation, rounding to the nearest with only one rounding error.
457    /// `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.
458    #[inline(always)]
459    fn kernel_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
460        self.mul_add_assign(*mul, add_mul1 * add_mul2);
461    }
462
463    /// Multiplies two products and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
464    /// `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.
465    #[inline(always)]
466    fn kernel_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
467        self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
468    }
469
470    // Native raw types have no validation policy: try_convert already validated the input.
471    #[inline(always)]
472    fn try_new_raw(value: Self::RawReal) -> Result<Self, ErrorsValidationRawReal<Self::RawReal>> {
473        Ok(value)
474    }
475
476    #[inline(always)]
477    fn target_precision() -> u32 {
478        T::MANTISSA_DIGITS
479    }
480}
481
482impl<T> ComplexScalarConstructors for Complex<T>
483where
484    Self: RawComplexTrait<RawReal = T>
485        + IntoInner<InnerType = Self>
486        + ScalarCore<RawScalarType = Self>,
487    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
488{
489    type RawComplex = Complex<T>;
490
491    fn try_new_complex(
492        real_part: T,
493        imag_part: T,
494    ) -> Result<Self, ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>> {
495        validate_complex_from_parts(&real_part, &imag_part, T::validate_raw_scalar_ref)
496            .map(|_| Complex::new(real_part, imag_part))
497    }
498}
499
500/// Implement the [`ComplexScalarGetParts`] trait for the `Complex<f64>` type.
501impl<T> ComplexScalarGetParts for Complex<T>
502where
503    Self: RawComplexTrait<RawReal = T>
504        + IntoInner<InnerType = Self>
505        + ScalarCore<RawScalarType = Self>,
506    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
507{
508    /// Get the real part of the complex number.
509    #[inline(always)]
510    fn real_part(&self) -> T {
511        self.re
512    }
513
514    /// Get the imaginary part of the complex number.
515    #[inline(always)]
516    fn imag_part(&self) -> T {
517        self.im
518    }
519
520    /// Returns a reference to the raw real part of the complex number.
521    #[inline(always)]
522    fn raw_real_part(&self) -> &T {
523        &self.re
524    }
525
526    /// Returns a reference to the raw imaginary part of the complex number.
527    #[inline(always)]
528    fn raw_imag_part(&self) -> &T {
529        &self.im
530    }
531}
532
533impl<T> ComplexScalarSetParts for Complex<T>
534where
535    Self: RawComplexTrait<RawReal = T>
536        + IntoInner<InnerType = Self>
537        + ScalarCore<RawScalarType = Self>,
538    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
539{
540    /// Set the value of the real part.
541    ///
542    /// # Panics
543    /// In **debug builds**, this will panic if `real_part` is not finite.
544    /// This check is disabled in release builds for performance.
545    #[inline(always)]
546    fn set_real_part(&mut self, real_part: T) {
547        debug_assert!(
548            real_part.is_finite(),
549            "The real part is not finite (i.e. is infinite or NaN)."
550        );
551        self.re = real_part;
552    }
553
554    /// Set the value of the imaginary part.
555    ///
556    /// # Panics
557    /// In **debug builds**, this will panic if `imag_part` is not finite.
558    /// This check is disabled in release builds for performance.
559    #[inline(always)]
560    fn set_imaginary_part(&mut self, imag_part: T) {
561        debug_assert!(
562            imag_part.is_finite(),
563            "The imaginary part is not finite (i.e. is infinite or NaN)."
564        );
565        self.im = imag_part;
566    }
567}
568
569impl<T> ComplexScalarMutateParts for Complex<T>
570where
571    Self: RawComplexTrait<RawReal = T>
572        + IntoInner<InnerType = Self>
573        + ScalarCore<RawScalarType = Self>,
574    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
575{
576    /// Add the value of the the real coefficient `c` to real part of `self`.
577    ///
578    /// # Panics
579    /// In **debug builds**, this will panic if the real part of `self` is not finite after the addition.
580    /// This check is disabled in release builds for performance.
581    #[inline(always)]
582    fn add_to_real_part(&mut self, c: &T) {
583        self.re += c;
584
585        debug_assert!(
586            self.re.is_finite(),
587            "The real part is not finite (i.e. is infinite or NaN)."
588        );
589    }
590
591    /// Add the value of the the real coefficient `c` to imaginary part of `self`.
592    ///
593    /// # Panics
594    /// In **debug builds**, this will panic if the imaginary part of `self` is not finite after the addition.
595    /// This check is disabled in release builds for performance.
596    #[inline(always)]
597    fn add_to_imaginary_part(&mut self, c: &T) {
598        self.im += c;
599
600        debug_assert!(
601            self.im.is_finite(),
602            "The imaginary part is not finite (i.e. is infinite or NaN)."
603        );
604    }
605
606    /// Multiply the value of the real part by the real coefficient `c`.
607    ///
608    /// # Panics
609    /// In **debug builds**, this will panic if the real part of `self` is not finite after the multiplication.
610    /// This check is disabled in release builds for performance.
611    #[inline(always)]
612    fn multiply_real_part(&mut self, c: &T) {
613        self.re *= c;
614
615        debug_assert!(
616            self.re.is_finite(),
617            "The real part is not finite (i.e. is infinite or NaN)."
618        );
619    }
620
621    /// Multiply the value of the imaginary part by the real coefficient `c`.
622    ///
623    /// # Panics
624    /// In **debug builds**, this will panic if the imaginary part of `self` is not finite after the multiplication.
625    /// This check is disabled in release builds for performance.
626    #[inline(always)]
627    fn multiply_imaginary_part(&mut self, c: &T) {
628        self.im *= c;
629
630        debug_assert!(
631            self.im.is_finite(),
632            "The imaginary part is not finite (i.e. is infinite or NaN)."
633        );
634    }
635}
636
637impl<T> ComplexScalar for Complex<T>
638where
639    Self: RawComplexTrait<RawReal = T>
640        + IntoInner<InnerType = Self>
641        + ScalarCore<RawScalarType = Self>,
642    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RealScalar<RawReal = T>,
643{
644    fn into_parts(self) -> (Self::RealType, Self::RealType) {
645        (self.re, self.im)
646    }
647}
648
649//----------------------------------------------------------------------------------------------
650
651//----------------------------------------------------------------------------------------------
652impl<T> MulAddRef for T
653where
654    T: MulAdd<Output = T> + Copy,
655{
656    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
657    ///
658    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
659    #[inline(always)]
660    fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
661        Self::mul_add(self, *b, *c)
662    }
663}
664//----------------------------------------------------------------------------------------------
665
666// =============================================================================
667// Implementations for f64/f32 and Complex<f64>/Complex<f32>
668// =============================================================================
669
670impl<T: NativeReal> RawScalarTrigonometric for T {
671    #[duplicate_item(
672        unchecked_method method;
673        [unchecked_sin]  [sin];
674        [unchecked_asin] [asin];
675        [unchecked_cos]  [cos];
676        [unchecked_acos] [acos];
677        [unchecked_tan]  [tan];
678        [unchecked_atan] [atan];
679    )]
680    #[inline(always)]
681    fn unchecked_method(self) -> Self {
682        T::method(self)
683    }
684}
685
686impl<T: NativeReal> RawScalarTrigonometric for Complex<T> {
687    #[duplicate_item(
688        unchecked_method method;
689        [unchecked_sin]  [sin];
690        [unchecked_asin] [asin];
691        [unchecked_cos]  [cos];
692        [unchecked_acos] [acos];
693        [unchecked_tan]  [tan];
694        [unchecked_atan] [atan];
695    )]
696    #[inline(always)]
697    fn unchecked_method(self) -> Self {
698        Complex::<T>::method(self)
699    }
700}
701
702impl<T: NativeReal> RawScalarHyperbolic for T {
703    #[duplicate_item(
704        unchecked_method  method;
705        [unchecked_sinh]  [sinh];
706        [unchecked_asinh] [asinh];
707        [unchecked_cosh]  [cosh];
708        [unchecked_acosh] [acosh];
709        [unchecked_tanh]  [tanh];
710        [unchecked_atanh] [atanh];
711    )]
712    #[inline(always)]
713    fn unchecked_method(self) -> Self {
714        T::method(self)
715    }
716}
717
718impl<T: NativeReal> RawScalarHyperbolic for Complex<T> {
719    #[duplicate_item(
720        unchecked_method  method;
721        [unchecked_sinh]  [sinh];
722        [unchecked_asinh] [asinh];
723        [unchecked_cosh]  [cosh];
724        [unchecked_acosh] [acosh];
725        [unchecked_tanh]  [tanh];
726        [unchecked_atanh] [atanh];
727    )]
728    #[inline(always)]
729    fn unchecked_method(self) -> Self {
730        Complex::<T>::method(self)
731    }
732}
733
734impl<T: NativeReal> RawScalarPow for T {
735    #[duplicate_item(
736        unchecked_method             exponent_type;
737        [unchecked_pow_exponent_i8]  [i8];
738        [unchecked_pow_exponent_i16] [i16];
739        [unchecked_pow_exponent_u8]  [u8];
740        [unchecked_pow_exponent_u16] [u16];
741    )]
742    #[inline(always)]
743    fn unchecked_method(self, exponent: &exponent_type) -> T {
744        T::powi(self, (*exponent).into())
745    }
746
747    #[inline(always)]
748    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
749        T::powi(self, *exponent)
750    }
751
752    #[duplicate_item(
753        unchecked_method               exponent_type;
754        [unchecked_pow_exponent_i64]   [i64];
755        [unchecked_pow_exponent_i128]  [i128];
756        [unchecked_pow_exponent_isize] [isize];
757        [unchecked_pow_exponent_u32]   [u32];
758        [unchecked_pow_exponent_u64]   [u64];
759        [unchecked_pow_exponent_u128]  [u128];
760        [unchecked_pow_exponent_usize] [usize];
761    )]
762    #[inline(always)]
763    fn unchecked_method(self, exponent: &exponent_type) -> T {
764        T::powi(
765            self,
766            (*exponent)
767                .try_into()
768                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
769        )
770    }
771}
772
773impl<T: NativeReal> RawScalarValidate for T {
774    type ValidationError = ErrorsValidationRawReal<T>;
775
776    fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
777        match self.classify() {
778            FpCategory::Nan => Err(ErrorsValidationRawReal::IsNaN {
779                value: *self,
780                backtrace: capture_backtrace(),
781            }),
782            FpCategory::Infinite => {
783                if self.is_sign_positive() {
784                    Err(ErrorsValidationRawReal::IsPosInfinity {
785                        backtrace: capture_backtrace(),
786                    })
787                } else {
788                    Err(ErrorsValidationRawReal::IsNegInfinity {
789                        backtrace: capture_backtrace(),
790                    })
791                }
792            }
793            FpCategory::Subnormal => Err(ErrorsValidationRawReal::IsSubnormal {
794                value: *self,
795                backtrace: capture_backtrace(),
796            }),
797            FpCategory::Normal | FpCategory::Zero => Ok(()),
798        }
799    }
800}
801
802#[inline(always)]
803fn debug_assert_if_invalid_precision<T: NativeReal>(precision: u32) {
804    debug_assert_eq!(
805        precision,
806        T::MANTISSA_DIGITS,
807        "Precision {precision} must be equal to the mantissa digits for type {} (mantissa digits = {}).",
808        std::any::type_name::<T>(),
809        T::MANTISSA_DIGITS
810    );
811}
812
813impl<T: NativeReal> RawScalarTrait for T {
814    #[inline(always)]
815    fn raw_zero(_precision: u32) -> T {
816        debug_assert_if_invalid_precision::<T>(_precision);
817        T::zero()
818    }
819
820    #[inline(always)]
821    fn is_zero(&self) -> bool {
822        <Self as Zero>::is_zero(self)
823    }
824    #[inline(always)]
825    fn raw_one(_precision: u32) -> T {
826        debug_assert_if_invalid_precision::<T>(_precision);
827        T::one()
828    }
829
830    #[duplicate_item(
831        unchecked_method       method;
832        [unchecked_reciprocal] [recip];
833        [unchecked_exp]        [exp];
834        [unchecked_sqrt]       [sqrt];
835        [unchecked_ln]         [ln];
836        [unchecked_log2]       [log2];
837        [unchecked_log10]      [log10];
838    )]
839    #[inline(always)]
840    fn unchecked_method(self) -> T {
841        <T as Float>::method(self)
842    }
843
844    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
845    ///
846    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
847    #[inline(always)]
848    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
849        Float::mul_add(self, *b, *c)
850    }
851
852    #[inline(always)]
853    fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
854        debug_assert!(
855            self.is_finite(),
856            concat!(
857                "Hashing a non-finite ",
858                stringify!(T),
859                " floating-point value (i.e., NaN or Infinity) may lead to inconsistent results."
860            )
861        );
862        let zero = T::zero();
863        if self == &zero {
864            // Hash all zeros (positive and negative) to the same value
865            zero.to_bits_native_real().hash(state);
866        } else {
867            self.to_bits_native_real().hash(state);
868        }
869    }
870}
871
872#[duplicate_item(
873    T cast_int_to_float from_raw_real;
874    [f64] [to_f64()]  [from_f64];
875    [f32] [to_f32()]  [from_f32];
876)]
877impl RawRealTrait for T {
878    type RawComplex = Complex<T>;
879
880    #[inline(always)]
881    fn unchecked_abs(self) -> Self {
882        <T as Float>::abs(self)
883    }
884
885    #[inline(always)]
886    fn unchecked_atan2(self, denominator: &Self) -> Self {
887        <T as Float>::atan2(self, *denominator)
888    }
889
890    #[inline(always)]
891    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
892        <T as Float>::powf(self, *exponent)
893    }
894
895    #[inline(always)]
896    fn unchecked_hypot(self, other: &Self) -> Self {
897        <T as Float>::hypot(self, *other)
898    }
899
900    #[inline(always)]
901    fn unchecked_ln_1p(self) -> Self {
902        <T as Float>::ln_1p(self)
903    }
904
905    #[inline(always)]
906    fn unchecked_exp_m1(self) -> Self {
907        <T as Float>::exp_m1(self)
908    }
909
910    /// Multiplies two pairs and adds them in one fused operation, rounding to the nearest with only one rounding error.
911    /// `a.unchecked_mul_add_mul_mut(&b, &c, &d)` produces a result like `&a * &b + &c * &d`, but stores the result in `a` using its precision.
912    #[inline(always)]
913    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
914        self.mul_add_assign(*mul, add_mul1 * add_mul2);
915    }
916
917    /// Multiplies two pairs and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
918    /// `a.unchecked_mul_sub_mul_mut(&b, &c, &d)` produces a result like `&a * &b - &c * &d`, but stores the result in `a` using its precision.
919    #[inline(always)]
920    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
921        self.mul_add_assign(*mul, -sub_mul1 * sub_mul2);
922    }
923
924    #[inline(always)]
925    fn raw_total_cmp(&self, other: &Self) -> Ordering {
926        T::total_cmp(self, other)
927    }
928
929    /// Clamps the value within the specified bounds.
930    #[inline(always)]
931    fn raw_clamp(self, min: &Self, max: &Self) -> Self {
932        <T as Float>::clamp(self, *min, *max)
933    }
934
935    #[inline(always)]
936    fn raw_classify(&self) -> FpCategory {
937        <T as Float>::classify(*self)
938    }
939
940    #[inline(always)]
941    fn raw_two(_precision: u32) -> Self {
942        debug_assert_if_invalid_precision::<T>(_precision);
943        2.
944    }
945
946    #[inline(always)]
947    fn raw_one_div_2(_precision: u32) -> Self {
948        debug_assert_if_invalid_precision::<T>(_precision);
949        0.5
950    }
951
952    #[inline(always)]
953    fn raw_pi(_precision: u32) -> Self {
954        debug_assert_if_invalid_precision::<T>(_precision);
955        <T as FloatConst>::PI()
956    }
957
958    #[inline(always)]
959    fn raw_two_pi(_precision: u32) -> Self {
960        debug_assert_if_invalid_precision::<T>(_precision);
961        <T as FloatConst>::TAU()
962    }
963
964    #[inline(always)]
965    fn raw_pi_div_2(_precision: u32) -> Self {
966        debug_assert_if_invalid_precision::<T>(_precision);
967        <T as FloatConst>::FRAC_PI_2()
968    }
969
970    #[inline(always)]
971    fn raw_max_finite(_precision: u32) -> Self {
972        debug_assert_if_invalid_precision::<T>(_precision);
973        <T as Float>::max_value()
974    }
975
976    #[inline(always)]
977    fn raw_min_finite(_precision: u32) -> Self {
978        debug_assert_if_invalid_precision::<T>(_precision);
979        <T as Float>::min_value()
980    }
981
982    #[inline(always)]
983    fn raw_epsilon(_precision: u32) -> Self {
984        debug_assert_if_invalid_precision::<T>(_precision);
985        <T as Float>::epsilon()
986    }
987
988    #[inline(always)]
989    fn raw_ln_2(_precision: u32) -> Self {
990        debug_assert_if_invalid_precision::<T>(_precision);
991        <T as FloatConst>::LN_2()
992    }
993
994    #[inline(always)]
995    fn raw_ln_10(_precision: u32) -> Self {
996        debug_assert_if_invalid_precision::<T>(_precision);
997        <T as FloatConst>::LN_10()
998    }
999
1000    #[inline(always)]
1001    fn raw_log10_2(_precision: u32) -> Self {
1002        debug_assert_if_invalid_precision::<T>(_precision);
1003        <T as FloatConst>::LOG10_2()
1004    }
1005
1006    #[inline(always)]
1007    fn raw_log2_10(_precision: u32) -> Self {
1008        debug_assert_if_invalid_precision::<T>(_precision);
1009        <T as FloatConst>::LOG2_10()
1010    }
1011
1012    #[inline(always)]
1013    fn raw_log2_e(_precision: u32) -> Self {
1014        debug_assert_if_invalid_precision::<T>(_precision);
1015        <T as FloatConst>::LOG2_E()
1016    }
1017
1018    #[inline(always)]
1019    fn raw_log10_e(_precision: u32) -> Self {
1020        debug_assert_if_invalid_precision::<T>(_precision);
1021        <T as FloatConst>::LOG10_E()
1022    }
1023
1024    #[inline(always)]
1025    fn raw_e(_precision: u32) -> Self {
1026        debug_assert_if_invalid_precision::<T>(_precision);
1027        <T as FloatConst>::E()
1028    }
1029
1030    #[inline(always)]
1031    fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<T, usize>> {
1032        if !self.is_finite() {
1033            return Err(ErrorsRawRealToInteger::NotFinite {
1034                value: self,
1035                backtrace: capture_backtrace(),
1036            });
1037        }
1038
1039        match self.checked_as::<usize>() {
1040            Some(value) => Ok(value),
1041            None => Err(ErrorsRawRealToInteger::OutOfRange {
1042                value: self,
1043                min: usize::MIN,
1044                max: usize::MAX,
1045                backtrace: capture_backtrace(),
1046            }),
1047        }
1048    }
1049
1050    fn unchecked_mul_assign_integer<I>(&mut self, integer: I)
1051    where
1052        I: IntegerScalar,
1053    {
1054        let as_raw_real = integer
1055            .cast_int_to_float
1056            .expect("Failed to cast integer to raw float");
1057        debug_assert!(
1058            I::from_raw_real(as_raw_real) == Some(integer),
1059            "unchecked_mul_assign_integer requires an exact conversion, but the integer is not exactly representable in the target raw real type"
1060        );
1061        *self *= as_raw_real;
1062    }
1063
1064    fn unchecked_div_assign_integer<I>(&mut self, integer: I)
1065    where
1066        I: IntegerScalar,
1067    {
1068        let as_raw_real = integer
1069            .cast_int_to_float
1070            .expect("Failed to cast integer to raw float");
1071        debug_assert!(
1072            I::from_raw_real(as_raw_real) == Some(integer),
1073            "unchecked_div_assign_integer requires an exact conversion, but the integer is not exactly representable in the target raw real type"
1074        );
1075        *self /= as_raw_real;
1076    }
1077}
1078
1079impl<T: NativeReal> RawScalarPow for Complex<T> {
1080    #[duplicate_item(
1081        unchecked_method             exponent_type;
1082        [unchecked_pow_exponent_i8]  [i8];
1083        [unchecked_pow_exponent_i16] [i16];
1084    )]
1085    #[inline(always)]
1086    fn unchecked_method(self, exponent: &exponent_type) -> Self {
1087        Complex::<T>::powi(&self, (*exponent).into())
1088    }
1089
1090    #[inline(always)]
1091    fn unchecked_pow_exponent_i32(self, exponent: &i32) -> Self {
1092        Complex::<T>::powi(&self, *exponent)
1093    }
1094
1095    #[duplicate_item(
1096        unchecked_method               exponent_type;
1097        [unchecked_pow_exponent_i64]   [i64];
1098        [unchecked_pow_exponent_i128]  [i128];
1099        [unchecked_pow_exponent_isize] [isize];
1100    )]
1101    #[inline(always)]
1102    fn unchecked_method(self, exponent: &exponent_type) -> Self {
1103        Complex::<T>::powi(
1104            &self,
1105            (*exponent)
1106                .try_into()
1107                .expect("The exponent {exponent} cannot be converted to an integer of type i32"),
1108        )
1109    }
1110
1111    #[duplicate_item(
1112        unchecked_method             exponent_type;
1113        [unchecked_pow_exponent_u8]  [u8];
1114        [unchecked_pow_exponent_u16] [u16];
1115    )]
1116    #[inline(always)]
1117    fn unchecked_method(self, exponent: &exponent_type) -> Self {
1118        Complex::<T>::powu(&self, (*exponent).into())
1119    }
1120
1121    #[inline(always)]
1122    fn unchecked_pow_exponent_u32(self, exponent: &u32) -> Self {
1123        Complex::<T>::powu(&self, *exponent)
1124    }
1125
1126    #[duplicate_item(
1127        unchecked_method               exponent_type;
1128        [unchecked_pow_exponent_u64]   [u64];
1129        [unchecked_pow_exponent_u128]  [u128];
1130        [unchecked_pow_exponent_usize] [usize];
1131    )]
1132    #[inline(always)]
1133    fn unchecked_method(self, exponent: &exponent_type) -> Self {
1134        Complex::<T>::powu(
1135            &self,
1136            (*exponent)
1137                .try_into()
1138                .expect("The exponent {exponent} cannot be converted to an integer of type u32"),
1139        )
1140    }
1141}
1142
1143impl<T: NativeReal> RawScalarValidate for Complex<T> {
1144    type ValidationError = ErrorsValidationRawComplex<ErrorsValidationRawReal<T>>;
1145
1146    #[inline(always)]
1147    fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
1148        validate_complex_from_parts(&self.re, &self.im, T::validate_raw_scalar_ref)
1149    }
1150}
1151
1152impl<T: NativeReal> RawScalarTrait for Complex<T> {
1153    #[inline(always)]
1154    fn raw_zero(_precision: u32) -> Self {
1155        debug_assert_if_invalid_precision::<T>(_precision);
1156        Complex::new(T::zero(), T::zero())
1157    }
1158
1159    #[inline(always)]
1160    fn is_zero(&self) -> bool {
1161        <Self as Zero>::is_zero(self)
1162    }
1163
1164    #[inline(always)]
1165    fn raw_one(_precision: u32) -> Self {
1166        debug_assert_if_invalid_precision::<T>(_precision);
1167        Complex::new(T::one(), T::zero())
1168    }
1169
1170    #[duplicate_item(
1171        unchecked_method       method;
1172        [unchecked_exp]        [exp];
1173        [unchecked_sqrt]       [sqrt];
1174        [unchecked_ln]         [ln];
1175        [unchecked_log10]      [log10];
1176    )]
1177    #[inline(always)]
1178    fn unchecked_method(self) -> Self {
1179        Complex::<T>::method(self)
1180    }
1181
1182    #[inline(always)]
1183    fn unchecked_reciprocal(self) -> Self {
1184        Complex::<T>::inv(&self)
1185    }
1186
1187    #[inline(always)]
1188    fn unchecked_log2(self) -> Self {
1189        Complex::<T>::ln(self) / <T as FloatConst>::LN_2()
1190    }
1191
1192    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
1193    ///
1194    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
1195    #[inline(always)]
1196    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
1197        Complex::<T>::mul_add(self, *b, *c)
1198    }
1199
1200    #[inline(always)]
1201    fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
1202        self.re.compute_hash_raw_scalar(state);
1203        self.im.compute_hash_raw_scalar(state);
1204    }
1205}
1206
1207impl<T> RawComplexTrait for Complex<T>
1208where
1209    //    T: RawRealTrait<RawComplex = Self>,
1210    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>> + RawRealTrait<RawComplex = Self>,
1211{
1212    type RawReal = T;
1213
1214    fn new_unchecked_raw_complex(real: T, imag: T) -> Self {
1215        Complex::<T>::new(real, imag)
1216    }
1217
1218    /// Returns a mutable reference to the real part of the complex number.
1219    fn mut_raw_real_part(&mut self) -> &mut T {
1220        &mut self.re
1221    }
1222
1223    /// Returns a mutable reference to the imaginary part of the complex number.
1224    fn mut_raw_imag_part(&mut self) -> &mut T {
1225        &mut self.im
1226    }
1227
1228    #[inline(always)]
1229    fn unchecked_abs(self) -> T {
1230        Complex::<T>::norm(self)
1231    }
1232
1233    #[inline(always)]
1234    fn raw_real_part(&self) -> &T {
1235        &self.re
1236    }
1237
1238    #[inline(always)]
1239    fn raw_imag_part(&self) -> &T {
1240        &self.im
1241    }
1242
1243    #[inline(always)]
1244    fn unchecked_arg(self) -> T {
1245        Complex::<T>::arg(self)
1246    }
1247
1248    #[inline(always)]
1249    fn unchecked_pow_exponent_real(self, exponent: &T) -> Self {
1250        Complex::<T>::powf(self, *exponent)
1251    }
1252}
1253
1254#[cfg(test)]
1255mod tests {
1256    use crate::{
1257        core::errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal},
1258        functions::TotalCmp,
1259    };
1260    use std::assert_matches;
1261
1262    mod real {
1263        use super::*;
1264        use crate::Constants;
1265
1266        #[test]
1267        fn test_constants() {
1268            assert_eq!(<f64 as Constants>::epsilon(), f64::EPSILON);
1269            assert_eq!(<f64 as Constants>::negative_one(), -1.0);
1270            assert_eq!(<f64 as Constants>::one_div_2(), 0.5);
1271            assert_eq!(<f64 as Constants>::two(), 2.0);
1272            assert_eq!(<f64 as Constants>::max_finite(), f64::MAX);
1273            assert_eq!(<f64 as Constants>::min_finite(), f64::MIN);
1274            assert_eq!(<f64 as Constants>::pi(), std::f64::consts::PI);
1275            assert_eq!(<f64 as Constants>::two_pi(), std::f64::consts::PI * 2.0);
1276            assert_eq!(<f64 as Constants>::pi_div_2(), std::f64::consts::FRAC_PI_2);
1277            assert_eq!(<f64 as Constants>::ln_2(), std::f64::consts::LN_2);
1278            assert_eq!(<f64 as Constants>::ln_10(), std::f64::consts::LN_10);
1279            assert_eq!(<f64 as Constants>::log10_2(), std::f64::consts::LOG10_2);
1280            assert_eq!(<f64 as Constants>::log2_10(), std::f64::consts::LOG2_10);
1281            assert_eq!(<f64 as Constants>::log2_e(), std::f64::consts::LOG2_E);
1282            assert_eq!(<f64 as Constants>::log10_e(), std::f64::consts::LOG10_E);
1283            assert_eq!(<f64 as Constants>::e(), std::f64::consts::E);
1284        }
1285
1286        #[test]
1287        #[allow(clippy::op_ref)]
1288        fn multiply_ref() {
1289            let a = 2.0f64;
1290            let b = 3.0f64;
1291            let result = a * &b;
1292            assert_eq!(result, 6.0);
1293        }
1294
1295        #[test]
1296        fn total_cmp() {
1297            let a = 2.0f64;
1298            let b = 3.0f64;
1299            assert_eq!(
1300                <f64 as TotalCmp>::total_cmp(&a, &b),
1301                std::cmp::Ordering::Less
1302            );
1303            assert_eq!(
1304                <f64 as TotalCmp>::total_cmp(&b, &a),
1305                std::cmp::Ordering::Greater
1306            );
1307            assert_eq!(
1308                <f64 as TotalCmp>::total_cmp(&a, &a),
1309                std::cmp::Ordering::Equal
1310            );
1311        }
1312
1313        mod from_f64 {
1314            use crate::{backends::native::validated::RealNative64StrictFinite, *};
1315
1316            #[test]
1317            fn test_from_f64_valid_constants() {
1318                // Test with mathematical constants (known valid values)
1319                let pi = RealNative64StrictFinite::from_f64(std::f64::consts::PI);
1320                assert_eq!(pi.as_raw_scalar_ref(), &std::f64::consts::PI);
1321
1322                let e = RealNative64StrictFinite::from_f64(std::f64::consts::E);
1323                assert_eq!(e.as_raw_scalar_ref(), &std::f64::consts::E);
1324
1325                let sqrt2 = RealNative64StrictFinite::from_f64(std::f64::consts::SQRT_2);
1326                assert_eq!(sqrt2.as_raw_scalar_ref(), &std::f64::consts::SQRT_2);
1327            }
1328
1329            #[test]
1330            fn test_from_f64_valid_values() {
1331                // Test with regular valid values
1332                let x = RealNative64StrictFinite::from_f64(42.0);
1333                assert_eq!(x.as_raw_scalar_ref(), &42.0);
1334
1335                let y = RealNative64StrictFinite::from_f64(-3.0);
1336                assert_eq!(y.as_raw_scalar_ref(), &-3.0);
1337
1338                let z = RealNative64StrictFinite::from_f64(0.0);
1339                assert_eq!(z.as_raw_scalar_ref(), &0.0);
1340            }
1341
1342            #[test]
1343            #[should_panic(
1344                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1345            )]
1346            fn test_from_f64_nan_panics() {
1347                let _ = RealNative64StrictFinite::from_f64(f64::NAN);
1348            }
1349
1350            #[test]
1351            #[should_panic(
1352                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1353            )]
1354            fn test_from_f64_infinity_panics() {
1355                let _ = RealNative64StrictFinite::from_f64(f64::INFINITY);
1356            }
1357
1358            #[test]
1359            #[should_panic(
1360                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1361            )]
1362            fn test_from_f64_neg_infinity_panics() {
1363                let _ = RealNative64StrictFinite::from_f64(f64::NEG_INFINITY);
1364            }
1365
1366            #[test]
1367            #[should_panic(
1368                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
1369            )]
1370            fn test_from_f64_subnormal_panics() {
1371                // Test with a subnormal value (very small but non-zero)
1372                let _ = RealNative64StrictFinite::from_f64(f64::MIN_POSITIVE / 2.0);
1373            }
1374
1375            #[test]
1376            fn test_try_from_f64_error_handling() {
1377                // Verify try_from_f64 still works for error handling
1378                assert!(RealNative64StrictFinite::try_from_f64(f64::NAN).is_err());
1379                assert!(RealNative64StrictFinite::try_from_f64(f64::INFINITY).is_err());
1380                assert!(RealNative64StrictFinite::try_from_f64(f64::NEG_INFINITY).is_err());
1381
1382                // Valid values work with try_from_f64
1383                assert!(RealNative64StrictFinite::try_from_f64(3.0).is_ok());
1384                assert!(RealNative64StrictFinite::try_from_f64(0.0).is_ok());
1385            }
1386        }
1387
1388        mod truncate_to_usize {
1389            use crate::{core::errors::ErrorsRawRealToInteger, kernels::RawRealTrait};
1390
1391            #[test]
1392            fn test_f64_truncate_to_usize_valid() {
1393                assert_eq!(42.0_f64.truncate_to_usize().unwrap(), 42);
1394                assert_eq!(42.9_f64.truncate_to_usize().unwrap(), 42);
1395                assert_eq!(0.0_f64.truncate_to_usize().unwrap(), 0);
1396            }
1397
1398            #[test]
1399            fn test_f64_truncate_to_usize_not_finite() {
1400                assert!(matches!(
1401                    f64::NAN.truncate_to_usize(),
1402                    Err(ErrorsRawRealToInteger::NotFinite { .. })
1403                ));
1404                assert!(matches!(
1405                    f64::INFINITY.truncate_to_usize(),
1406                    Err(ErrorsRawRealToInteger::NotFinite { .. })
1407                ));
1408                assert!(matches!(
1409                    f64::NEG_INFINITY.truncate_to_usize(),
1410                    Err(ErrorsRawRealToInteger::NotFinite { .. })
1411                ));
1412            }
1413
1414            #[test]
1415            fn test_f64_truncate_to_usize_out_of_range() {
1416                // Negative value
1417                assert!(matches!(
1418                    (-1.0_f64).truncate_to_usize(),
1419                    Err(ErrorsRawRealToInteger::OutOfRange { .. })
1420                ));
1421                // Value too large
1422                assert!(matches!(
1423                    ((usize::MAX as f64) + 1.0).truncate_to_usize(),
1424                    Err(ErrorsRawRealToInteger::OutOfRange { .. })
1425                ));
1426
1427                // this is exactly usize::MAX, which is out of range because f64 cannot represent all integers above 2^53 exactly
1428                assert!(matches!(
1429                    (usize::MAX as f64).truncate_to_usize(),
1430                    Err(ErrorsRawRealToInteger::OutOfRange { .. })
1431                ));
1432            }
1433        }
1434
1435        mod mul_assign_integer {
1436            use crate::kernels::RawRealTrait;
1437
1438            #[test]
1439            fn f64_multiplies_by_signed_integer() {
1440                let mut real = 3.5_f64;
1441                real.unchecked_mul_assign_integer(-4_i32);
1442                assert_eq!(real, -14.0);
1443            }
1444
1445            #[test]
1446            fn f32_multiplies_by_unsigned_integer() {
1447                let mut real = 3.5_f32;
1448                real.unchecked_mul_assign_integer(4_u16);
1449                assert_eq!(real, 14.0);
1450            }
1451
1452            #[test]
1453            fn zeroes_the_value() {
1454                let mut real_f64 = 3.5_f64;
1455                let mut real_f32 = 3.5_f32;
1456
1457                real_f64.unchecked_mul_assign_integer(0_i8);
1458                real_f32.unchecked_mul_assign_integer(0_i8);
1459
1460                assert_eq!(real_f64, 0.0);
1461                assert_eq!(real_f32, 0.0);
1462            }
1463
1464            #[test]
1465            fn f64_accepts_integer_at_precision_boundary() {
1466                let mut real = 1.0_f64;
1467                real.unchecked_mul_assign_integer(1_i128 << 53);
1468                assert_eq!(real, 9_007_199_254_740_992.0);
1469            }
1470
1471            #[test]
1472            #[cfg(debug_assertions)]
1473            #[should_panic(expected = "unchecked_mul_assign_integer requires an exact conversion")]
1474            fn f64_panics_on_non_exact_conversion() {
1475                let mut real = 1.0_f64;
1476                real.unchecked_mul_assign_integer((1_i128 << 53) + 1);
1477            }
1478        }
1479
1480        mod div_assign_integer {
1481            use crate::kernels::RawRealTrait;
1482
1483            #[test]
1484            fn f64_divides_by_signed_integer() {
1485                let mut real = 14.0_f64;
1486                real.unchecked_div_assign_integer(-4_i32);
1487                assert_eq!(real, -3.5);
1488            }
1489
1490            #[test]
1491            fn f32_divides_by_unsigned_integer() {
1492                let mut real = 14.0_f32;
1493                real.unchecked_div_assign_integer(4_u16);
1494                assert_eq!(real, 3.5);
1495            }
1496
1497            #[test]
1498            fn f64_accepts_integer_at_precision_boundary() {
1499                let mut real = 9_007_199_254_740_992.0_f64;
1500                real.unchecked_div_assign_integer(1_i128 << 53);
1501                assert_eq!(real, 1.0);
1502            }
1503
1504            #[test]
1505            #[cfg(debug_assertions)]
1506            #[should_panic(expected = "unchecked_div_assign_integer requires an exact conversion")]
1507            fn f64_panics_on_non_exact_conversion() {
1508                let mut real = 1.0_f64;
1509                real.unchecked_div_assign_integer((1_i128 << 53) + 1);
1510            }
1511        }
1512
1513        mod mul_integer {
1514            use crate::kernels::RawRealTrait;
1515
1516            #[test]
1517            fn f64_returns_product_without_mutating_in_place() {
1518                let real = 3.5_f64;
1519                assert_eq!(real.unchecked_mul_integer(-4_i32), -14.0);
1520            }
1521        }
1522
1523        mod div_integer {
1524            use crate::kernels::RawRealTrait;
1525
1526            #[test]
1527            fn f64_returns_quotient_without_mutating_in_place() {
1528                let real = 14.0_f64;
1529                assert_eq!(real.unchecked_div_integer(-4_i32), -3.5);
1530            }
1531        }
1532    }
1533
1534    mod complex {
1535        use super::*;
1536        use crate::{
1537            ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
1538            ComplexScalarSetParts,
1539        };
1540        use num::{Complex, Zero};
1541
1542        #[test]
1543        fn real_part() {
1544            let c1 = Complex::new(1.23, 4.56);
1545            assert_eq!(c1.real_part(), 1.23);
1546
1547            let c2 = Complex::new(-7.89, 0.12);
1548            assert_eq!(c2.real_part(), -7.89);
1549
1550            let c3 = Complex::new(0.0, 10.0);
1551            assert_eq!(c3.real_part(), 0.0);
1552
1553            let c_nan_re = Complex::new(f64::NAN, 5.0);
1554            assert!(c_nan_re.real_part().is_nan());
1555
1556            let c_inf_re = Complex::new(f64::INFINITY, 5.0);
1557            assert!(c_inf_re.real_part().is_infinite());
1558            assert!(c_inf_re.real_part().is_sign_positive());
1559
1560            let c_neg_inf_re = Complex::new(f64::NEG_INFINITY, 5.0);
1561            assert!(c_neg_inf_re.real_part().is_infinite());
1562            assert!(c_neg_inf_re.real_part().is_sign_negative());
1563        }
1564
1565        #[test]
1566        fn imag_part() {
1567            let c1 = Complex::new(1.23, 4.56);
1568            assert_eq!(c1.imag_part(), 4.56);
1569
1570            let c2 = Complex::new(7.89, -0.12);
1571            assert_eq!(c2.imag_part(), -0.12);
1572
1573            let c3 = Complex::new(10.0, 0.0);
1574            assert_eq!(c3.imag_part(), 0.0);
1575
1576            let c_nan_im = Complex::new(5.0, f64::NAN);
1577            assert!(c_nan_im.imag_part().is_nan());
1578
1579            let c_inf_im = Complex::new(5.0, f64::INFINITY);
1580            assert!(c_inf_im.imag_part().is_infinite());
1581            assert!(c_inf_im.imag_part().is_sign_positive());
1582
1583            let c_neg_inf_im = Complex::new(5.0, f64::NEG_INFINITY);
1584            assert!(c_neg_inf_im.imag_part().is_infinite());
1585            assert!(c_neg_inf_im.imag_part().is_sign_negative());
1586        }
1587
1588        #[test]
1589        fn try_new_complex() {
1590            let r1 = 1.23;
1591            let i1 = 4.56;
1592            let c1 = Complex::<f64>::try_new_complex(r1, i1).unwrap();
1593            assert_eq!(c1.re, r1);
1594            assert_eq!(c1.im, i1);
1595            assert_eq!(c1.real_part(), r1);
1596            assert_eq!(c1.imag_part(), i1);
1597
1598            let r2 = -7.89;
1599            let i2 = -0.12;
1600            let c2 = Complex::<f64>::try_new_complex(r2, i2).unwrap();
1601            assert_eq!(c2.re, r2);
1602            assert_eq!(c2.im, i2);
1603            assert_eq!(c2.real_part(), r2);
1604            assert_eq!(c2.imag_part(), i2);
1605
1606            let r3 = 0.0;
1607            let i3 = 0.0;
1608            let c3 = Complex::<f64>::try_new_complex(r3, i3).unwrap();
1609            assert_eq!(c3.re, r3);
1610            assert_eq!(c3.im, i3);
1611            assert!(c3.is_zero()); // Assuming Zero trait is available and implemented
1612
1613            let c_nan_re = Complex::<f64>::try_new_complex(f64::NAN, 5.0).unwrap_err();
1614            assert!(matches!(
1615                c_nan_re,
1616                ErrorsValidationRawComplex::InvalidRealPart { .. }
1617            ));
1618
1619            let c_inf_im = Complex::<f64>::try_new_complex(10.0, f64::INFINITY).unwrap_err();
1620            assert!(matches!(
1621                c_inf_im,
1622                ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1623            ));
1624
1625            let c_nan_re_inf_im =
1626                Complex::<f64>::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
1627            assert!(matches!(
1628                c_nan_re_inf_im,
1629                ErrorsValidationRawComplex::InvalidBothParts { .. }
1630            ));
1631        }
1632
1633        #[test]
1634        fn try_new_pure_real() {
1635            let r1 = 1.23;
1636            let c1 = Complex::<f64>::try_new_pure_real(r1).unwrap();
1637            assert_eq!(c1.re, r1);
1638            assert_eq!(c1.im, 0.0);
1639
1640            let c_nan = Complex::<f64>::try_new_pure_real(f64::NAN).unwrap_err();
1641            assert_matches!(
1642                c_nan,
1643                ErrorsValidationRawComplex::InvalidRealPart {
1644                    source
1645                } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1646            );
1647        }
1648
1649        #[test]
1650        fn try_new_pure_imaginary() {
1651            let i1 = 1.23;
1652            let c1 = Complex::<f64>::try_new_pure_imaginary(i1).unwrap();
1653            assert_eq!(c1.re, 0.0);
1654            assert_eq!(c1.im, i1);
1655
1656            let c_nan = Complex::<f64>::try_new_pure_imaginary(f64::NAN).unwrap_err();
1657            assert_matches!(
1658                c_nan,
1659                ErrorsValidationRawComplex::InvalidImaginaryPart {
1660                    source
1661                } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1662            );
1663        }
1664
1665        #[test]
1666        fn add_to_real_part() {
1667            let mut c = Complex::new(1.0, 2.0);
1668            c.add_to_real_part(&3.0);
1669            assert_eq!(c.re, 4.0);
1670            assert_eq!(c.im, 2.0);
1671
1672            c.add_to_real_part(&-5.0);
1673            assert_eq!(c.re, -1.0);
1674            assert_eq!(c.im, 2.0);
1675        }
1676
1677        #[cfg(debug_assertions)]
1678        #[test]
1679        #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1680        fn add_to_real_part_nan() {
1681            let mut c = Complex::new(1.0, 2.0);
1682            c.add_to_real_part(&f64::NAN);
1683        }
1684
1685        #[test]
1686        fn add_to_imaginary_part() {
1687            let mut c = Complex::new(1.0, 2.0);
1688            c.add_to_imaginary_part(&3.0);
1689            assert_eq!(c.re, 1.0);
1690            assert_eq!(c.im, 5.0);
1691
1692            c.add_to_imaginary_part(&-4.0);
1693            assert_eq!(c.re, 1.0);
1694            assert_eq!(c.im, 1.0);
1695        }
1696
1697        #[cfg(debug_assertions)]
1698        #[test]
1699        #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1700        fn add_to_imaginary_part_nan() {
1701            let mut c = Complex::new(1.0, 2.0);
1702            c.add_to_imaginary_part(&f64::NAN);
1703        }
1704
1705        #[test]
1706        fn multiply_real_part() {
1707            let mut c = Complex::new(1.0, 2.0);
1708            c.multiply_real_part(&3.0);
1709            assert_eq!(c.re, 3.0);
1710            assert_eq!(c.im, 2.0);
1711
1712            c.multiply_real_part(&-2.0);
1713            assert_eq!(c.re, -6.0);
1714            assert_eq!(c.im, 2.0);
1715        }
1716
1717        #[cfg(debug_assertions)]
1718        #[test]
1719        #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1720        fn multiply_real_part_nan() {
1721            let mut c = Complex::new(1.0, 2.0);
1722            c.multiply_real_part(&f64::NAN);
1723        }
1724
1725        #[test]
1726        fn multiply_imaginary_part() {
1727            let mut c = Complex::new(1.0, 2.0);
1728            c.multiply_imaginary_part(&3.0);
1729            assert_eq!(c.re, 1.0);
1730            assert_eq!(c.im, 6.0);
1731
1732            c.multiply_imaginary_part(&-0.5);
1733            assert_eq!(c.re, 1.0);
1734            assert_eq!(c.im, -3.0);
1735        }
1736
1737        #[cfg(debug_assertions)]
1738        #[test]
1739        #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1740        fn multiply_imaginary_part_nan() {
1741            let mut c = Complex::new(1.0, 2.0);
1742            c.multiply_imaginary_part(&f64::NAN);
1743        }
1744
1745        #[test]
1746        fn set_real_part() {
1747            let mut c = Complex::new(1.0, 2.0);
1748            c.set_real_part(3.0);
1749            assert_eq!(c.re, 3.0);
1750            assert_eq!(c.im, 2.0);
1751
1752            c.set_real_part(-4.0);
1753            assert_eq!(c.re, -4.0);
1754            assert_eq!(c.im, 2.0);
1755        }
1756
1757        #[cfg(debug_assertions)]
1758        #[test]
1759        #[should_panic(expected = "The real part is not finite (i.e. is infinite or NaN).")]
1760        fn set_real_part_nan() {
1761            let mut c = Complex::new(1.0, 2.0);
1762            c.set_real_part(f64::NAN);
1763        }
1764
1765        #[test]
1766        fn set_imaginary_part() {
1767            let mut c = Complex::new(1.0, 2.0);
1768            c.set_imaginary_part(3.0);
1769            assert_eq!(c.re, 1.0);
1770            assert_eq!(c.im, 3.0);
1771
1772            c.set_imaginary_part(-4.0);
1773            assert_eq!(c.re, 1.0);
1774            assert_eq!(c.im, -4.0);
1775        }
1776
1777        #[cfg(debug_assertions)]
1778        #[test]
1779        #[should_panic(expected = "The imaginary part is not finite (i.e. is infinite or NaN).")]
1780        fn set_imaginary_part_nan() {
1781            let mut c = Complex::new(1.0, 2.0);
1782            c.set_imaginary_part(f64::NAN);
1783        }
1784
1785        #[test]
1786        #[allow(clippy::op_ref)]
1787        fn multiply_ref() {
1788            let c1 = Complex::new(1.0, 2.0);
1789            let c2 = Complex::new(3.0, 4.0);
1790            let result = c1 * &c2;
1791            assert_eq!(result, Complex::new(-5.0, 10.0)); // (1*3 - 2*4) + (1*4 + 2*3)i
1792        }
1793    }
1794}