Skip to main content

num_valid/functions/
logarithm.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! This module provides functionality for computing logarithms of real and complex numbers.
4//!
5//! The module includes traits and implementations for computing various types of logarithms,
6//! including the natural logarithm (base `e`), base-10 logarithm, and base-2 logarithm. It also
7//! defines error types that can occur during the computation of logarithms.
8//!
9//! # Traits
10//!
11//! - [`Ln`]: Trait for computing the natural logarithm (base `e`) of a number.
12//! - [`Log10`]: Trait for computing the base-10 logarithm of a number.
13//! - [`Log2`]: Trait for computing the base-2 logarithm of a number.
14//!
15//! # Error Types
16//!
17//! - [`LogarithmRealInputErrors`]: Errors that can occur when computing the logarithm of a real number.
18//! - [`LogarithmComplexInputErrors`]: Errors that can occur when computing the logarithm of a complex number.
19//! - [`LogarithmRealErrors`]: Errors that can occur when computing the logarithm of a real number, including both input and output errors.
20//! - [`LogarithmComplexErrors`]: Errors that can occur when computing the logarithm of a complex number, including both input and output errors.
21//!
22//! # Implementations
23//!
24//! The traits are implemented for various numeric types, including:
25//!
26//! - [`f64`]: Provides logarithm functions for 64-bit floating-point numbers.
27//! - [`Complex<f64>`]: Provides logarithm functions for complex numbers with 64-bit floating-point components.
28//! - [`RealValidated`](crate::RealValidated): Provides logarithm functions for validated real numbers.
29//! - [`ComplexValidated`](crate::ComplexValidated): Provides logarithm functions for validated complex numbers.
30//!
31//! # Example
32//!
33//! ```rust
34//! use num_valid::{functions::Ln, backends::native::raw::Native64};
35//!
36//!
37//! let value = 2.718281828459045;
38//! match value.try_ln() {
39//!     Ok(result) => println!("Natural Logarithm: {}", result),
40//!     Err(e) => println!("Error: {:?}", e),
41//! }
42//!
43//! // Using the panicking method (simpler, panics on invalid input)
44//! let result = Ln::ln(value);
45//! println!("Natural Logarithm: {}", result);
46//! ```
47
48use crate::{
49    core::{errors::ErrorsValidationRawReal, traits::raw::RawScalarValidate},
50    functions::FunctionErrors,
51    kernels::{RawComplexTrait, RawRealTrait},
52};
53use duplicate::duplicate_item;
54use num::Complex;
55use num_traits::Float;
56use std::backtrace::Backtrace;
57use thiserror::Error;
58
59#[cfg(debug_assertions)]
60use crate::core::{errors::capture_backtrace, traits::validation::sealed::NativeReal};
61
62#[cfg(not(debug_assertions))]
63use crate::core::traits::validation::sealed::NativeReal;
64
65#[cfg(debug_assertions)]
66use num::Zero;
67
68//------------------------------------------------------------------
69/// Errors that can occur when computing the logarithm of a real number.
70///
71/// This enum represents the possible errors that can occur when computing the logarithm of a real number.
72/// It includes errors for invalid arguments and other validation errors.
73///
74/// # Type Parameters
75///
76/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify
77///   the numeric type for the computation and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError`.
78///
79/// # Variants
80///
81/// - `NegativeArgument`: Indicates that the argument of the function is negative, which is not allowed
82///   for real logarithms. This variant includes the value that is out of the domain and a backtrace.
83/// - `ZeroArgument`: Indicates that the argument of the function is zero, which is not allowed for real logarithms.
84///   This variant includes a backtrace.
85/// - `InvalidArgument`: Indicates that the argument of the function is invalid. This variant includes
86///   the source error that occurred during validation.
87#[derive(Debug, Error)]
88pub enum LogarithmRealInputErrors<RawReal: RawRealTrait> {
89    /// The argument of the function is negative.
90    ///
91    /// This variant indicates that the argument of the function is negative, which is not allowed
92    /// for real logarithms. It includes the value that is out of the domain and a backtrace.
93    #[error("negative argument ({value})!")]
94    NegativeArgument {
95        /// The value that is out of the domain.
96        value: RawReal,
97
98        /// A captured backtrace for debugging purposes.
99        backtrace: Backtrace,
100    },
101
102    /// The argument of the function is zero.
103    ///
104    /// This variant indicates that the argument of the function is zero, which is not allowed
105    /// for real logarithms. It includes a backtrace.
106    #[error("zero argument!")]
107    ZeroArgument {
108        /// A captured backtrace for debugging purposes.
109        backtrace: Backtrace,
110    },
111
112    /// The argument of the function is invalid.
113    ///
114    /// This variant indicates that the argument of the function is invalid. It includes the source
115    /// error that occurred during validation.
116    #[error("the argument is invalid!")]
117    InvalidArgument {
118        /// The source error that occurred during validation.
119        #[source]
120        #[backtrace]
121        source: <RawReal as RawScalarValidate>::ValidationError,
122    },
123}
124
125/// Errors that can occur when computing the logarithm of a complex number.
126///
127/// This enum represents the possible errors that can occur when computing the logarithm of a complex number.
128/// It includes errors for invalid arguments and other validation errors.
129///
130/// # Type Parameters
131///
132/// - `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify
133///   the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.
134///
135/// # Variants
136///
137/// - `ZeroArgument`: Indicates that the argument of the function is zero, which is not allowed for complex logarithms.
138///   This variant includes a backtrace.
139/// - `InvalidArgument`: Indicates that the argument of the function is invalid. This variant includes
140///   the source error that occurred during validation.
141#[derive(Debug, Error)]
142pub enum LogarithmComplexInputErrors<RawComplex: RawComplexTrait> {
143    /// The argument of the function is zero.
144    ///
145    /// This variant indicates that the argument of the function is zero, which is not allowed
146    /// for complex logarithms. It includes a backtrace.
147    #[error("the argument is zero!")]
148    ZeroArgument {
149        /// A captured backtrace for debugging purposes.
150        backtrace: Backtrace,
151    },
152
153    /// The argument of the function is invalid.
154    ///
155    /// This variant indicates that the argument of the function is invalid. It includes the source
156    /// error that occurred during validation.
157    #[error("the argument is invalid!")]
158    InvalidArgument {
159        /// The source error that occurred during validation.
160        #[source]
161        #[backtrace]
162        source: <RawComplex as RawScalarValidate>::ValidationError,
163    },
164}
165
166/// Errors that can occur when computing the logarithm of a real number.
167///
168/// This enum represents the possible errors that can occur when computing the logarithm of a real number.
169/// It includes errors for invalid input values and other validation errors.
170///
171/// # Type Parameters
172///
173/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify
174///   the numeric type for the computation and its associated raw error type `<RawReal as RawScalarValidate>::ValidationError`.
175///
176/// # Variants
177///
178/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that
179///   occurred during validation.
180/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that
181///   occurred during validation.
182pub type LogarithmRealErrors<RawReal> = FunctionErrors<
183    LogarithmRealInputErrors<RawReal>,
184    <RawReal as RawScalarValidate>::ValidationError,
185>;
186
187/// Errors that can occur when computing the logarithm of a complex number.
188///
189/// This enum represents the possible errors that can occur when computing the logarithm of a complex number.
190/// It includes errors for invalid input values and other validation errors.
191///
192/// # Type Parameters
193///
194/// - `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify
195///   the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarValidate>::ValidationError`.
196///
197/// # Variants
198///
199/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that
200///   occurred during validation.
201/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that
202///   occurred during validation.
203pub type LogarithmComplexErrors<RawComplex> = FunctionErrors<
204    LogarithmComplexInputErrors<RawComplex>,
205    <RawComplex as RawScalarValidate>::ValidationError,
206>;
207
208#[duplicate_item(
209    trait_name try_func    func    trait_doc try_func_doc func_doc err_doc;
210    [Ln]       [try_ln]    [ln]    ["Trait for computing the [*natural logarithm*](https://en.wikipedia.org/wiki/Natural_logarithm) (base `e`) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_ln` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_ln`: Computes the *natural logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `ln`: Computes the *natural logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."] ["Computes the *natural logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Ln::Error`] type."]    ["Computes the *natural logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_ln` method for safe computations."]    ["The error type that is returned by the `try_ln` method."];
211    [Log10]    [try_log10] [log10] ["Trait for computing the [*base-10 logarithm*](https://en.wikipedia.org/wiki/Common_logarithm) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_log10` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_log10`: Computes the *base-10 logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `log10`: Computes the *base-10 logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."]    ["Computes the *base-10 logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Log10::Error`] type."] ["Computes the *base-10 logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_log10` method for safe computations."] ["The error type that is returned by the `try_log10` method."];
212    [Log2]     [try_log2]  [log2]  ["Trait for computing the [*base-2 logarithm*](https://en.wikipedia.org/wiki/Binary_logarithm) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_log2` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_log2`: Computes the *base-2 logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `log2`: Computes the *base-2 logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."]          ["Computes the *base-2 logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Log2::Error`] type."]   ["Computes the *base-2 logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_log2` method for safe computations."]   ["The error type that is returned by the `try_log2` method."];
213)]
214#[doc = trait_doc]
215pub trait trait_name: Sized {
216    #[doc = err_doc]
217    type Error: std::error::Error;
218
219    #[doc = try_func_doc]
220    #[must_use = "this `Result` may contain an error that should be handled"]
221    fn try_func(self) -> Result<Self, Self::Error>;
222
223    #[doc = func_doc]
224    fn func(self) -> Self;
225}
226
227#[duplicate_item(
228    trait_name try_func func;
229    [Ln]       [try_ln]    [ln];
230    [Log10]    [try_log10] [log10];
231    [Log2]     [try_log2]  [log2];
232)]
233impl<T> trait_name for T
234where
235    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
236{
237    type Error = LogarithmRealErrors<Self>;
238
239    #[inline(always)]
240    fn try_func(self) -> Result<Self, Self::Error> {
241        #[cfg(debug_assertions)]
242        {
243            self.validate_raw_scalar()
244                .map_err(|e| LogarithmRealInputErrors::InvalidArgument { source: e }.into())
245                .and_then(|v| {
246                    let zero = T::zero();
247                    if v < zero {
248                        Err(LogarithmRealInputErrors::NegativeArgument {
249                            value: v,
250                            backtrace: capture_backtrace(),
251                        }
252                        .into())
253                    } else if v == zero {
254                        Err(LogarithmRealInputErrors::ZeroArgument {
255                            backtrace: capture_backtrace(),
256                        }
257                        .into())
258                    } else {
259                        <T as Float>::func(v)
260                            .validate_raw_scalar()
261                            .map_err(|e| LogarithmRealErrors::Output { source: e })
262                    }
263                })
264        }
265        #[cfg(not(debug_assertions))]
266        {
267            Ok(<T as Float>::func(self))
268        }
269    }
270
271    #[inline(always)]
272    fn func(self) -> Self {
273        #[cfg(debug_assertions)]
274        {
275            self.try_func().unwrap()
276        }
277        #[cfg(not(debug_assertions))]
278        {
279            <T as Float>::func(self)
280        }
281    }
282}
283
284#[duplicate_item(
285    trait_name try_func func;
286    [Ln]       [try_ln]    [ln];
287    [Log10]    [try_log10] [log10];
288    [Log2]     [try_log2]  [log2];
289)]
290impl<T> trait_name for Complex<T>
291where
292    Self: RawComplexTrait<RawReal = T>,
293    T: NativeReal<ValidationError = ErrorsValidationRawReal<T>>,
294{
295    type Error = LogarithmComplexErrors<Self>;
296
297    #[inline(always)]
298    fn try_func(self) -> Result<Self, Self::Error> {
299        #[cfg(debug_assertions)]
300        {
301            self.validate_raw_scalar()
302                .map_err(|e| LogarithmComplexInputErrors::InvalidArgument { source: e }.into())
303                .and_then(|v| {
304                    if Zero::is_zero(&v) {
305                        Err(LogarithmComplexInputErrors::ZeroArgument {
306                            backtrace: capture_backtrace(),
307                        }
308                        .into())
309                    } else {
310                        Complex::func(v)
311                            .validate_raw_scalar()
312                            .map_err(|e| LogarithmComplexErrors::Output { source: e })
313                    }
314                })
315        }
316        #[cfg(not(debug_assertions))]
317        {
318            Ok(Complex::func(self))
319        }
320    }
321
322    #[inline(always)]
323    fn func(self) -> Self {
324        #[cfg(debug_assertions)]
325        {
326            self.try_func().unwrap()
327        }
328        #[cfg(not(debug_assertions))]
329        {
330            Complex::func(self)
331        }
332    }
333}
334//------------------------------------------------------------------
335
336//------------------------------------------------------------------
337/// A convenience trait that aggregates the standard logarithm functions.
338///
339/// This trait serves as a shorthand for requiring a type to implement all the fundamental
340/// logarithm operations:
341/// - [`Ln`] (natural logarithm)
342/// - [`Log10`] (base-10 logarithm)
343/// - [`Log2`] (base-2 logarithm)
344///
345/// It is primarily used as a super-trait for [`FpScalar`](crate::FpScalar) to simplify trait bounds
346/// and ensure that any scalar type in the library provides a comprehensive set of logarithmic
347/// capabilities. By using `LogarithmFunctions` as a bound, you can write generic functions that
348/// utilize any of its constituent trait methods.
349///
350/// # Examples
351///
352/// ```
353/// use num_valid::functions::{LogarithmFunctions, Ln, Log10, Log2};
354/// use std::fmt::Debug;
355///
356/// // A generic function that calculates various logarithms of a number.
357/// // We bound T by FpScalar, which implies LogarithmFunctions.
358/// fn calculate_logs<T>(x: T)
359/// where
360///     T: LogarithmFunctions + Clone + Debug,
361/// {
362///     let ln_x = x.clone().ln();
363///     let log10_x = x.clone().log10();
364///     let log2_x = x.log2();
365///
366///     println!("ln(x) = {:?}", ln_x);
367///     println!("log10(x) = {:?}", log10_x);
368///     println!("log2(x) = {:?}", log2_x);
369/// }
370///
371/// let value = 100.0f64;
372/// calculate_logs(value);
373///
374/// // Verify the results
375/// assert_eq!(value.ln(), 4.605170185988092);
376/// assert_eq!(value.log10(), 2.0);
377/// assert_eq!(value.log2(), 6.643856189774724);
378/// ```
379pub trait LogarithmFunctions: Ln + Log2 + Log10 {}
380
381impl<T> LogarithmFunctions for T where T: Ln + Log2 + Log10 {}
382//------------------------------------------------------------------
383
384//------------------------------------------------------------------
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    #[cfg(feature = "rug")]
390    use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
391
392    #[cfg(feature = "rug")]
393    use try_create::TryNew;
394
395    mod ln {
396        use super::*;
397
398        mod native {
399            use super::*;
400
401            mod real {
402                use super::*;
403
404                #[test]
405                fn test_f64_ln_valid() {
406                    let value = 10.0;
407                    let expected_result = std::f64::consts::LN_10;
408                    assert_eq!(Float::ln(value), expected_result);
409                    assert_eq!(Ln::ln(value), expected_result);
410                    assert_eq!(value.try_ln().unwrap(), expected_result);
411                }
412
413                #[test]
414                #[cfg(debug_assertions)]
415                fn test_f64_ln_zero() {
416                    let value = 0.0;
417                    let result = value.try_ln();
418                    assert!(matches!(
419                        result,
420                        Err(LogarithmRealErrors::Input(
421                            LogarithmRealInputErrors::ZeroArgument { .. }
422                        ))
423                    ));
424                }
425
426                #[test]
427                #[cfg(debug_assertions)]
428                fn test_f64_ln_negative() {
429                    let value = -10.0;
430                    let result = value.try_ln();
431                    assert!(matches!(
432                        result,
433                        Err(LogarithmRealErrors::Input(
434                            LogarithmRealInputErrors::NegativeArgument { .. }
435                        ))
436                    ));
437                }
438
439                #[test]
440                fn test_f64_ln_one() {
441                    let value = 1.0;
442                    let expected_result = 0.0;
443                    assert_eq!(Float::ln(value), expected_result);
444                    assert_eq!(Ln::ln(value), expected_result);
445                    assert_eq!(value.try_ln().unwrap(), expected_result);
446                }
447
448                #[test]
449                #[cfg(debug_assertions)]
450                fn test_f64_ln_infinity() {
451                    let value = f64::INFINITY;
452                    let result = value.try_ln();
453                    assert!(matches!(
454                        result,
455                        Err(LogarithmRealErrors::Input(
456                            LogarithmRealInputErrors::InvalidArgument { .. }
457                        ))
458                    ));
459                }
460
461                #[test]
462                #[cfg(debug_assertions)]
463                fn test_f64_ln_nan() {
464                    let value = f64::NAN;
465                    let result = value.try_ln();
466                    assert!(matches!(
467                        result,
468                        Err(LogarithmRealErrors::Input(
469                            LogarithmRealInputErrors::InvalidArgument { .. }
470                        ))
471                    ));
472                }
473            }
474
475            mod complex {
476                use super::*;
477
478                #[test]
479                fn test_complex_f64_ln_valid() {
480                    let value = Complex::new(10.0, 0.0);
481                    let expected_result = Complex::new(std::f64::consts::LN_10, 0.0);
482                    assert_eq!(value.ln(), expected_result);
483                    assert_eq!(value.try_ln().unwrap(), expected_result);
484                }
485
486                #[test]
487                #[cfg(debug_assertions)]
488                fn test_complex_f64_ln_zero() {
489                    let value = Complex::new(0.0, 0.0);
490                    let result = value.try_ln();
491                    assert!(matches!(
492                        result,
493                        Err(LogarithmComplexErrors::Input(
494                            LogarithmComplexInputErrors::ZeroArgument { .. }
495                        ))
496                    ));
497                }
498
499                #[test]
500                fn test_complex_f64_ln_negative() {
501                    let value = Complex::new(-10.0, 0.0);
502                    let expected_result =
503                        Complex::new(std::f64::consts::LN_10, std::f64::consts::PI);
504                    assert_eq!(value.ln(), expected_result);
505                    assert_eq!(value.try_ln().unwrap(), expected_result);
506                }
507
508                #[test]
509                fn test_complex_f64_ln_one() {
510                    let value = Complex::new(1.0, 0.0);
511                    let expected_result = Complex::new(0.0, 0.0);
512                    assert_eq!(value.ln(), expected_result);
513                    assert_eq!(value.try_ln().unwrap(), expected_result);
514                }
515
516                #[test]
517                #[cfg(debug_assertions)]
518                fn test_complex_f64_ln_infinity() {
519                    let value = Complex::new(f64::INFINITY, 0.0);
520                    let result = value.try_ln();
521                    assert!(matches!(
522                        result,
523                        Err(LogarithmComplexErrors::Input(
524                            LogarithmComplexInputErrors::InvalidArgument { .. }
525                        ))
526                    ));
527
528                    let value = Complex::new(0.0, f64::INFINITY);
529                    let result = value.try_ln();
530                    assert!(matches!(
531                        result,
532                        Err(LogarithmComplexErrors::Input(
533                            LogarithmComplexInputErrors::InvalidArgument { .. }
534                        ))
535                    ));
536                }
537
538                #[test]
539                #[cfg(debug_assertions)]
540                fn test_complex_f64_ln_nan() {
541                    let value = Complex::new(f64::NAN, 0.0);
542                    let result = value.try_ln();
543                    assert!(matches!(
544                        result,
545                        Err(LogarithmComplexErrors::Input(
546                            LogarithmComplexInputErrors::InvalidArgument { .. }
547                        ))
548                    ));
549
550                    let value = Complex::new(0.0, f64::NAN);
551                    let result = value.try_ln();
552                    assert!(matches!(
553                        result,
554                        Err(LogarithmComplexErrors::Input(
555                            LogarithmComplexInputErrors::InvalidArgument { .. }
556                        ))
557                    ));
558                }
559            }
560        }
561
562        #[cfg(feature = "rug")]
563        mod rug53 {
564            use super::*;
565            use rug::{Complex, Float};
566
567            mod real {
568                use super::*;
569
570                #[test]
571                fn test_real_ln_valid() {
572                    let value =
573                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
574                    let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
575                        53,
576                        std::f64::consts::LN_10,
577                    ))
578                    .unwrap();
579                    assert_eq!(value.clone().ln(), expected_result);
580                    assert_eq!(value.try_ln().unwrap(), expected_result);
581                }
582
583                #[test]
584                fn test_real_ln_zero() {
585                    let value =
586                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
587                    let result = value.try_ln();
588                    assert!(matches!(
589                        result,
590                        Err(LogarithmRealErrors::Input(
591                            LogarithmRealInputErrors::ZeroArgument { .. }
592                        ))
593                    ));
594                }
595
596                #[test]
597                fn test_real_ln_negative() {
598                    let value =
599                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
600                    let result = value.try_ln();
601                    assert!(matches!(
602                        result,
603                        Err(LogarithmRealErrors::Input(
604                            LogarithmRealInputErrors::NegativeArgument { .. }
605                        ))
606                    ));
607                }
608
609                #[test]
610                fn test_real_ln_one() {
611                    let value =
612                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
613                    let expected_result =
614                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
615                    assert_eq!(value.clone().ln(), expected_result);
616                    assert_eq!(value.try_ln().unwrap(), expected_result);
617                }
618            }
619
620            mod complex {
621                use super::*;
622
623                #[test]
624                fn test_complex_ln_valid() {
625                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
626                        53,
627                        (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
628                    ))
629                    .unwrap();
630                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
631                        53,
632                        (
633                            Float::with_val(53, std::f64::consts::LN_10),
634                            Float::with_val(53, 0.0),
635                        ),
636                    ))
637                    .unwrap();
638                    assert_eq!(value.clone().ln(), expected_result);
639                    assert_eq!(value.try_ln().unwrap(), expected_result);
640                }
641
642                #[test]
643                fn test_complex_ln_zero() {
644                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
645                        53,
646                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
647                    ))
648                    .unwrap();
649                    let result = value.try_ln();
650                    assert!(matches!(
651                        result,
652                        Err(LogarithmComplexErrors::Input(
653                            LogarithmComplexInputErrors::ZeroArgument { .. }
654                        ))
655                    ));
656                }
657
658                #[test]
659                fn test_complex_ln_negative() {
660                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
661                        53,
662                        (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
663                    ))
664                    .unwrap();
665                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
666                        53,
667                        (
668                            Float::with_val(53, std::f64::consts::LN_10),
669                            Float::with_val(53, std::f64::consts::PI),
670                        ),
671                    ))
672                    .unwrap();
673                    assert_eq!(value.clone().ln(), expected_result);
674                    assert_eq!(value.try_ln().unwrap(), expected_result);
675                }
676
677                #[test]
678                fn test_complex_ln_one() {
679                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
680                        53,
681                        (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
682                    ))
683                    .unwrap();
684                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
685                        53,
686                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
687                    ))
688                    .unwrap();
689                    assert_eq!(value.clone().ln(), expected_result);
690                    assert_eq!(value.try_ln().unwrap(), expected_result);
691                }
692            }
693        }
694    }
695
696    mod log10 {
697        use super::*;
698
699        mod native {
700            use super::*;
701
702            mod real {
703                use super::*;
704
705                #[test]
706                fn test_f64_log10_valid() {
707                    let value = 10.0;
708                    let expected_result = 1.0;
709                    assert_eq!(Float::log10(value), expected_result);
710                    assert_eq!(Log10::log10(value), expected_result);
711                    assert_eq!(value.try_log10().unwrap(), expected_result);
712                }
713
714                #[test]
715                #[cfg(debug_assertions)]
716                fn test_f64_log10_zero() {
717                    let value = 0.0;
718                    let result = value.try_log10();
719                    assert!(matches!(
720                        result,
721                        Err(LogarithmRealErrors::Input(
722                            LogarithmRealInputErrors::ZeroArgument { .. }
723                        ))
724                    ));
725                }
726
727                #[test]
728                #[cfg(debug_assertions)]
729                fn test_f64_log10_negative() {
730                    let value = -10.0;
731                    let result = value.try_log10();
732                    assert!(matches!(
733                        result,
734                        Err(LogarithmRealErrors::Input(
735                            LogarithmRealInputErrors::NegativeArgument { .. }
736                        ))
737                    ));
738                }
739
740                #[test]
741                fn test_f64_log10_one() {
742                    let value = 1.0;
743                    let expected_result = 0.0;
744                    assert_eq!(Float::log10(value), expected_result);
745                    assert_eq!(Log10::log10(value), expected_result);
746                    assert_eq!(value.try_log10().unwrap(), expected_result);
747                }
748
749                #[test]
750                #[cfg(debug_assertions)]
751                fn test_f64_log10_infinity() {
752                    let value = f64::INFINITY;
753                    let result = value.try_log10();
754                    assert!(matches!(
755                        result,
756                        Err(LogarithmRealErrors::Input(
757                            LogarithmRealInputErrors::InvalidArgument { .. }
758                        ))
759                    ));
760                }
761
762                #[test]
763                #[cfg(debug_assertions)]
764                fn test_f64_log10_nan() {
765                    let value = f64::NAN;
766                    let result = value.try_log10();
767                    assert!(matches!(
768                        result,
769                        Err(LogarithmRealErrors::Input(
770                            LogarithmRealInputErrors::InvalidArgument { .. }
771                        ))
772                    ));
773                }
774            }
775
776            mod complex {
777                use super::*;
778
779                #[test]
780                fn test_complex_f64_log10_valid() {
781                    let value = Complex::new(10.0, 0.0);
782                    let expected_result = Complex::new(1.0, 0.0);
783                    assert_eq!(value.log10(), expected_result);
784                    assert_eq!(value.try_log10().unwrap(), expected_result);
785                }
786
787                #[test]
788                #[cfg(debug_assertions)]
789                fn test_complex_f64_log10_zero() {
790                    let value = Complex::new(0.0, 0.0);
791                    let result = value.try_log10();
792                    assert!(matches!(
793                        result,
794                        Err(LogarithmComplexErrors::Input(
795                            LogarithmComplexInputErrors::ZeroArgument { .. }
796                        ))
797                    ));
798                }
799
800                #[test]
801                #[cfg(debug_assertions)]
802                fn test_complex_f64_log10_negative() {
803                    let value = Complex::new(-10.0, 0.0);
804                    let expected_result = Complex::new(1.0, 1.3643763538418412);
805                    assert_eq!(value.log10(), expected_result);
806                    assert_eq!(value.try_log10().unwrap(), expected_result);
807                }
808
809                #[test]
810                fn test_complex_f64_log10_one() {
811                    let value = Complex::new(1.0, 0.0);
812                    let expected_result = Complex::new(0.0, 0.0);
813                    assert_eq!(value.log10(), expected_result);
814                    assert_eq!(value.try_log10().unwrap(), expected_result);
815                }
816
817                #[test]
818                #[cfg(debug_assertions)]
819                fn test_complex_f64_log10_infinity() {
820                    let value = Complex::new(f64::INFINITY, 0.0);
821                    let result = value.try_log10();
822                    assert!(matches!(
823                        result,
824                        Err(LogarithmComplexErrors::Input(
825                            LogarithmComplexInputErrors::InvalidArgument { .. }
826                        ))
827                    ));
828
829                    let value = Complex::new(0.0, f64::INFINITY);
830                    let result = value.try_log10();
831                    assert!(matches!(
832                        result,
833                        Err(LogarithmComplexErrors::Input(
834                            LogarithmComplexInputErrors::InvalidArgument { .. }
835                        ))
836                    ));
837                }
838
839                #[test]
840                #[cfg(debug_assertions)]
841                fn test_complex_f64_log10_nan() {
842                    let value = Complex::new(f64::NAN, 0.0);
843                    let result = value.try_log10();
844                    assert!(matches!(
845                        result,
846                        Err(LogarithmComplexErrors::Input(
847                            LogarithmComplexInputErrors::InvalidArgument { .. }
848                        ))
849                    ));
850
851                    let value = Complex::new(0.0, f64::NAN);
852                    let result = value.try_log10();
853                    assert!(matches!(
854                        result,
855                        Err(LogarithmComplexErrors::Input(
856                            LogarithmComplexInputErrors::InvalidArgument { .. }
857                        ))
858                    ));
859                }
860            }
861        }
862
863        #[cfg(feature = "rug")]
864        mod rug53 {
865            use super::*;
866            use rug::{Complex, Float};
867
868            mod real {
869                use super::*;
870
871                #[test]
872                fn test_real_log10_valid() {
873                    let value =
874                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
875                    let expected_result =
876                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
877                    assert_eq!(value.clone().log10(), expected_result);
878                    assert_eq!(value.try_log10().unwrap(), expected_result);
879                }
880
881                #[test]
882                fn test_real_log10_zero() {
883                    let value =
884                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
885                    let result = value.try_log10();
886                    assert!(matches!(
887                        result,
888                        Err(LogarithmRealErrors::Input(
889                            LogarithmRealInputErrors::ZeroArgument { .. }
890                        ))
891                    ));
892                }
893
894                #[test]
895                fn test_real_log10_negative() {
896                    let value =
897                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
898                    let result = value.try_log10();
899                    assert!(matches!(
900                        result,
901                        Err(LogarithmRealErrors::Input(
902                            LogarithmRealInputErrors::NegativeArgument { .. }
903                        ))
904                    ));
905                }
906
907                #[test]
908                fn test_real_log10_one() {
909                    let value =
910                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
911                    let expected_result =
912                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
913                    assert_eq!(value.clone().log10(), expected_result);
914                    assert_eq!(value.try_log10().unwrap(), expected_result);
915                }
916            }
917
918            mod complex {
919                use super::*;
920
921                #[test]
922                fn test_complex_log10_valid() {
923                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
924                        53,
925                        (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
926                    ))
927                    .unwrap();
928                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
929                        53,
930                        (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
931                    ))
932                    .unwrap();
933                    assert_eq!(value.clone().log10(), expected_result);
934                    assert_eq!(value.try_log10().unwrap(), expected_result);
935                }
936
937                #[test]
938                fn test_complex_log10_zero() {
939                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
940                        53,
941                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
942                    ))
943                    .unwrap();
944                    let result = value.try_log10();
945                    assert!(matches!(
946                        result,
947                        Err(LogarithmComplexErrors::Input(
948                            LogarithmComplexInputErrors::ZeroArgument { .. }
949                        ))
950                    ));
951                }
952
953                #[test]
954                fn test_complex_log10_negative() {
955                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
956                        53,
957                        (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
958                    ))
959                    .unwrap();
960                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
961                        53,
962                        (
963                            Float::with_val(53, 1.0),
964                            Float::with_val(53, 1.3643763538418414),
965                        ),
966                    ))
967                    .unwrap();
968                    assert_eq!(value.clone().log10(), expected_result);
969                    assert_eq!(value.try_log10().unwrap(), expected_result);
970                }
971
972                #[test]
973                fn test_complex_log10_one() {
974                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
975                        53,
976                        (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
977                    ))
978                    .unwrap();
979                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
980                        53,
981                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
982                    ))
983                    .unwrap();
984                    assert_eq!(value.clone().log10(), expected_result);
985                    assert_eq!(value.try_log10().unwrap(), expected_result);
986                }
987            }
988        }
989    }
990
991    mod log2 {
992        use super::*;
993
994        mod native {
995            use super::*;
996
997            mod real {
998                use super::*;
999
1000                #[test]
1001                fn test_f64_log2_valid() {
1002                    let value = 10.0;
1003                    let expected_result = std::f64::consts::LOG2_10;
1004                    assert_eq!(Float::log2(value), expected_result);
1005                    assert_eq!(Log2::log2(value), expected_result);
1006                    assert_eq!(value.try_log2().unwrap(), expected_result);
1007                }
1008
1009                #[test]
1010                #[cfg(debug_assertions)]
1011                fn test_f64_log2_zero() {
1012                    let value = 0.0;
1013                    let result = value.try_log2();
1014                    assert!(matches!(
1015                        result,
1016                        Err(LogarithmRealErrors::Input(
1017                            LogarithmRealInputErrors::ZeroArgument { .. }
1018                        ))
1019                    ));
1020                }
1021
1022                #[test]
1023                #[cfg(debug_assertions)]
1024                fn test_f64_log2_negative() {
1025                    let value = -10.0;
1026                    let result = value.try_log2();
1027                    assert!(matches!(
1028                        result,
1029                        Err(LogarithmRealErrors::Input(
1030                            LogarithmRealInputErrors::NegativeArgument { .. }
1031                        ))
1032                    ));
1033                }
1034
1035                #[test]
1036                fn test_f64_log2_one() {
1037                    let value = 1.0;
1038                    let expected_result = 0.0;
1039                    assert_eq!(Float::log2(value), expected_result);
1040                    assert_eq!(Log2::log2(value), expected_result);
1041                    assert_eq!(value.try_log2().unwrap(), expected_result);
1042                }
1043
1044                #[test]
1045                #[cfg(debug_assertions)]
1046                fn test_f64_log2_infinity() {
1047                    let value = f64::INFINITY;
1048                    let result = value.try_log2();
1049                    assert!(matches!(
1050                        result,
1051                        Err(LogarithmRealErrors::Input(
1052                            LogarithmRealInputErrors::InvalidArgument { .. }
1053                        ))
1054                    ));
1055                }
1056
1057                #[test]
1058                #[cfg(debug_assertions)]
1059                fn test_f64_log2_nan() {
1060                    let value = f64::NAN;
1061                    let result = value.try_log2();
1062                    assert!(matches!(
1063                        result,
1064                        Err(LogarithmRealErrors::Input(
1065                            LogarithmRealInputErrors::InvalidArgument { .. }
1066                        ))
1067                    ));
1068                }
1069            }
1070
1071            mod complex {
1072                use super::*;
1073
1074                #[test]
1075                fn test_complex_f64_log2_valid() {
1076                    let value = Complex::new(10.0, 0.0);
1077                    let expected_result = Complex::new(3.3219280948873626, 0.0);
1078                    assert_eq!(value.log2(), expected_result);
1079                    assert_eq!(value.try_log2().unwrap(), expected_result);
1080                }
1081
1082                #[test]
1083                #[cfg(debug_assertions)]
1084                fn test_complex_f64_log2_zero() {
1085                    let value = Complex::new(0.0, 0.0);
1086                    let result = value.try_log2();
1087                    assert!(matches!(
1088                        result,
1089                        Err(LogarithmComplexErrors::Input(
1090                            LogarithmComplexInputErrors::ZeroArgument { .. }
1091                        ))
1092                    ));
1093                }
1094
1095                #[test]
1096                fn test_complex_f64_log2_negative() {
1097                    let value = Complex::new(-10.0, 0.0);
1098                    let expected_result = Complex::new(3.3219280948873626, 4.532360141827194);
1099                    assert_eq!(value.log2(), expected_result);
1100                    assert_eq!(value.try_log2().unwrap(), expected_result);
1101                }
1102
1103                #[test]
1104                fn test_complex_f64_log2_one() {
1105                    let value = Complex::new(1.0, 0.0);
1106                    let expected_result = Complex::new(0.0, 0.0);
1107                    assert_eq!(value.log2(), expected_result);
1108                    assert_eq!(value.try_log2().unwrap(), expected_result);
1109                }
1110
1111                #[test]
1112                #[cfg(debug_assertions)]
1113                fn test_complex_f64_log2_infinity() {
1114                    let value = Complex::new(f64::INFINITY, 0.0);
1115                    let result = value.try_log2();
1116                    assert!(matches!(
1117                        result,
1118                        Err(LogarithmComplexErrors::Input(
1119                            LogarithmComplexInputErrors::InvalidArgument { .. }
1120                        ))
1121                    ));
1122
1123                    let value = Complex::new(0.0, f64::INFINITY);
1124                    let result = value.try_log2();
1125                    assert!(matches!(
1126                        result,
1127                        Err(LogarithmComplexErrors::Input(
1128                            LogarithmComplexInputErrors::InvalidArgument { .. }
1129                        ))
1130                    ));
1131                }
1132
1133                #[test]
1134                #[cfg(debug_assertions)]
1135                fn test_complex_f64_log2_nan() {
1136                    let value = Complex::new(f64::NAN, 0.0);
1137                    let result = value.try_log2();
1138                    assert!(matches!(
1139                        result,
1140                        Err(LogarithmComplexErrors::Input(
1141                            LogarithmComplexInputErrors::InvalidArgument { .. }
1142                        ))
1143                    ));
1144
1145                    let value = Complex::new(0.0, f64::NAN);
1146                    let result = value.try_log2();
1147                    assert!(matches!(
1148                        result,
1149                        Err(LogarithmComplexErrors::Input(
1150                            LogarithmComplexInputErrors::InvalidArgument { .. }
1151                        ))
1152                    ));
1153                }
1154            }
1155        }
1156
1157        #[cfg(feature = "rug")]
1158        mod rug53 {
1159            use super::*;
1160            use rug::{Complex, Float};
1161
1162            mod real {
1163                use super::*;
1164
1165                #[test]
1166                fn test_real_log2_valid() {
1167                    let value =
1168                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
1169                    let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
1170                        53,
1171                        std::f64::consts::LOG2_10,
1172                    ))
1173                    .unwrap();
1174                    assert_eq!(value.clone().log2(), expected_result);
1175                    assert_eq!(value.try_log2().unwrap(), expected_result);
1176                }
1177
1178                #[test]
1179                fn test_real_log2_zero() {
1180                    let value =
1181                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
1182                    let result = value.try_log2();
1183                    assert!(matches!(
1184                        result,
1185                        Err(LogarithmRealErrors::Input(
1186                            LogarithmRealInputErrors::ZeroArgument { .. }
1187                        ))
1188                    ));
1189                }
1190
1191                #[test]
1192                fn test_real_log2_negative() {
1193                    let value =
1194                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
1195                    let result = value.try_log2();
1196                    assert!(matches!(
1197                        result,
1198                        Err(LogarithmRealErrors::Input(
1199                            LogarithmRealInputErrors::NegativeArgument { .. }
1200                        ))
1201                    ));
1202                }
1203
1204                #[test]
1205                fn test_real_log2_one() {
1206                    let value =
1207                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
1208                    let expected_result =
1209                        RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
1210                    assert_eq!(value.clone().log2(), expected_result);
1211                    assert_eq!(value.try_log2().unwrap(), expected_result);
1212                }
1213            }
1214
1215            mod complex {
1216                use super::*;
1217
1218                #[test]
1219                fn test_complex_log2_valid() {
1220                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1221                        53,
1222                        (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
1223                    ))
1224                    .unwrap();
1225                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1226                        53,
1227                        (
1228                            Float::with_val(53, 3.3219280948873626),
1229                            Float::with_val(53, 0.0),
1230                        ),
1231                    ))
1232                    .unwrap();
1233                    assert_eq!(value.clone().log2(), expected_result);
1234                    assert_eq!(value.try_log2().unwrap(), expected_result);
1235                }
1236
1237                #[test]
1238                fn test_complex_log2_zero() {
1239                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1240                        53,
1241                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
1242                    ))
1243                    .unwrap();
1244                    let result = value.try_log2();
1245                    assert!(matches!(
1246                        result,
1247                        Err(LogarithmComplexErrors::Input(
1248                            LogarithmComplexInputErrors::ZeroArgument { .. }
1249                        ))
1250                    ));
1251                }
1252
1253                #[test]
1254                fn test_complex_log2_negative() {
1255                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1256                        53,
1257                        (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
1258                    ))
1259                    .unwrap();
1260                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1261                        53,
1262                        (
1263                            Float::with_val(53, 3.3219280948873626),
1264                            Float::with_val(53, 4.532360141827194),
1265                        ),
1266                    ))
1267                    .unwrap();
1268                    assert_eq!(value.clone().log2(), expected_result);
1269                    assert_eq!(value.try_log2().unwrap(), expected_result);
1270                }
1271
1272                #[test]
1273                fn test_complex_log2_one() {
1274                    let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1275                        53,
1276                        (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
1277                    ))
1278                    .unwrap();
1279                    let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1280                        53,
1281                        (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
1282                    ))
1283                    .unwrap();
1284                    assert_eq!(value.clone().log2(), expected_result);
1285                    assert_eq!(value.try_log2().unwrap(), expected_result);
1286                }
1287            }
1288        }
1289    }
1290}
1291//------------------------------------------------------------------