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(crate) mod complex;
74mod exponential;
75mod hyperbolic;
76mod logarithm;
77mod max_min;
78mod neg_assign;
79pub(crate) mod pow;
80mod real;
81mod reciprocal;
82pub(crate) mod sqrt;
83mod trigonometric;
84
85pub use abs::{Abs, AbsComplexErrors, AbsInputErrors, AbsRealErrors};
86pub use complex::{
87 Arg, ArgErrors, ArgInputErrors, ComplexScalarConstructors, ComplexScalarGetParts,
88 ComplexScalarMutateParts, ComplexScalarSetParts, Conjugate,
89};
90pub use exponential::{Exp, ExpErrors, ExpInputErrors};
91pub use hyperbolic::{
92 ACosH, ACosHErrors, ACosHInputErrors, ASinH, ASinHErrors, ASinHInputErrors, ATanH, ATanHErrors,
93 ATanHInputErrors, CosH, CosHErrors, CosHInputErrors, HyperbolicFunctions, SinH, SinHErrors,
94 SinHInputErrors, TanH, TanHComplexErrors, TanHComplexInputErrors, TanHRealErrors,
95 TanHRealInputErrors,
96};
97pub use logarithm::{
98 Ln, Log2, Log10, LogarithmComplexErrors, LogarithmComplexInputErrors, LogarithmFunctions,
99 LogarithmRealErrors, LogarithmRealInputErrors,
100};
101pub use max_min::{Max, Min};
102pub use neg_assign::NegAssign;
103pub use pow::{
104 Pow, PowComplexBaseRealExponentErrors, PowComplexBaseRealExponentInputErrors, PowIntExponent,
105 PowIntExponentErrors, PowIntExponentInputErrors, PowRealBaseRealExponentErrors,
106 PowRealBaseRealExponentInputErrors,
107};
108pub use real::{Clamp, Classify, ExpM1, Hypot, Ln1p, TotalCmp};
109pub use reciprocal::{Reciprocal, ReciprocalErrors, ReciprocalInputErrors};
110pub use sqrt::{
111 Sqrt, SqrtComplexErrors, SqrtComplexInputErrors, SqrtRealErrors, SqrtRealInputErrors,
112};
113pub use trigonometric::{
114 ACos, ACosComplexErrors, ACosComplexInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
115 ASinComplexErrors, ASinComplexInputErrors, ASinRealErrors, ASinRealInputErrors, ATan, ATan2,
116 ATan2Errors, ATan2InputErrors, ATanComplexErrors, ATanComplexInputErrors, ATanRealErrors,
117 ATanRealInputErrors, Cos, CosErrors, CosInputErrors, Sin, SinErrors, SinInputErrors, Tan,
118 TanComplexErrors, TanComplexInputErrors, TanRealErrors, TanRealInputErrors,
119 TrigonometricFunctions,
120};
121
122//-------------------------------------------------------------
123/// A convenience trait alias that aggregates the standard arithmetic operations.
124///
125/// This trait alias bundles the common arithmetic operator traits from `std::ops`
126/// (e.g., [`Add`], [`Sub`], [`Mul`], [`Div`], and their `*Assign` variants)
127/// into a single super-trait. It is used as a bound on [`FpScalar`](crate::FpScalar) to ensure
128/// all scalar types support basic arithmetic.
129///
130/// This trait alias does **not** require `Copy`. Instead, it explicitly requires that
131/// arithmetic operations are implemented for both owned values (`Self`) and
132/// references (`&Self`). This provides flexibility for both move and copy semantics,
133/// allowing implementors to avoid unnecessary clones in performance-sensitive code.
134pub trait Arithmetic = Sized
135 + Add<Output = Self>
136 + for<'a> Add<&'a Self, Output = Self>
137 + AddAssign
138 + for<'a> AddAssign<&'a Self>
139 + Sub<Output = Self>
140 + for<'a> Sub<&'a Self, Output = Self>
141 + SubAssign
142 + for<'a> SubAssign<&'a Self>
143 + Mul<Output = Self>
144 + for<'a> Mul<&'a Self, Output = Self>
145 + MulAssign
146 + for<'a> MulAssign<&'a Self>
147 + Div<Output = Self>
148 + for<'a> Div<&'a Self, Output = Self>
149 + DivAssign
150 + for<'a> DivAssign<&'a Self>
151 + Neg<Output = Self>
152 + NegAssign
153 + LowerExp;
154//------------------------------------------------------------------------------------------------------------
155
156/// A generic error type for fallible numerical function computations.
157///
158/// This enum is used as a standard wrapper for function-specific errors,
159/// distinguishing between failures that occur during input validation and those
160/// that occur during output validation (or due to the computation itself resulting
161/// in an invalid value according to the defined policy).
162///
163/// # Type Parameters
164///
165/// - `InputError`: The type of the error that occurs if input validation fails.
166/// This is typically a function-specific enum detailing various input-related
167/// problems (e.g., [`ExpInputErrors`],, [`LogarithmRealInputErrors`], etc.).
168/// - `OutputError`: The type of the error that occurs if output validation fails.
169/// This is usually an error type related to the properties of the scalar value itself,
170/// often from the [`core::errors`](crate::core::errors) module (e.g.,
171/// [`ErrorsValidationRawReal`](crate::core::errors::ErrorsValidationRawReal) or
172/// [`ErrorsValidationRawComplex`](crate::core::errors::ErrorsValidationRawComplex)), indicating
173/// that the computed result is not valid (e.g., NaN, Infinity).
174#[derive(Debug, Error)]
175pub enum FunctionErrors<InputError: std::error::Error, OutputError: std::error::Error> {
176 /// Error due to invalid input values.
177 ///
178 /// This variant is returned when initial validation of the function's arguments
179 /// fails according to the defined validation policy (e.g.,
180 /// [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy)) or due to
181 /// domain-specific constraints (e.g., negative input to a real logarithm).
182 #[error("the input value is not valid accordingly to the used validation policy!")]
183 Input {
184 /// The source error that occurred during input validation.
185 /// This provides specific details about why the input was considered invalid.
186 #[from] // Allows easy conversion from InputError to FunctionErrors::Input
187 source: InputError,
188 },
189
190 /// Error due to the computed output failing validation.
191 ///
192 /// This variant is returned if the result of the computation, even from
193 /// valid inputs, fails validation according to the defined policy. This
194 /// typically means the result was non-finite (NaN or Infinity) or otherwise
195 /// did not meet the criteria for a valid output.
196 #[error("the output value is not valid accordingly to the used validation policy!")]
197 Output {
198 /// The source error that occurred during output validation.
199 /// This provides specific details about why the computed output was
200 /// considered invalid.
201 #[source] // Indicates that `source` is the underlying cause of this error
202 #[backtrace] // Captures a backtrace when this error variant is created
203 source: OutputError,
204 },
205}
206
207//------------------------------------------------------------------------------------------------
208/// Trait for fused multiply-add operations.
209///
210/// This trait provides methods for computing `(self * b) + c` efficiently.
211///
212/// ## Why a custom `MulAddRef` trait?
213///
214/// This trait is distinct from [`num_traits::MulAdd`] primarily in its method signatures,
215/// which take `b` and `c` by reference (`&Self`). This is a deliberate design choice to:
216/// 1. **Maintain API Consistency:** Aligns with the other operator traits in this library that
217/// support by-reference operations.
218/// 2. **Reduce Cloning:** Allows implementors to avoid cloning values in performance-sensitive
219/// contexts, which is especially important for non-`Copy` types like [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
220///
221/// Implementors should aim to use hardware FMA (Fused Multiply-Add) instructions
222/// where available and appropriate for the underlying scalar type to improve
223/// performance and accuracy.
224pub trait MulAddRef {
225 /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
226 ///
227 /// `a.mul_add_ref(b, c)` produces a result like `a * &b + &c`.
228 fn mul_add_ref(self, b: &Self, c: &Self) -> Self;
229}
230//------------------------------------------------------------------------------------------------
231
232/// Provides methods for rounding floating-point numbers.
233pub trait Rounding {
234 /// Returns the smallest integer greater than or equal to `self`.
235 fn kernel_ceil(self) -> Self;
236
237 /// Returns the largest integer smaller than or equal to `self`.
238 fn kernel_floor(self) -> Self;
239
240 /// Returns the fractional part of `self`.
241 fn kernel_fract(self) -> Self;
242
243 /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
244 fn kernel_round(self) -> Self;
245
246 /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
247 ///
248 /// This function always returns the precise result.
249 ///
250 /// # Examples
251 /// ```
252 /// use num_valid::functions::Rounding;
253 ///
254 /// let f = 3.3_f64;
255 /// let g = -3.3_f64;
256 /// let h = 3.5_f64;
257 /// let i = 4.5_f64;
258 ///
259 /// assert_eq!(f.kernel_round_ties_even(), 3.0);
260 /// assert_eq!(g.kernel_round_ties_even(), -3.0);
261 /// assert_eq!(h.kernel_round_ties_even(), 4.0);
262 /// assert_eq!(i.kernel_round_ties_even(), 4.0);
263 /// ```
264 fn kernel_round_ties_even(self) -> Self;
265
266 /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
267 ///
268 /// # Examples
269 /// ```
270 /// use num_valid::{RealScalar, functions::Rounding};
271 ///
272 /// let f = 3.7_f64;
273 /// let g = 3.0_f64;
274 /// let h = -3.7_f64;
275 ///
276 /// assert_eq!(f.kernel_trunc(), 3.0);
277 /// assert_eq!(g.kernel_trunc(), 3.0);
278 /// assert_eq!(h.kernel_trunc(), -3.0);
279 /// ```
280 fn kernel_trunc(self) -> Self;
281}
282
283/// Provides methods for sign manipulation and checking.
284pub trait Sign {
285 /// Returns a number with the magnitude of `self` and the sign of `sign`.
286 fn kernel_copysign(self, sign: &Self) -> Self;
287
288 /// Computes the signum.
289 ///
290 /// The returned value is:
291 /// - `1.0` if the value is positive, +0.0 or +∞
292 /// - `−1.0` if the value is negative, −0.0 or −∞
293 /// - `NaN` if the value is NaN
294 fn kernel_signum(self) -> Self;
295
296 /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
297 fn kernel_is_sign_negative(&self) -> bool;
298
299 /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
300 fn kernel_is_sign_positive(&self) -> bool;
301}