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