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