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