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 [`validation`](crate::validation) 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::validation::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 that aggregates the standard arithmetic operations.
124///
125/// This trait 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 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:
135 Sized
136 + Add<Self, Output = Self>
137 + for<'a> Add<&'a Self, Output = Self>
138 + AddAssign
139 + for<'a> AddAssign<&'a Self>
140 + Sub<Output = Self>
141 + for<'a> Sub<&'a Self, Output = Self>
142 + SubAssign
143 + for<'a> SubAssign<&'a Self>
144 + Mul<Output = Self>
145 + for<'a> Mul<&'a Self, Output = Self>
146 + MulAssign
147 + for<'a> MulAssign<&'a Self>
148 + Div<Output = Self>
149 + for<'a> Div<&'a Self, Output = Self>
150 + DivAssign
151 + for<'a> DivAssign<&'a Self>
152 + Neg<Output = Self>
153 + NegAssign
154 + LowerExp
155{
156}
157//------------------------------------------------------------------------------------------------------------
158
159/// A generic error type for fallible numerical function computations.
160///
161/// This enum is used as a standard wrapper for function-specific errors,
162/// distinguishing between failures that occur during input validation and those
163/// that occur during output validation (or due to the computation itself resulting
164/// in an invalid value according to the defined policy).
165///
166/// # Type Parameters
167///
168/// - `InputError`: The type of the error that occurs if input validation fails.
169/// This is typically a function-specific enum detailing various input-related
170/// problems (e.g., [`ExpInputErrors`],, [`LogarithmRealInputErrors`], etc.).
171/// - `OutputError`: The type of the error that occurs if output validation fails.
172/// This is usually an error type related to the properties of the scalar value itself,
173/// often from the [`validation`](crate::validation) module (e.g.,
174/// [`ErrorsValidationRawReal`](crate::validation::ErrorsValidationRawReal) or
175/// [`ErrorsValidationRawComplex`](crate::validation::ErrorsValidationRawComplex)), indicating
176/// that the computed result is not valid (e.g., NaN, Infinity).
177#[derive(Debug, Error)]
178pub enum FunctionErrors<InputError: std::error::Error, OutputError: std::error::Error> {
179 /// Error due to invalid input values.
180 ///
181 /// This variant is returned when initial validation of the function's arguments
182 /// fails according to the defined validation policy (e.g.,
183 /// [`StrictFinitePolicy`](crate::validation::StrictFinitePolicy)) or due to
184 /// domain-specific constraints (e.g., negative input to a real logarithm).
185 #[error("the input value is not valid accordingly to the used validation policy!")]
186 Input {
187 /// The source error that occurred during input validation.
188 /// This provides specific details about why the input was considered invalid.
189 #[from] // Allows easy conversion from InputError to FunctionErrors::Input
190 source: InputError,
191 },
192
193 /// Error due to the computed output failing validation.
194 ///
195 /// This variant is returned if the result of the computation, even from
196 /// valid inputs, fails validation according to the defined policy. This
197 /// typically means the result was non-finite (NaN or Infinity) or otherwise
198 /// did not meet the criteria for a valid output.
199 #[error("the output value is not valid accordingly to the used validation policy!")]
200 Output {
201 /// The source error that occurred during output validation.
202 /// This provides specific details about why the computed output was
203 /// considered invalid.
204 #[source] // Indicates that `source` is the underlying cause of this error
205 #[backtrace] // Captures a backtrace when this error variant is created
206 source: OutputError,
207 },
208}
209
210//------------------------------------------------------------------------------------------------
211/// Trait for fused multiply-add operations.
212///
213/// This trait provides methods for computing `(self * b) + c` efficiently.
214///
215/// ## Why a custom `MulAddRef` trait?
216///
217/// This trait is distinct from [`num_traits::MulAdd`] primarily in its method signatures,
218/// which take `b` and `c` by reference (`&Self`). This is a deliberate design choice to:
219/// 1. **Maintain API Consistency:** Aligns with the other operator traits in this library that
220/// support by-reference operations.
221/// 2. **Reduce Cloning:** Allows implementors to avoid cloning values in performance-sensitive
222/// contexts, which is especially important for non-`Copy` types like [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
223///
224/// Implementors should aim to use hardware FMA (Fused Multiply-Add) instructions
225/// where available and appropriate for the underlying scalar type to improve
226/// performance and accuracy.
227pub trait MulAddRef {
228 /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
229 ///
230 /// `a.mul_add_ref(b, c)` produces a result like `a * &b + &c`.
231 fn mul_add_ref(self, b: &Self, c: &Self) -> Self;
232}
233//------------------------------------------------------------------------------------------------
234
235/// Provides methods for rounding floating-point numbers.
236pub trait Rounding {
237 /// Returns the smallest integer greater than or equal to `self`.
238 fn kernel_ceil(self) -> Self;
239
240 /// Returns the largest integer smaller than or equal to `self`.
241 fn kernel_floor(self) -> Self;
242
243 /// Returns the fractional part of `self`.
244 fn kernel_fract(self) -> Self;
245
246 /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
247 fn kernel_round(self) -> Self;
248
249 /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
250 ///
251 /// This function always returns the precise result.
252 ///
253 /// # Examples
254 /// ```
255 /// use num_valid::functions::Rounding;
256 ///
257 /// let f = 3.3_f64;
258 /// let g = -3.3_f64;
259 /// let h = 3.5_f64;
260 /// let i = 4.5_f64;
261 ///
262 /// assert_eq!(f.kernel_round_ties_even(), 3.0);
263 /// assert_eq!(g.kernel_round_ties_even(), -3.0);
264 /// assert_eq!(h.kernel_round_ties_even(), 4.0);
265 /// assert_eq!(i.kernel_round_ties_even(), 4.0);
266 /// ```
267 fn kernel_round_ties_even(self) -> Self;
268
269 /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
270 ///
271 /// # Examples
272 /// ```
273 /// use num_valid::{RealScalar, functions::Rounding};
274 ///
275 /// let f = 3.7_f64;
276 /// let g = 3.0_f64;
277 /// let h = -3.7_f64;
278 ///
279 /// assert_eq!(f.kernel_trunc(), 3.0);
280 /// assert_eq!(g.kernel_trunc(), 3.0);
281 /// assert_eq!(h.kernel_trunc(), -3.0);
282 /// ```
283 fn kernel_trunc(self) -> Self;
284}
285
286/// Provides methods for sign manipulation and checking.
287pub trait Sign {
288 /// Returns a number with the magnitude of `self` and the sign of `sign`.
289 fn kernel_copysign(self, sign: &Self) -> Self;
290
291 /// Computes the signum.
292 ///
293 /// The returned value is:
294 /// - `1.0` if the value is positive, +0.0 or +∞
295 /// - `−1.0` if the value is negative, −0.0 or −∞
296 /// - `NaN` if the value is NaN
297 fn kernel_signum(self) -> Self;
298
299 /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
300 fn kernel_is_sign_negative(&self) -> bool;
301
302 /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
303 fn kernel_is_sign_positive(&self) -> bool;
304}