#![deny(rustdoc::broken_intra_doc_links)]
//! This module provides functionality for computing logarithms of real and complex numbers.
//!
//! The module includes traits and implementations for computing various types of logarithms,
//! including the natural logarithm (base `e`), base-10 logarithm, and base-2 logarithm. It also
//! defines error types that can occur during the computation of logarithms.
//!
//! # Traits
//!
//! - [`Ln`]: Trait for computing the natural logarithm (base `e`) of a number.
//! - [`Log10`]: Trait for computing the base-10 logarithm of a number.
//! - [`Log2`]: Trait for computing the base-2 logarithm of a number.
//!
//! # Error Types
//!
//! - [`LogarithmRealInputErrors`]: Errors that can occur when computing the logarithm of a real number.
//! - [`LogarithmComplexInputErrors`]: Errors that can occur when computing the logarithm of a complex number.
//! - [`LogarithmRealErrors`]: Errors that can occur when computing the logarithm of a real number, including both input and output errors.
//! - [`LogarithmComplexErrors`]: Errors that can occur when computing the logarithm of a complex number, including both input and output errors.
//!
//! # Implementations
//!
//! The traits are implemented for various numeric types, including:
//!
//! - [`f64`]: Provides logarithm functions for 64-bit floating-point numbers.
//! - [`Complex<f64>`]: Provides logarithm functions for complex numbers with 64-bit floating-point components.
//! - [`RealValidated`](crate::RealValidated): Provides logarithm functions for validated real numbers.
//! - [`ComplexValidated`](crate::ComplexValidated): Provides logarithm functions for validated complex numbers.
//!
//! # Example
//!
//! ```rust
//! use num_valid::{functions::Ln, backends::native64::raw::Native64};
//!
//!
//! let value = 2.718281828459045;
//! match value.try_ln() {
//! Ok(result) => println!("Natural Logarithm: {}", result),
//! Err(e) => println!("Error: {:?}", e),
//! }
//!
//! // Using the panicking method (simpler, panics on invalid input)
//! let result = Ln::ln(value);
//! println!("Natural Logarithm: {}", result);
//! ```
use crate::{
core::{errors::capture_backtrace, policies::StrictFinitePolicy},
functions::FunctionErrors,
kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait},
};
use duplicate::duplicate_item;
use num::Complex;
use num::Zero;
use std::backtrace::Backtrace;
use thiserror::Error;
use try_create::ValidationPolicy;
//------------------------------------------------------------------
/// Errors that can occur when computing the logarithm of a real number.
///
/// This enum represents the possible errors that can occur when computing the logarithm of a real number.
/// It includes errors for invalid arguments and other validation errors.
///
/// # Type Parameters
///
/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify
/// the numeric type for the computation and its associated raw error type `<RawReal as RawScalarTrait>::ValidationErrors`.
///
/// # Variants
///
/// - `NegativeArgument`: Indicates that the argument of the function is negative, which is not allowed
/// for real logarithms. This variant includes the value that is out of the domain and a backtrace.
/// - `ZeroArgument`: Indicates that the argument of the function is zero, which is not allowed for real logarithms.
/// This variant includes a backtrace.
/// - `InvalidArgument`: Indicates that the argument of the function is invalid. This variant includes
/// the source error that occurred during validation.
#[derive(Debug, Error)]
pub enum LogarithmRealInputErrors<RawReal: RawRealTrait> {
/// The argument of the function is negative.
///
/// This variant indicates that the argument of the function is negative, which is not allowed
/// for real logarithms. It includes the value that is out of the domain and a backtrace.
#[error("negative argument ({value})!")]
NegativeArgument {
/// The value that is out of the domain.
value: RawReal,
/// A captured backtrace for debugging purposes.
backtrace: Backtrace,
},
/// The argument of the function is zero.
///
/// This variant indicates that the argument of the function is zero, which is not allowed
/// for real logarithms. It includes a backtrace.
#[error("zero argument!")]
ZeroArgument {
/// A captured backtrace for debugging purposes.
backtrace: Backtrace,
},
/// The argument of the function is invalid.
///
/// This variant indicates that the argument of the function is invalid. It includes the source
/// error that occurred during validation.
#[error("the argument is invalid!")]
InvalidArgument {
/// The source error that occurred during validation.
#[source]
#[backtrace]
source: <RawReal as RawScalarTrait>::ValidationErrors,
},
}
/// Errors that can occur when computing the logarithm of a complex number.
///
/// This enum represents the possible errors that can occur when computing the logarithm of a complex number.
/// It includes errors for invalid arguments and other validation errors.
///
/// # Type Parameters
///
/// - `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify
/// the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarTrait>::ValidationErrors`.
///
/// # Variants
///
/// - `ZeroArgument`: Indicates that the argument of the function is zero, which is not allowed for complex logarithms.
/// This variant includes a backtrace.
/// - `InvalidArgument`: Indicates that the argument of the function is invalid. This variant includes
/// the source error that occurred during validation.
#[derive(Debug, Error)]
pub enum LogarithmComplexInputErrors<RawComplex: RawComplexTrait> {
/// The argument of the function is zero.
///
/// This variant indicates that the argument of the function is zero, which is not allowed
/// for complex logarithms. It includes a backtrace.
#[error("the argument is zero!")]
ZeroArgument {
/// A captured backtrace for debugging purposes.
backtrace: Backtrace,
},
/// The argument of the function is invalid.
///
/// This variant indicates that the argument of the function is invalid. It includes the source
/// error that occurred during validation.
#[error("the argument is invalid!")]
InvalidArgument {
/// The source error that occurred during validation.
#[source]
#[backtrace]
source: <RawComplex as RawScalarTrait>::ValidationErrors,
},
}
/// Errors that can occur when computing the logarithm of a real number.
///
/// This enum represents the possible errors that can occur when computing the logarithm of a real number.
/// It includes errors for invalid input values and other validation errors.
///
/// # Type Parameters
///
/// - `RawReal`: A type that implements the [`RawRealTrait`] trait. This type parameter is used to specify
/// the numeric type for the computation and its associated raw error type `<RawReal as RawScalarTrait>::ValidationErrors`.
///
/// # Variants
///
/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that
/// occurred during validation.
/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that
/// occurred during validation.
pub type LogarithmRealErrors<RawReal> = FunctionErrors<
LogarithmRealInputErrors<RawReal>,
<RawReal as RawScalarTrait>::ValidationErrors,
>;
/// Errors that can occur when computing the logarithm of a complex number.
///
/// This enum represents the possible errors that can occur when computing the logarithm of a complex number.
/// It includes errors for invalid input values and other validation errors.
///
/// # Type Parameters
///
/// - `RawComplex`: A type that implements the [`RawComplexTrait`] trait. This type parameter is used to specify
/// the numeric type for the computation and its associated raw error type `<RawComplex as RawScalarTrait>::ValidationErrors`.
///
/// # Variants
///
/// - `Input`: Indicates that the input value is invalid. This variant includes the source error that
/// occurred during validation.
/// - `Output`: Indicates that the output value is invalid. This variant includes the source error that
/// occurred during validation.
pub type LogarithmComplexErrors<RawComplex> = FunctionErrors<
LogarithmComplexInputErrors<RawComplex>,
<RawComplex as RawScalarTrait>::ValidationErrors,
>;
#[duplicate_item(
trait_name try_func func trait_doc try_func_doc func_doc err_doc;
[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."];
[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."];
[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."];
)]
#[doc = trait_doc]
pub trait trait_name: Sized {
#[doc = err_doc]
type Error: std::error::Error;
#[doc = try_func_doc]
#[must_use = "this `Result` may contain an error that should be handled"]
fn try_func(self) -> Result<Self, Self::Error>;
#[doc = func_doc]
fn func(self) -> Self;
}
#[duplicate_item(
trait_name try_func func;
[Ln] [try_ln] [ln];
[Log10] [try_log10] [log10];
[Log2] [try_log2] [log2];
)]
impl trait_name for f64 {
type Error = LogarithmRealErrors<Self>;
#[inline(always)]
fn try_func(self) -> Result<Self, Self::Error> {
StrictFinitePolicy::<Self, 53>::validate(self)
.map_err(|e| LogarithmRealInputErrors::InvalidArgument { source: e }.into())
.and_then(|v| {
if v < 0.0 {
Err(LogarithmRealInputErrors::NegativeArgument {
value: v,
backtrace: capture_backtrace(),
}
.into())
} else if v == 0. {
Err(LogarithmRealInputErrors::ZeroArgument {
backtrace: capture_backtrace(),
}
.into())
} else {
StrictFinitePolicy::<Self, 53>::validate(f64::func(v))
.map_err(|e| LogarithmRealErrors::Output { source: e })
}
})
}
#[inline(always)]
fn func(self) -> Self {
#[cfg(debug_assertions)]
{
self.try_func().unwrap()
}
#[cfg(not(debug_assertions))]
{
f64::func(self)
}
}
}
#[duplicate_item(
trait_name try_func func;
[Ln] [try_ln] [ln];
[Log10] [try_log10] [log10];
[Log2] [try_log2] [log2];
)]
impl trait_name for Complex<f64> {
type Error = LogarithmComplexErrors<Self>;
#[inline(always)]
fn try_func(self) -> Result<Self, Self::Error> {
StrictFinitePolicy::<Self, 53>::validate(self)
.map_err(|e| LogarithmComplexInputErrors::InvalidArgument { source: e }.into())
.and_then(|v| {
if Zero::is_zero(&v) {
Err(LogarithmComplexInputErrors::ZeroArgument {
backtrace: capture_backtrace(),
}
.into())
} else {
StrictFinitePolicy::<Self, 53>::validate(Complex::func(v))
.map_err(|e| LogarithmComplexErrors::Output { source: e })
}
})
}
#[inline(always)]
fn func(self) -> Self {
#[cfg(debug_assertions)]
{
self.try_func().unwrap()
}
#[cfg(not(debug_assertions))]
{
Complex::func(self)
}
}
}
//------------------------------------------------------------------
//------------------------------------------------------------------
/// A convenience trait that aggregates the standard logarithm functions.
///
/// This trait serves as a shorthand for requiring a type to implement all the fundamental
/// logarithm operations:
/// - [`Ln`] (natural logarithm)
/// - [`Log10`] (base-10 logarithm)
/// - [`Log2`] (base-2 logarithm)
///
/// It is primarily used as a super-trait for [`FpScalar`](crate::FpScalar) to simplify trait bounds
/// and ensure that any scalar type in the library provides a comprehensive set of logarithmic
/// capabilities. By using `LogarithmFunctions` as a bound, you can write generic functions that
/// utilize any of its constituent trait methods.
///
/// # Examples
///
/// ```
/// use num_valid::functions::{LogarithmFunctions, Ln, Log10, Log2};
/// use std::fmt::Debug;
///
/// // A generic function that calculates various logarithms of a number.
/// // We bound T by FpScalar, which implies LogarithmFunctions.
/// fn calculate_logs<T>(x: T)
/// where
/// T: LogarithmFunctions + Clone + Debug,
/// {
/// let ln_x = x.clone().ln();
/// let log10_x = x.clone().log10();
/// let log2_x = x.log2();
///
/// println!("ln(x) = {:?}", ln_x);
/// println!("log10(x) = {:?}", log10_x);
/// println!("log2(x) = {:?}", log2_x);
/// }
///
/// let value = 100.0f64;
/// calculate_logs(value);
///
/// // Verify the results
/// assert_eq!(value.ln(), 4.605170185988092);
/// assert_eq!(value.log10(), 2.0);
/// assert_eq!(value.log2(), 6.643856189774724);
/// ```
pub trait LogarithmFunctions: Ln + Log2 + Log10 {}
#[duplicate_item(
T;
[f64];
[Complex<f64>];
)]
impl LogarithmFunctions for T {}
//------------------------------------------------------------------
//------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "rug")]
use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
#[cfg(feature = "rug")]
use try_create::TryNew;
mod ln {
use super::*;
mod native64 {
use super::*;
mod real {
use super::*;
#[test]
fn test_f64_ln_valid() {
let value = 10.0;
let expected_result = std::f64::consts::LN_10;
assert_eq!(value.ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_f64_ln_zero() {
let value = 0.0;
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_f64_ln_negative() {
let value = -10.0;
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_f64_ln_one() {
let value = 1.0;
let expected_result = 0.0;
assert_eq!(value.ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_f64_ln_infinity() {
let value = f64::INFINITY;
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_f64_ln_nan() {
let value = f64::NAN;
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn test_complex_f64_ln_valid() {
let value = Complex::new(10.0, 0.0);
let expected_result = Complex::new(std::f64::consts::LN_10, 0.0);
assert_eq!(value.ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_ln_zero() {
let value = Complex::new(0.0, 0.0);
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_f64_ln_negative() {
let value = Complex::new(-10.0, 0.0);
let expected_result =
Complex::new(std::f64::consts::LN_10, std::f64::consts::PI);
assert_eq!(value.ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_ln_one() {
let value = Complex::new(1.0, 0.0);
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(value.ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_ln_infinity() {
let value = Complex::new(f64::INFINITY, 0.0);
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::INFINITY);
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_complex_f64_ln_nan() {
let value = Complex::new(f64::NAN, 0.0);
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::NAN);
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
}
}
#[cfg(feature = "rug")]
mod rug53 {
use super::*;
use rug::{Complex, Float};
mod real {
use super::*;
#[test]
fn test_real_ln_valid() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
53,
std::f64::consts::LN_10,
))
.unwrap();
assert_eq!(value.clone().ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_real_ln_zero() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_real_ln_negative() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_real_ln_one() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert_eq!(value.clone().ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
}
mod complex {
use super::*;
#[test]
fn test_complex_ln_valid() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, std::f64::consts::LN_10),
Float::with_val(53, 0.0),
),
))
.unwrap();
assert_eq!(value.clone().ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_complex_ln_zero() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let result = value.try_ln();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_ln_negative() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, std::f64::consts::LN_10),
Float::with_val(53, std::f64::consts::PI),
),
))
.unwrap();
assert_eq!(value.clone().ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
#[test]
fn test_complex_ln_one() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
assert_eq!(value.clone().ln(), expected_result);
assert_eq!(value.try_ln().unwrap(), expected_result);
}
}
}
}
mod log10 {
use super::*;
mod native64 {
use super::*;
mod real {
use super::*;
#[test]
fn test_f64_log10_valid() {
let value = 10.0;
let expected_result = 1.0;
assert_eq!(value.log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_f64_log10_zero() {
let value = 0.0;
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_f64_log10_negative() {
let value = -10.0;
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_f64_log10_one() {
let value = 1.0;
let expected_result = 0.0;
assert_eq!(value.log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_f64_log10_infinity() {
let value = f64::INFINITY;
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_f64_log10_nan() {
let value = f64::NAN;
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn test_complex_f64_log10_valid() {
let value = Complex::new(10.0, 0.0);
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(value.log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log10_zero() {
let value = Complex::new(0.0, 0.0);
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_f64_log10_negative() {
let value = Complex::new(-10.0, 0.0);
let expected_result = Complex::new(1.0, 1.3643763538418412);
assert_eq!(value.log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log10_one() {
let value = Complex::new(1.0, 0.0);
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(value.log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log10_infinity() {
let value = Complex::new(f64::INFINITY, 0.0);
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::INFINITY);
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_complex_f64_log10_nan() {
let value = Complex::new(f64::NAN, 0.0);
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::NAN);
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
}
}
#[cfg(feature = "rug")]
mod rug53 {
use super::*;
use rug::{Complex, Float};
mod real {
use super::*;
#[test]
fn test_real_log10_valid() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert_eq!(value.clone().log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_real_log10_zero() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_real_log10_negative() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_real_log10_one() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert_eq!(value.clone().log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
}
mod complex {
use super::*;
#[test]
fn test_complex_log10_valid() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
))
.unwrap();
assert_eq!(value.clone().log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_complex_log10_zero() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let result = value.try_log10();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_log10_negative() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, 1.0),
Float::with_val(53, 1.3643763538418414),
),
))
.unwrap();
assert_eq!(value.clone().log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
#[test]
fn test_complex_log10_one() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
assert_eq!(value.clone().log10(), expected_result);
assert_eq!(value.try_log10().unwrap(), expected_result);
}
}
}
}
mod log2 {
use super::*;
mod native64 {
use super::*;
mod real {
use super::*;
#[test]
fn test_f64_log2_valid() {
let value = 10.0;
let expected_result = std::f64::consts::LOG2_10;
assert_eq!(value.log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_f64_log2_zero() {
let value = 0.0;
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_f64_log2_negative() {
let value = -10.0;
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_f64_log2_one() {
let value = 1.0;
let expected_result = 0.0;
assert_eq!(value.log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_f64_log2_infinity() {
let value = f64::INFINITY;
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_f64_log2_nan() {
let value = f64::NAN;
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::InvalidArgument { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn test_complex_f64_log2_valid() {
let value = Complex::new(10.0, 0.0);
let expected_result = Complex::new(3.3219280948873626, 0.0);
assert_eq!(value.log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log2_zero() {
let value = Complex::new(0.0, 0.0);
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_f64_log2_negative() {
let value = Complex::new(-10.0, 0.0);
let expected_result = Complex::new(3.3219280948873626, 4.532360141827194);
assert_eq!(value.log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log2_one() {
let value = Complex::new(1.0, 0.0);
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(value.log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_complex_f64_log2_infinity() {
let value = Complex::new(f64::INFINITY, 0.0);
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::INFINITY);
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
#[test]
fn test_complex_f64_log2_nan() {
let value = Complex::new(f64::NAN, 0.0);
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
let value = Complex::new(0.0, f64::NAN);
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::InvalidArgument { .. }
})
));
}
}
}
#[cfg(feature = "rug")]
mod rug53 {
use super::*;
use rug::{Complex, Float};
mod real {
use super::*;
#[test]
fn test_real_log2_valid() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
53,
std::f64::consts::LOG2_10,
))
.unwrap();
assert_eq!(value.clone().log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_real_log2_zero() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_real_log2_negative() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
}
#[test]
fn test_real_log2_one() {
let value =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert_eq!(value.clone().log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
}
mod complex {
use super::*;
#[test]
fn test_complex_log2_valid() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, 3.3219280948873626),
Float::with_val(53, 0.0),
),
))
.unwrap();
assert_eq!(value.clone().log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_complex_log2_zero() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let result = value.try_log2();
assert!(matches!(
result,
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn test_complex_log2_negative() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, 3.3219280948873626),
Float::with_val(53, 4.532360141827194),
),
))
.unwrap();
assert_eq!(value.clone().log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
#[test]
fn test_complex_log2_one() {
let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
assert_eq!(value.clone().log2(), expected_result);
assert_eq!(value.try_log2().unwrap(), expected_result);
}
}
}
}
}
//------------------------------------------------------------------