Skip to main content

num_valid/
functions.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Scalar Numerical Functions Module
4//!
5//! This module provides a collection of traits and error types for common mathematical
6//! functions operating on scalar numerical values. These functions are designed to be
7//! generic over different floating-point and complex number types, including support
8//! for arbitrary-precision numbers via the [`rug`](https://crates.io/crates/rug) library (when the "rug" feature is enabled).
9//!
10//! ## Core Concepts
11//!
12//! - **Function Traits**: Each mathematical operation (e.g., [`Exp`], [`Ln`], [`Sin`], [`Pow`], etc.)
13//!   is defined by a trait. These traits typically offer two methods:
14//!     - `try_xxx()`: A fallible method that performs comprehensive validation of inputs
15//!       and outputs, returning a [`Result`].
16//!     - `xxx()`: An infallible method that aims for performance, especially in release
17//!       builds. In debug builds, it usually calls `try_xxx().unwrap()`.
18//!
19//! - **Error Handling**: Errors are structured using the [`FunctionErrors`] enum, which
20//!   distinguishes between input validation failures and output validation failures.
21//!   Each function trait usually has an associated error type (e.g., [`ExpErrors`], [`LogarithmRealErrors`], etc.)
22//!   that is a type alias for [`FunctionErrors`] specialized with function-specific
23//!   input error enums (e.g., [`ExpInputErrors`], [`LogarithmRealInputErrors`], etc.).
24//!
25//! - **Validation**: Input and output values are typically validated using policies defined
26//!   in the [`core::policies`](crate::core::policies) module (as implementation of the
27//!   [`ValidationPolicy`](try_create::ValidationPolicy) trait from the [`try_create`](https://crates.io/crates/try_create) crate),
28//!   with [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy) being commonly used to ensure
29//!   values are not NaN, Infinity, or subnormal.
30//!
31//! ## Provided Functions
32//!
33//! The module re-exports traits and error types for various categories of functions:
34//!
35//! - **Basic Operations**:
36//!   - [`Abs`]: Absolute value.
37//!   - [`NegAssign`]: In-place negation.
38//!   - [`Reciprocal`]: Reciprocal (`1/x`).
39//!   - [`Pow`]: Power function (`base^exponent`).
40//!   - [`Sqrt`]: Square root.
41//! - **Exponential and Logarithmic**:
42//!   - [`Exp`]: Exponential function (`e^x`).
43//!   - [`Ln`]: Natural logarithm.
44//!   - [`Log2`]: Base-2 logarithm.
45//!   - [`Log10`]: Base-10 logarithm.
46//! - **Trigonometric**:
47//!   - [`Sin`], [`Cos`], [`Tan`]: Basic trigonometric functions.
48//!   - [`ASin`], [`ACos`], [`ATan`]: Inverse trigonometric functions.
49//!   - [`ATan2`]: Four-quadrant inverse tangent.
50//! - **Hyperbolic**:
51//!   - [`SinH`], [`CosH`], [`TanH`]: Hyperbolic functions.
52//!   - [`ASinH`], [`ACosH`], [`ATanH`]: Inverse hyperbolic functions.
53//! - **Complex Number Operations**:
54//!   - [`Arg`]: Argument (phase) of a complex number.
55//!   - [`Conjugate`]: Complex conjugate.
56//! - **Comparison**:
57//!   - [`Max`], [`Min`]: Maximum and minimum of two numbers.
58//! - **Real Number Specific**:
59//!   - [`Rounding`]: Ceiling, floor, rounding operations.
60//!   - [`Sign`]: Sign manipulation and checking.
61//!   - [`Clamp`], [`Classify`], [`ExpM1`], [`Hypot`], [`Ln1p`], [`TotalCmp`]: Specialized real number operations.
62//!
63//! Each function is organized into its own submodule (e.g., `abs`, `exp`) and its
64//! public interface is re-exported here.
65
66use std::{
67    fmt::LowerExp,
68    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
69};
70use thiserror::Error;
71
72mod abs;
73pub use abs::{Abs, AbsComplexErrors, AbsInputErrors, AbsRealErrors};
74
75pub(crate) mod complex;
76pub use complex::{
77    Arg, ArgErrors, ArgInputErrors, ComplexScalarConstructors, ComplexScalarGetParts,
78    ComplexScalarMutateParts, ComplexScalarSetParts, Conjugate,
79};
80
81mod exponential;
82pub use exponential::{Exp, ExpErrors, ExpInputErrors};
83
84mod hyperbolic;
85pub use hyperbolic::{
86    ACosH, ACosHErrors, ACosHInputErrors, ASinH, ASinHErrors, ASinHInputErrors, ATanH, ATanHErrors,
87    ATanHInputErrors, CosH, CosHErrors, CosHInputErrors, HyperbolicFunctions, SinH, SinHErrors,
88    SinHInputErrors, TanH, TanHComplexErrors, TanHComplexInputErrors, TanHRealErrors,
89    TanHRealInputErrors,
90};
91
92mod logarithm;
93pub use logarithm::{
94    Ln, Log2, Log10, LogarithmComplexErrors, LogarithmComplexInputErrors, LogarithmFunctions,
95    LogarithmRealErrors, LogarithmRealInputErrors,
96};
97
98mod max_min;
99pub use max_min::{Max, Min};
100
101mod neg_assign;
102pub use neg_assign::NegAssign;
103
104pub(crate) mod pow;
105pub use pow::{
106    Pow, PowComplexBaseRealExponentErrors, PowComplexBaseRealExponentInputErrors, PowIntExponent,
107    PowIntExponentErrors, PowIntExponentInputErrors, PowRealBaseRealExponentErrors,
108    PowRealBaseRealExponentInputErrors,
109};
110
111mod real;
112pub use real::{Clamp, Classify, ExpM1, Hypot, Ln1p, TotalCmp};
113
114mod reciprocal;
115pub use reciprocal::{Reciprocal, ReciprocalErrors, ReciprocalInputErrors};
116
117pub(crate) mod sqrt;
118pub use sqrt::{
119    Sqrt, SqrtComplexErrors, SqrtComplexInputErrors, SqrtRealErrors, SqrtRealInputErrors,
120};
121
122mod trigonometric;
123pub use trigonometric::{
124    ACos, ACosComplexErrors, ACosComplexInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
125    ASinComplexErrors, ASinComplexInputErrors, ASinRealErrors, ASinRealInputErrors, ATan, ATan2,
126    ATan2Errors, ATan2InputErrors, ATanComplexErrors, ATanComplexInputErrors, ATanRealErrors,
127    ATanRealInputErrors, Cos, CosErrors, CosInputErrors, Sin, SinErrors, SinInputErrors, Tan,
128    TanComplexErrors, TanComplexInputErrors, TanRealErrors, TanRealInputErrors,
129    TrigonometricFunctions,
130};
131
132//-------------------------------------------------------------
133/// A convenience trait alias that aggregates the standard arithmetic operations.
134///
135/// This trait alias bundles the common arithmetic operator traits from `std::ops`
136/// (e.g., [`Add`], [`Sub`], [`Mul`], [`Div`], and their `*Assign` variants)
137/// into a single super-trait. It is used as a bound on [`FpScalar`](crate::FpScalar) to ensure
138/// all scalar types support basic arithmetic.
139///
140/// This trait alias does **not** require `Copy`. Instead, it explicitly requires that
141/// arithmetic operations are implemented for both owned values (`Self`) and
142/// references (`&Self`). This provides flexibility for both move and copy semantics,
143/// allowing implementors to avoid unnecessary clones in performance-sensitive code.
144pub trait Arithmetic = Sized
145    + Add<Output = Self>
146    + for<'a> Add<&'a Self, Output = Self>
147    + AddAssign
148    + for<'a> AddAssign<&'a Self>
149    + Sub<Output = Self>
150    + for<'a> Sub<&'a Self, Output = Self>
151    + SubAssign
152    + for<'a> SubAssign<&'a Self>
153    + Mul<Output = Self>
154    + for<'a> Mul<&'a Self, Output = Self>
155    + MulAssign
156    + for<'a> MulAssign<&'a Self>
157    + Div<Output = Self>
158    + for<'a> Div<&'a Self, Output = Self>
159    + DivAssign
160    + for<'a> DivAssign<&'a Self>
161    + Neg<Output = Self>
162    + NegAssign
163    + LowerExp;
164//------------------------------------------------------------------------------------------------------------
165
166/// A generic error type for fallible numerical function computations.
167///
168/// This enum is used as a standard wrapper for function-specific errors,
169/// distinguishing between failures that occur during input validation and those
170/// that occur during output validation (or due to the computation itself resulting
171/// in an invalid value according to the defined policy).
172///
173/// # Type Parameters
174///
175/// - `InputError`: The type of the error that occurs if input validation fails.
176///   This is typically a function-specific enum detailing various input-related
177///   problems (e.g., [`ExpInputErrors`],, [`LogarithmRealInputErrors`], etc.).
178/// - `OutputError`: The type of the error that occurs if output validation fails.
179///   This is usually an error type related to the properties of the scalar value itself,
180///   often from the [`core::errors`](crate::core::errors) module (e.g.,
181///   [`ErrorsValidationRawReal`](crate::core::errors::ErrorsValidationRawReal) or
182///   [`ErrorsValidationRawComplex`](crate::core::errors::ErrorsValidationRawComplex)), indicating
183///   that the computed result is not valid (e.g., NaN, Infinity).
184#[derive(Debug, Error)]
185pub enum FunctionErrors<InputError: std::error::Error, OutputError: std::error::Error> {
186    /// Error due to invalid input values.
187    ///
188    /// This variant is returned when initial validation of the function's arguments
189    /// fails according to the defined validation policy (e.g.,
190    /// [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy)) or due to
191    /// domain-specific constraints (e.g., negative input to a real logarithm).
192    #[error("the input value is not valid accordingly to the used validation policy!")]
193    Input {
194        /// The source error that occurred during input validation.
195        /// This provides specific details about why the input was considered invalid.
196        #[from] // Allows easy conversion from InputError to FunctionErrors::Input
197        source: InputError,
198    },
199
200    /// Error due to the computed output failing validation.
201    ///
202    /// This variant is returned if the result of the computation, even from
203    /// valid inputs, fails validation according to the defined policy. This
204    /// typically means the result was non-finite (NaN or Infinity) or otherwise
205    /// did not meet the criteria for a valid output.
206    #[error("the output value is not valid accordingly to the used validation policy!")]
207    Output {
208        /// The source error that occurred during output validation.
209        /// This provides specific details about why the computed output was
210        /// considered invalid.
211        #[source] // Indicates that `source` is the underlying cause of this error
212        #[backtrace] // Captures a backtrace when this error variant is created
213        source: OutputError,
214    },
215}
216
217//------------------------------------------------------------------------------------------------
218/// Trait for fused multiply-add operations.
219///
220/// This trait provides methods for computing `(self * b) + c` efficiently.
221///
222/// ## Why a custom `MulAddRef` trait?
223///
224/// This trait is distinct from [`num_traits::MulAdd`] primarily in its method signatures,
225/// which take `b` and `c` by reference (`&Self`). This is a deliberate design choice to:
226/// 1.  **Maintain API Consistency:** Aligns with the other operator traits in this library that
227///     support by-reference operations.
228/// 2.  **Reduce Cloning:** Allows implementors to avoid cloning values in performance-sensitive
229///     contexts, which is especially important for non-`Copy` types like [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
230///
231/// Implementors should aim to use hardware FMA (Fused Multiply-Add) instructions
232/// where available and appropriate for the underlying scalar type to improve
233/// performance and accuracy.
234pub trait MulAddRef {
235    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
236    ///
237    /// `a.mul_add_ref(b, c)` produces a result like `a * &b + &c`.
238    fn mul_add_ref(self, b: &Self, c: &Self) -> Self;
239}
240//------------------------------------------------------------------------------------------------
241
242/// Provides methods for rounding floating-point numbers.
243pub trait Rounding {
244    /// Returns the smallest integer greater than or equal to `self`.
245    fn kernel_ceil(self) -> Self;
246
247    /// Returns the largest integer smaller than or equal to `self`.
248    fn kernel_floor(self) -> Self;
249
250    /// Returns the fractional part of `self`.
251    fn kernel_fract(self) -> Self;
252
253    /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
254    fn kernel_round(self) -> Self;
255
256    /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
257    ///
258    /// This function always returns the precise result.
259    ///
260    /// # Examples
261    /// ```
262    /// use num_valid::functions::Rounding;
263    ///
264    /// let f = 3.3_f64;
265    /// let g = -3.3_f64;
266    /// let h = 3.5_f64;
267    /// let i = 4.5_f64;
268    ///
269    /// assert_eq!(f.kernel_round_ties_even(), 3.0);
270    /// assert_eq!(g.kernel_round_ties_even(), -3.0);
271    /// assert_eq!(h.kernel_round_ties_even(), 4.0);
272    /// assert_eq!(i.kernel_round_ties_even(), 4.0);
273    /// ```
274    fn kernel_round_ties_even(self) -> Self;
275
276    /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
277    ///    
278    /// # Examples
279    /// ```
280    /// use num_valid::{RealScalar, functions::Rounding};
281    ///
282    /// let f = 3.7_f64;
283    /// let g = 3.0_f64;
284    /// let h = -3.7_f64;
285    ///
286    /// assert_eq!(f.kernel_trunc(), 3.0);
287    /// assert_eq!(g.kernel_trunc(), 3.0);
288    /// assert_eq!(h.kernel_trunc(), -3.0);
289    /// ```
290    fn kernel_trunc(self) -> Self;
291}
292
293/// Provides methods for sign manipulation and checking.
294pub trait Sign {
295    /// Returns a number with the magnitude of `self` and the sign of `sign`.
296    fn kernel_copysign(self, sign: &Self) -> Self;
297
298    /// Computes the signum.
299    ///
300    /// The returned value is:
301    /// - `1.0` if the value is positive, +0.0 or +∞
302    /// - `−1.0` if the value is negative, −0.0 or −∞
303    /// - `NaN` if the value is NaN
304    fn kernel_signum(self) -> Self;
305
306    /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
307    fn kernel_is_sign_negative(&self) -> bool;
308
309    /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
310    fn kernel_is_sign_positive(&self) -> bool;
311}