ftl_numkernel/functions.rs
1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
4 errors::{ComplexValueErrors, ComplexValueValidator, RealValueErrors, RealValueValidator},
5 Native64, NumKernel, TryNew, Zero,
6};
7use num::Complex;
8use std::{backtrace::Backtrace, fmt};
9use thiserror::Error;
10
11#[cfg(feature = "rug")]
12use crate::{ComplexRug, RealRug, Rug};
13
14//------------------------------------------------------------------------------------------------
15/// Errors that can occur during the computation of the square root of a real number,
16/// before the computation of the square root.
17#[derive(Debug, Error)]
18pub enum SqrtRealInputErrors<T: NumKernel + 'static> {
19 /// The input value is negative.
20 ///
21 /// This error occurs when the input value for the square root computation is negative.
22 #[error("the input value ({value:?}) is negative!")]
23 NegativeValue {
24 /// The negative input value.
25 value: T::RawRealType,
26
27 /// The backtrace of the error.
28 backtrace: Backtrace,
29 },
30
31 /// The input value (i.e. the value before the computation of the square root) is invalid.
32 ///
33 /// This error occurs when the input value for the square root computation is invalid
34 /// (i.e. NaN, infinite or sub-normal).
35 #[error("the input value is invalid!")]
36 ValidationError {
37 #[from]
38 source: RealValueErrors<T::RawRealType>,
39 },
40}
41
42/// Errors that can occur during the computation of the square root of a complex number,
43/// before the computation of the square root.
44#[derive(Debug, Error)]
45pub enum SqrtComplexInputErrors<T: NumKernel + 'static> {
46 /// The input value (i.e. the value before the computation of the square root) is invalid.
47 ///
48 /// This error occurs when the input value for the square root computation is invalid
49 /// (i.e. the real or imaginary part of the complex number is NaN, infinite or sub-normal).
50 #[error("the input value is invalid!")]
51 ValidationError {
52 /// The source error that occurred during validation.
53 #[from]
54 source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
55 },
56}
57
58/// Errors that can occur during the computation of the square root of a real number.
59#[derive(Debug, Error)]
60pub enum SqrtRealErrors<T: NumKernel + 'static> {
61 /// The input value (i.e. the value before the computation of the square root) is invalid.
62 ///
63 /// This error occurs when the input value for the square root computation is invalid.
64 #[error("the input value is invalid!")]
65 Input {
66 /// The source error that occurred during validation.
67 #[from]
68 source: SqrtRealInputErrors<T>,
69 },
70
71 /// The output value (i.e. the value after the computation of the square root) is invalid.
72 ///
73 /// This error occurs when the output value of the square root computation is invalid.
74 #[error("the output value is invalid!")]
75 Output {
76 /// The source error that occurred during validation.
77 #[from]
78 source: RealValueErrors<T::RawRealType>,
79 },
80}
81
82/// Errors that can occur during the computation of the square root of a complex number.
83#[derive(Debug, Error)]
84pub enum SqrtComplexErrors<T: NumKernel + 'static> {
85 /// The input value (i.e. the value before the computation of the square root) is invalid.
86 ///
87 /// This error occurs when the input value for the square root computation is invalid.
88 #[error("the input value is invalid!")]
89 Input {
90 /// The source error that occurred during validation.
91 #[from]
92 source: SqrtComplexInputErrors<T>,
93 },
94
95 /// The output value (i.e. the value after the computation of the square root) is invalid.
96 ///
97 /// This error occurs when the output value of the square root computation is invalid.
98 #[error("the output value is invalid!")]
99 Output {
100 /// The source error that occurred during validation.
101 #[from]
102 source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
103 },
104}
105
106/// Validation of the input real value for the square root function.
107///
108/// The input value is valid if is *finite*, *positive* and *normal*;
109fn sqrt_real_validate_input<T: NumKernel>(
110 value: T::RawRealType,
111) -> Result<T::RawRealType, SqrtRealInputErrors<T>> {
112 let v = value.validate();
113 match v {
114 Ok(value) => {
115 if value < 0. {
116 Err(SqrtRealInputErrors::NegativeValue {
117 value,
118 backtrace: Backtrace::force_capture(),
119 })
120 } else {
121 Ok(value)
122 }
123 }
124 Err(e) => Err(SqrtRealInputErrors::ValidationError { source: e }),
125 }
126}
127
128/// Validation of the input complex value for the square root function.
129///
130/// The input value is valid if is *finite* and *normal*;
131fn sqrt_complex_validate_input<T: NumKernel>(
132 value: T::RawComplexType,
133) -> Result<T::RawComplexType, SqrtComplexInputErrors<T>> {
134 Ok(value.validate()?)
135}
136//--------------------------------------------------------------------------------------------
137
138//--------------------------------------------------------------------------------------------
139/// This trait provides the interface for the function used to compute the square root of a number.
140pub trait Sqrt: TryNew {
141 /// The error type that can be returned by the `try_sqrt` method.
142 type Error: fmt::Debug;
143
144 /// Computes the square root of `self`, checking the input and output values for validity.
145 ///
146 /// # Validity
147 ///
148 /// - For the square root of a real number:
149 /// - the input value is valid if is *finite*, *positive* and *normal*;
150 /// - the output value is valid if is *finite* and *normal*.
151 /// - For the square root of a complex number:
152 /// - The input and output values are valid if they are *finite* and *normal*.
153 ///
154 /// # Returns
155 ///
156 /// - `Ok(self)` if the square root computation is successful and the input and output values are valid.
157 /// - `Err(Self::Error)` if the input or output values are invalid.
158 fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error>;
159
160 /// Computes the square root of `self`, with no checks (in Release mode) on the validity of the input and output values.
161 ///
162 /// In Debug mode, this function internally calls the function [`Sqrt::try_sqrt()`] and a `panic!` is raised if the function returns an error.
163 ///
164 /// # Panics
165 ///
166 /// This function will panic in Debug mode if the input or output values are invalid.
167 fn sqrt(self) -> Self;
168}
169
170#[duplicate::duplicate_item(
171 T E input_validation trait_comment;
172 [f64] [SqrtRealErrors::<Native64>] [sqrt_real_validate_input] ["Implementation of the [`Sqrt`] trait for [`f64`]."];
173 [Complex::<f64>] [SqrtComplexErrors::<Native64>] [sqrt_complex_validate_input] ["Implementation of the [`Sqrt`] trait for [`Complex`]."];
174)]
175#[doc = trait_comment]
176impl Sqrt for T {
177 type Error = E;
178
179 #[inline(always)]
180 fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error> {
181 let value = input_validation(self)?;
182
183 match T::try_new(value.sqrt()) {
184 Ok(sqrt) => Ok(sqrt),
185 Err(e) => Err(E::Output { source: e }),
186 }
187 }
188
189 #[inline(always)]
190 fn sqrt(self) -> Self {
191 if cfg!(debug_assertions) {
192 self.try_sqrt().unwrap()
193 } else {
194 self.sqrt()
195 }
196 }
197}
198
199#[cfg(feature = "rug")]
200#[duplicate::duplicate_item(
201 T E input_validation trait_comment;
202 [RealRug::<PRECISION>] [SqrtRealErrors::<Rug<PRECISION>>] [sqrt_real_validate_input] ["Implementation of the [`Sqrt`] trait for [`RealRug`]."];
203 [ComplexRug::<PRECISION>] [SqrtComplexErrors::<Rug<PRECISION>>] [sqrt_complex_validate_input] ["Implementation of the [`Sqrt`] trait for [`ComplexRug`]."];
204)]
205#[doc = trait_comment]
206impl<const PRECISION: u32> Sqrt for T {
207 type Error = E;
208
209 #[inline(always)]
210 fn try_sqrt(self) -> Result<Self, <Self as Sqrt>::Error> {
211 let value = input_validation(self.0)?;
212
213 match T::try_new(value.sqrt()) {
214 Ok(sqrt) => Ok(sqrt),
215 Err(e) => Err(E::Output { source: e }),
216 }
217 }
218
219 #[inline(always)]
220 fn sqrt(self) -> Self {
221 if cfg!(debug_assertions) {
222 self.try_sqrt().unwrap()
223 } else {
224 Self(self.0.sqrt())
225 }
226 }
227}
228
229//------------------------------------------------------------------------------------------------
230
231//------------------------------------------------------------------------------------------------
232/// Errors that can occur during the computation of the reciprocal of a real number.
233#[derive(Debug, Error)]
234pub enum RecipRealInputErrors<T: NumKernel + 'static> {
235 /// The input value is zero.
236 ///
237 /// This error occurs when the input value for the reciprocal computation is zero.
238 #[error("division by zero!")]
239 DivisionByZero {
240 /// The backtrace of the error.
241 backtrace: Backtrace,
242 },
243
244 /// The input value is invalid.
245 ///
246 /// This error occurs when the input value for the reciprocal computation is invalid.
247 #[error("the input value is invalid!")]
248 ValidationError {
249 /// The source error that occurred during validation.
250 #[from]
251 source: RealValueErrors<T::RawRealType>,
252 },
253}
254
255/// Errors that can occur during the computation of the reciprocal of a complex number.
256#[derive(Debug, Error)]
257pub enum RecipComplexInputErrors<T: NumKernel + 'static> {
258 /// The input value is zero.
259 ///
260 /// This error occurs when the input value for the reciprocal computation is zero.
261 #[error("division by zero!")]
262 DivisionByZero {
263 /// The backtrace of the error.
264 backtrace: Backtrace,
265 },
266
267 /// The input value is invalid.
268 ///
269 /// This error occurs when the input value for the reciprocal computation is invalid.
270 #[error("the input value is invalid!")]
271 ValidationError {
272 /// The source error that occurred during validation.
273 #[from]
274 source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
275 },
276}
277
278/// Errors that can occur during the computation of the reciprocal of a real number.
279#[derive(Debug, Error)]
280pub enum RecipRealErrors<T: NumKernel + 'static> {
281 /// The input value is invalid.
282 ///
283 /// This error occurs when the input value for the reciprocal computation is invalid.
284 #[error("the input value is invalid!")]
285 Input {
286 /// The source error that occurred during validation.
287 #[from]
288 source: RecipRealInputErrors<T>,
289 },
290
291 /// The output value is invalid.
292 ///
293 /// This error occurs when the output value of the reciprocal computation is invalid.
294 #[error("the output value is invalid!")]
295 Output {
296 /// The source error that occurred during validation.
297 #[from]
298 source: RealValueErrors<T::RawRealType>,
299 },
300}
301
302/// Errors that can occur during the computation of the reciprocal of a complex number.
303#[derive(Debug, Error)]
304pub enum RecipComplexErrors<T: NumKernel + 'static> {
305 /// The input value is invalid.
306 ///
307 /// This error occurs when the input value for the reciprocal computation is invalid.
308 #[error("the input value is invalid!")]
309 Input {
310 /// The source error that occurred during validation.
311 #[from]
312 source: RecipComplexInputErrors<T>,
313 },
314
315 /// The output value is invalid.
316 ///
317 /// This error occurs when the output value of the reciprocal computation is invalid.
318 #[error("the output value is invalid!")]
319 Output {
320 /// The source error that occurred during validation.
321 #[from]
322 source: ComplexValueErrors<T::RawRealType, T::RawComplexType>,
323 },
324}
325
326/// A trait for computing the reciprocal of a number.
327pub trait Reciprocal: TryNew {
328 /// The error type that can be returned by the `try_recip` method.
329 type Error: fmt::Debug;
330
331 /// Computes the reciprocal of `self`, checking the input and output values for validity.
332 ///
333 /// # Validity
334 ///
335 /// - The input value is valid if it is *finite*, *non-zero*, and *normal*.
336 ///
337 /// # Returns
338 ///
339 /// - `Ok(self)` if the reciprocal computation is successful and the input and output values are valid.
340 /// - `Err(Self::Error)` if the input or output values are invalid.
341 fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error>;
342
343 /// Computes the reciprocal of `self`, with no checks (in Release mode) on the validity of the input and output values.
344 ///
345 /// In Debug mode, this function internally calls the function [`Reciprocal::try_reciprocal()`] and a `panic!` is raised if the function returns an error.
346 ///
347 /// # Panics
348 ///
349 /// This function will panic in Debug mode if the input or output values are invalid.
350 fn reciprocal(self) -> Self;
351}
352
353#[duplicate::duplicate_item(
354 T implementation E InputError trait_comment;
355 [f64] [recip()] [RecipRealErrors::<Native64>] [RecipRealInputErrors] ["Implementation of the [`Reciprocal`] trait for [`f64`]."];
356 [Complex::<f64>] [inv()] [RecipComplexErrors::<Native64>] [RecipComplexInputErrors] ["Implementation of the [`Reciprocal`] trait for [`Complex`]."];
357)]
358impl Reciprocal for T {
359 type Error = E;
360
361 #[inline(always)]
362 fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error> {
363 match self.validate() {
364 Ok(value) => {
365 if value.is_zero() {
366 Err(E::Input {
367 source: InputError::DivisionByZero {
368 backtrace: Backtrace::force_capture(),
369 },
370 })
371 } else {
372 // value is different from zero, so we can "safely" compute the reciprocal
373 match Self::try_new(value.implementation) {
374 Ok(recip) => Ok(recip),
375 Err(e) => Err(E::Output { source: e }),
376 }
377 }
378 }
379 Err(e) => Err(E::Input {
380 source: InputError::ValidationError { source: e },
381 }),
382 }
383 }
384
385 #[inline(always)]
386 fn reciprocal(self) -> Self {
387 if cfg!(debug_assertions) {
388 self.try_reciprocal().unwrap()
389 } else {
390 self.implementation
391 }
392 }
393}
394
395#[cfg(feature = "rug")]
396#[duplicate::duplicate_item(
397 T E InputError trait_comment;
398 [RealRug::<PRECISION>] [RecipRealErrors::<Rug<PRECISION>>] [RecipRealInputErrors] ["Implementation of the [`Reciprocal`] trait for [`f64`]."];
399 [ComplexRug::<PRECISION>] [RecipComplexErrors::<Rug<PRECISION>>] [RecipComplexInputErrors] ["Implementation of the [`Reciprocal`] trait for [`Complex`]."];
400)]
401impl<const PRECISION: u32> Reciprocal for T {
402 type Error = E;
403
404 #[inline(always)]
405 fn try_reciprocal(self) -> Result<Self, <Self as Reciprocal>::Error> {
406 match self.0.validate() {
407 Ok(value) => {
408 if value.is_zero() {
409 Err(E::Input {
410 source: InputError::DivisionByZero {
411 backtrace: Backtrace::force_capture(),
412 },
413 })
414 } else {
415 // value is different from zero, so we can "safely" compute the reciprocal
416 match Self::try_new(value.recip()) {
417 Ok(recip) => Ok(recip),
418 Err(e) => Err(E::Output { source: e }),
419 }
420 }
421 }
422 Err(e) => Err(E::Input {
423 source: InputError::ValidationError { source: e },
424 }),
425 }
426 }
427
428 #[inline(always)]
429 fn reciprocal(self) -> Self {
430 if cfg!(debug_assertions) {
431 self.try_reciprocal().unwrap()
432 } else {
433 Self(self.0.recip())
434 }
435 }
436}
437//--------------------------------------------------------------------------------------------
438
439//------------------------------------------------------------------------------------------------
440/// This trait provides the interface for the function used to compute the *absolute value* of a number.
441pub trait Abs {
442 /// The return type of the *absolute value* function. It is always a real number (also when the input is a complex number).
443 type Output;
444
445 /// Returns the *absolute value* of `self`. The return type is always a real number (also when `self` is a complex number)
446 fn abs(self) -> Self::Output;
447}
448
449#[duplicate::duplicate_item(
450 T implementation trait_comment;
451 [f64] [self.abs()] ["Implementation of the [`Abs`] trait for `f64`."];
452 [Complex<f64>] [self.norm()] ["Implementation of the [`Abs`] trait for `Complex<f64>`."];
453)]
454#[doc = trait_comment]
455impl Abs for T {
456 /// The return type of the *absolute value* function.
457 type Output = f64;
458
459 /// Returns the *absolute value* of `self`.
460 #[inline(always)]
461 fn abs(self) -> Self::Output {
462 implementation
463 }
464}
465
466#[cfg(feature = "rug")]
467#[duplicate::duplicate_item(
468 T implementation trait_comment;
469 [RealRug<PRECISION>] [RealRug(self.0.abs())] ["Implementation of the [`Abs`] trait for [`RealRug`]."];
470 [ComplexRug<PRECISION>] [RealRug(self.0.abs().real().clone())] ["Implementation of the [`Abs`] trait for [`ComplexRug`]."];
471)]
472#[doc = trait_comment]
473impl<const PRECISION: u32> Abs for T {
474 /// The return type of the *absolute value* function.
475 type Output = RealRug<PRECISION>;
476
477 /// Returns the *absolute value* of `self`.
478 #[inline(always)]
479 fn abs(self) -> Self::Output {
480 implementation
481 }
482}
483//------------------------------------------------------------------------------------------------