#![deny(rustdoc::broken_intra_doc_links)]
use crate::{
core::{errors::capture_backtrace, policies::StrictFinitePolicy},
functions::FunctionErrors,
kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait},
};
use duplicate::duplicate_item;
use num::{Complex, Zero};
use num_traits::int::PrimInt;
use std::backtrace::Backtrace;
use thiserror::Error;
use try_create::ValidationPolicy;
pub trait IntegerExponent: PrimInt {}
impl IntegerExponent for i8 {}
impl IntegerExponent for u8 {}
impl IntegerExponent for i16 {}
impl IntegerExponent for u16 {}
impl IntegerExponent for i32 {}
impl IntegerExponent for u32 {}
impl IntegerExponent for i64 {}
impl IntegerExponent for u64 {}
impl IntegerExponent for i128 {}
impl IntegerExponent for u128 {}
impl IntegerExponent for isize {}
impl IntegerExponent for usize {}
#[derive(Debug, Error)]
pub enum PowRealBaseRealExponentInputErrors<RawReal: RawRealTrait> {
#[error("detected a negative base ({base}) with a real exponent ({exponent}) !")]
NegativeBase {
base: RawReal,
exponent: RawReal,
backtrace: Backtrace,
},
#[error("the base is invalid!")]
InvalidBase {
#[source]
#[backtrace]
source: <RawReal as RawScalarTrait>::ValidationErrors,
},
#[error("the exponent is invalid!")]
InvalidExponent {
#[source]
#[backtrace]
source: <RawReal as RawScalarTrait>::ValidationErrors,
},
#[error("the base and the exponent are invalid!")]
InvalidBaseAndExponent {
error_base: <RawReal as RawScalarTrait>::ValidationErrors,
error_exponent: <RawReal as RawScalarTrait>::ValidationErrors,
#[backtrace]
backtrace: Backtrace,
},
}
#[derive(Debug, Error)]
pub enum PowComplexBaseRealExponentInputErrors<RawComplex: RawComplexTrait> {
#[error("the input complex base is invalid according to validation policy")]
InvalidBase {
#[source]
#[backtrace]
source: <RawComplex as RawScalarTrait>::ValidationErrors,
},
#[error("the input real exponent is invalid according to validation policy")]
InvalidExponent {
#[source]
#[backtrace]
source: <RawComplex::RawReal as RawScalarTrait>::ValidationErrors,
},
#[error(
"the input complex base and the real exponent is invalid according to validation policy"
)]
InvalidBaseAndExponent {
error_base: <RawComplex as RawScalarTrait>::ValidationErrors,
error_exponent: <RawComplex::RawReal as RawScalarTrait>::ValidationErrors,
#[backtrace]
backtrace: Backtrace,
},
#[error("the base is zero and the exponent (={exponent}) is negative!")]
ZeroBaseNegativeExponent {
exponent: RawComplex::RawReal,
backtrace: Backtrace,
},
}
#[derive(Debug, Error)]
pub enum PowIntExponentInputErrors<RawScalar: RawScalarTrait, ExponentType: IntegerExponent> {
#[error("the input base is invalid according to validation policy")]
InvalidBase {
#[source]
#[backtrace]
source: <RawScalar as RawScalarTrait>::ValidationErrors,
},
#[error("detected a zero base with a negative integer exponent ({exponent:?})!")]
ZeroBaseNegativeExponent {
exponent: ExponentType,
backtrace: Backtrace,
},
}
#[derive(Debug, Error)]
pub enum PowRealBaseRealExponentErrors<RawReal: RawRealTrait> {
#[error("the input value is invalid!")]
Input {
#[from]
source: PowRealBaseRealExponentInputErrors<RawReal>,
},
#[error("the output value is invalid!")]
Output {
#[source]
#[backtrace]
source: <RawReal as RawScalarTrait>::ValidationErrors,
},
}
#[derive(Debug, Error)]
pub enum PowComplexBaseRealExponentErrors<RawComplex: RawComplexTrait> {
#[error("the input value is invalid!")]
Input {
#[from]
source: PowComplexBaseRealExponentInputErrors<RawComplex>,
},
#[error("the output value is invalid!")]
Output {
#[source]
#[backtrace]
source: <RawComplex as RawScalarTrait>::ValidationErrors,
},
}
pub type PowIntExponentErrors<RawScalar, ExponentType> = FunctionErrors<
PowIntExponentInputErrors<RawScalar, ExponentType>,
<RawScalar as RawScalarTrait>::ValidationErrors,
>;
pub trait Pow<ExponentType>: Sized {
type Error: std::error::Error;
#[must_use = "this `Result` may contain an error that should be handled"]
fn try_pow(self, exponent: ExponentType) -> Result<Self, Self::Error>;
fn pow(self, exponent: ExponentType) -> Self;
}
impl Pow<&f64> for f64 {
type Error = PowRealBaseRealExponentErrors<f64>;
#[inline(always)]
fn try_pow(self, exponent: &f64) -> Result<Self, Self::Error> {
let validation_base = StrictFinitePolicy::<f64, 53>::validate(self);
let validation_exponent = StrictFinitePolicy::<f64, 53>::validate_ref(exponent);
match (validation_base, validation_exponent) {
(Ok(base), Ok(())) => {
if base < 0.0 {
Err(PowRealBaseRealExponentInputErrors::NegativeBase {
base,
exponent: *exponent,
backtrace: capture_backtrace(),
}
.into())
} else {
let result = base.powf(*exponent);
StrictFinitePolicy::<f64, 53>::validate(result)
.map_err(|e| PowRealBaseRealExponentErrors::Output { source: e })
}
}
(Ok(_), Err(error_exponent)) => {
Err(PowRealBaseRealExponentInputErrors::InvalidExponent {
source: error_exponent,
}
.into())
}
(Err(error_base), Ok(_)) => {
Err(PowRealBaseRealExponentInputErrors::InvalidBase { source: error_base }.into())
}
(Err(error_base), Err(error_exponent)) => {
Err(PowRealBaseRealExponentInputErrors::InvalidBaseAndExponent {
error_base,
error_exponent,
backtrace: capture_backtrace(),
}
.into())
}
}
}
#[inline(always)]
fn pow(self, exponent: &f64) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent).unwrap()
}
#[cfg(not(debug_assertions))]
{
self.powf(*exponent)
}
}
}
impl Pow<&f64> for Complex<f64> {
type Error = PowComplexBaseRealExponentErrors<Self>;
#[inline(always)]
fn try_pow(self, exponent: &f64) -> Result<Self, Self::Error> {
let validation_base = StrictFinitePolicy::<Complex<f64>, 53>::validate(self);
let validation_exponent = StrictFinitePolicy::<f64, 53>::validate_ref(exponent);
match (validation_base, validation_exponent) {
(Ok(base), Ok(())) => {
if Zero::is_zero(&base) {
if *exponent < 0.0 {
Err(
PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent {
exponent: *exponent,
backtrace: capture_backtrace(),
}
.into(),
)
} else if *exponent == 0.0 {
Ok(Complex::new(1.0, 0.0))
} else {
Ok(Complex::new(0.0, 0.0))
}
} else {
let result = base.powf(*exponent);
StrictFinitePolicy::<Complex<f64>, 53>::validate(result)
.map_err(|e| PowComplexBaseRealExponentErrors::Output { source: e })
}
}
(Ok(_), Err(error_exponent)) => {
Err(PowComplexBaseRealExponentInputErrors::InvalidExponent {
source: error_exponent,
}
.into())
}
(Err(error_base), Ok(_)) => {
Err(
PowComplexBaseRealExponentInputErrors::InvalidBase { source: error_base }
.into(),
)
}
(Err(error_base), Err(error_exponent)) => Err(
PowComplexBaseRealExponentInputErrors::InvalidBaseAndExponent {
error_base,
error_exponent,
backtrace: capture_backtrace(),
}
.into(),
),
}
}
#[inline(always)]
fn pow(self, exponent: &f64) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent)
.expect("Error raised by Pow::try_pow() in the function Pow::pow() (debug mode)")
}
#[cfg(not(debug_assertions))]
{
self.powf(*exponent)
}
}
}
#[duplicate_item(
exponent_type exponent_func;
[i8] [exponent.into()];
[i16] [exponent.into()];
[i32] [exponent];
[i64] [exponent.try_into().unwrap()];
[i128] [exponent.try_into().unwrap()];
[isize] [exponent.try_into().unwrap()];
)]
impl Pow<exponent_type> for f64 {
type Error = PowIntExponentErrors<f64, exponent_type>;
fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
StrictFinitePolicy::<f64, 53>::validate(self)
.map_err(|e| PowIntExponentInputErrors::InvalidBase { source: e }.into())
.and_then(|base| {
if base == 0. && exponent < 0 {
Err(PowIntExponentInputErrors::ZeroBaseNegativeExponent {
exponent,
backtrace: capture_backtrace(),
}
.into())
} else {
let res = base.powi(exponent_func);
StrictFinitePolicy::<f64, 53>::validate(res)
.map_err(|e| Self::Error::Output { source: e })
}
})
}
#[inline(always)]
fn pow(self, exponent: exponent_type) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent).unwrap()
}
#[cfg(not(debug_assertions))]
{
self.powi(exponent_func)
}
}
}
#[duplicate_item(
exponent_type exponent_func;
[u8] [exponent.into()];
[u16] [exponent.into()];
[u32] [exponent.try_into().unwrap()];
[u64] [exponent.try_into().unwrap()];
[u128] [exponent.try_into().unwrap()];
[usize] [exponent.try_into().unwrap()];
)]
impl Pow<exponent_type> for f64 {
type Error = PowIntExponentErrors<f64, exponent_type>;
fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
StrictFinitePolicy::<f64, 53>::validate(self)
.map_err(|e| PowIntExponentInputErrors::InvalidBase { source: e }.into())
.and_then(|base| {
let res = base.powi(exponent_func);
StrictFinitePolicy::<f64, 53>::validate(res)
.map_err(|e| Self::Error::Output { source: e })
})
}
#[inline(always)]
fn pow(self, exponent: exponent_type) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent).unwrap()
}
#[cfg(not(debug_assertions))]
{
self.powi(exponent_func)
}
}
}
#[duplicate_item(
exponent_type func_name exponent_func;
[i8] [powi] [exponent.into()];
[i16] [powi] [exponent.into()];
[i32] [powi] [exponent];
[i64] [powi] [exponent.try_into().unwrap()];
[i128] [powi] [exponent.try_into().unwrap()];
[isize] [powi] [exponent.try_into().unwrap()];
)]
impl Pow<exponent_type> for Complex<f64> {
type Error = PowIntExponentErrors<Complex<f64>, exponent_type>;
#[inline(always)]
fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
StrictFinitePolicy::<Self, 53>::validate(self)
.map_err(|e| PowIntExponentInputErrors::InvalidBase { source: e }.into())
.and_then(|base| {
if Zero::is_zero(&base) && exponent < 0 {
Err(PowIntExponentInputErrors::ZeroBaseNegativeExponent {
exponent,
backtrace: capture_backtrace(),
}
.into())
} else {
StrictFinitePolicy::<Self, 53>::validate(base.func_name(exponent_func))
.map_err(|e| Self::Error::Output { source: e })
}
})
}
#[inline(always)]
fn pow(self, exponent: exponent_type) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent).unwrap()
}
#[cfg(not(debug_assertions))]
{
self.func_name(exponent_func)
}
}
}
#[duplicate_item(
exponent_type func_name exponent_func;
[u8] [powu] [exponent.into()];
[u16] [powu] [exponent.into()];
[u32] [powu] [exponent];
[u64] [powu] [exponent.try_into().unwrap()];
[u128] [powu] [exponent.try_into().unwrap()];
[usize] [powu] [exponent.try_into().unwrap()];
)]
impl Pow<exponent_type> for Complex<f64> {
type Error = PowIntExponentErrors<Complex<f64>, exponent_type>;
#[inline(always)]
fn try_pow(self, exponent: exponent_type) -> Result<Self, Self::Error> {
StrictFinitePolicy::<Self, 53>::validate(self)
.map_err(|e| PowIntExponentInputErrors::InvalidBase { source: e }.into())
.and_then(|base| {
StrictFinitePolicy::<Self, 53>::validate(base.func_name(exponent_func))
.map_err(|e| Self::Error::Output { source: e })
})
}
#[inline(always)]
fn pow(self, exponent: exponent_type) -> Self {
#[cfg(debug_assertions)]
{
self.try_pow(exponent).unwrap()
}
#[cfg(not(debug_assertions))]
{
self.func_name(exponent_func)
}
}
}
pub trait PowIntExponent:
Pow<i8, Error = PowIntExponentErrors<Self::RawType, i8>>
+ Pow<u8, Error = PowIntExponentErrors<Self::RawType, u8>>
+ Pow<i16, Error = PowIntExponentErrors<Self::RawType, i16>>
+ Pow<u16, Error = PowIntExponentErrors<Self::RawType, u16>>
+ Pow<i32, Error = PowIntExponentErrors<Self::RawType, i32>>
+ Pow<u32, Error = PowIntExponentErrors<Self::RawType, u32>>
+ Pow<i64, Error = PowIntExponentErrors<Self::RawType, i64>>
+ Pow<u64, Error = PowIntExponentErrors<Self::RawType, u64>>
+ Pow<i128, Error = PowIntExponentErrors<Self::RawType, i128>>
+ Pow<u128, Error = PowIntExponentErrors<Self::RawType, u128>>
+ Pow<isize, Error = PowIntExponentErrors<Self::RawType, isize>>
+ Pow<usize, Error = PowIntExponentErrors<Self::RawType, usize>>
{
type RawType: RawScalarTrait;
}
impl PowIntExponent for f64 {
type RawType = f64;
}
impl PowIntExponent for Complex<f64> {
type RawType = Complex<f64>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
RealScalar,
core::errors::{ErrorsValidationRawComplex, ErrorsValidationRawReal},
functions::{
Pow, PowIntExponentErrors, PowIntExponentInputErrors,
PowRealBaseRealExponentInputErrors,
},
};
use num::Complex;
#[cfg(feature = "rug")]
use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
#[cfg(feature = "rug")]
use try_create::TryNew;
mod pow_u32_exponent {
use super::*;
mod real_base {
use super::*;
fn pow_generic_real_u32_valid<RealType: RealScalar>() {
let base = RealType::try_from_f64(2.0).unwrap();
let exponent = 3u32;
let expected_result = RealType::try_from_f64(8.0).unwrap();
assert_eq!(Pow::pow(base.clone(), exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_pow_generic_real_u32_valid() {
pow_generic_real_u32_valid::<f64>();
}
#[test]
fn test_f64_pow_u32_valid() {
let base = 2.0;
let exponent = 3u32;
let expected_result = 8.0;
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_u32_zero_exponent() {
let base = 2.0;
let exponent = 0u32;
let expected_result = 1.0;
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_u32_one_exponent() {
let base = 2.0;
let exponent = 1u32;
let expected_result = 2.0;
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_u32_zero_base() {
let base = 0.0;
let exponent = 3u32;
let expected_result = 0.0;
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_u32_nan_base() {
let base = f64::NAN;
let exponent = 3u32;
let result = base.try_pow(exponent);
assert!(result.is_err());
}
#[test]
fn test_f64_pow_u32_infinity_base() {
let base = f64::INFINITY;
let exponent = 3u32;
let result = base.try_pow(exponent);
assert!(result.is_err());
}
}
mod complex_base {
use super::*;
#[test]
fn test_complex_f64_pow_u32_valid() {
let base = Complex::new(2.0, 3.0);
let exponent = 2u32;
let expected_result = Complex::new(-5.0, 12.0);
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_u32_zero_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 0u32;
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_u32_one_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 1u32;
let expected_result = Complex::new(2.0, 3.0);
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_u32_zero_base() {
let base = Complex::new(0.0, 0.0);
let exponent = 3u32;
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(Pow::pow(base, exponent), expected_result);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_u32_nan_base() {
let base = Complex::new(f64::NAN, 0.0);
let exponent = 3u32;
let result = base.try_pow(exponent);
assert!(result.is_err());
let base = Complex::new(0.0, f64::NAN);
let result = base.try_pow(exponent);
assert!(result.is_err());
}
#[test]
fn test_complex_f64_pow_u32_infinity_base() {
let base = Complex::new(f64::INFINITY, 0.0);
let exponent = 3u32;
let result = base.try_pow(exponent);
assert!(result.is_err());
let base = Complex::new(0.0, f64::INFINITY);
let result = base.try_pow(exponent);
assert!(result.is_err());
}
}
}
mod pow_i32_exponent {
use super::*;
mod native64 {
use super::*;
mod real_base {
use super::*;
#[test]
fn test_f64_pow_valid() {
let base = 2.0;
let exponent = 3i32;
let expected_result = 8.0;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
assert_eq!(<f64 as Pow<i32>>::pow(base, exponent), expected_result);
}
#[test]
fn test_f64_pow_zero_exponent() {
let base = 2.0;
let exponent = 0i32;
let expected_result = 1.0;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_negative_exponent() {
let base = 2.0;
let exponent = -3i32;
let expected_result = 0.125;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_zero_base() {
let base = 0.0;
let exponent = 3i32;
let expected_result = 0.0;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_zero_base_zero_exponent() {
let base = 0.0;
let exponent = 0i32;
let expected_result = 1.0;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_zero_base_negative_exponent() {
let base = 0.0;
let err = base.try_pow(-1i32).unwrap_err();
assert!(matches!(
err,
PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent {
exponent: -1,
..
}
}
));
}
#[test]
fn test_f64_pow_negative_base_positive_exponent() {
let base = -2.0;
let exponent = 3i32;
let expected_result = -8.0;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_negative_base_negative_exponent() {
let base = -2.0;
let exponent = -3i32;
let expected_result = -0.125;
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
}
mod complex_base {
use super::*;
#[test]
fn test_complex_f64_pow_valid() {
let base = Complex::new(2.0, 3.0);
let exponent = 2i32;
let expected_result = Complex::new(-5.0, 12.0);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
assert_eq!(
<Complex<f64> as Pow<i32>>::pow(base, exponent),
expected_result
);
}
#[test]
fn test_complex_f64_pow_zero_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 0i32;
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_negative_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = -2i32;
let expected_result = Complex::new(-0.029585798816568053, -0.07100591715976332);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base() {
let base = Complex::new(0.0, 0.0);
let exponent = 3i32;
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base_zero_exponent() {
let base = Complex::new(0.0, 0.0);
let exponent = 0i32;
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base_negative_exponent() {
let base = Complex::new(0.0, 0.0);
let err = base.try_pow(-1i32).unwrap_err();
assert!(matches!(
err,
PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent {
exponent: -1,
..
}
}
));
}
#[test]
fn test_complex_f64_pow_negative_base_positive_exponent() {
let base = Complex::new(-2.0, -3.0);
let exponent = 3i32;
let expected_result = Complex::new(46.0, -9.0);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_negative_base_negative_exponent() {
let base = Complex::new(-2.0, -3.0);
let exponent = -3i32;
let expected_result = Complex::new(0.02093764223941739, 0.004096495220755574);
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
}
}
#[cfg(feature = "rug")]
mod rug53 {
use super::*;
use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
use rug::Float;
mod real {
use super::*;
#[test]
fn test_rug_float_pow_valid() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent = 3;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 8.0)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_zero_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent = 0;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_negative_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent = -3;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.125)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_zero_base() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let exponent = 3;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_zero_base_zero_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let exponent = 0;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_negative_base_positive_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let exponent = 3;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -8.0)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_rug_float_pow_negative_base_negative_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let exponent = -3;
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -0.125)).unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
}
mod complex {
use super::*;
use rug::Complex;
#[test]
fn test_complex_rug_float_pow_valid() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent = 2;
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -5.0), Float::with_val(53, 12.0)),
))
.unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_zero_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent = 0;
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!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent = -2;
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, -2.9585798816568046e-2),
Float::with_val(53, -7.100591715976332e-2),
),
))
.unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_zero_base() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let exponent = 3;
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!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_zero_base_zero_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let exponent = 0;
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!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_base_positive_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -2.0), Float::with_val(53, -3.0)),
))
.unwrap();
let exponent = 3;
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 46.0), Float::with_val(53, -9.0)),
))
.unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_base_negative_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -2.0), Float::with_val(53, -3.0)),
))
.unwrap();
let exponent = -3;
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, 2.0937642239417388e-2),
Float::with_val(53, 4.096495220755576e-3),
),
))
.unwrap();
assert_eq!(base.try_pow(exponent).unwrap(), expected_result);
}
}
}
}
mod pow_real_exponent {
use super::*;
mod native64 {
use super::*;
mod real_base {
use super::*;
use core::f64;
#[test]
fn test_f64_pow_f64_valid() {
let base = 2.0;
let exponent = 3.0;
let expected_result = 8.0;
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_f64_zero_exponent() {
let base = 2.0;
let exponent = 0.0;
let expected_result = 1.0;
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_f64_invalid_exponent() {
let base = 2.0;
let err = base.try_pow(&f64::NAN).unwrap_err();
assert!(matches!(
err,
PowRealBaseRealExponentErrors::Input {
source: PowRealBaseRealExponentInputErrors::InvalidExponent {
source: ErrorsValidationRawReal::IsNaN { .. }
}
}
))
}
#[test]
fn test_f64_pow_f64_invalid_base_invalid_exponent() {
let err = (f64::INFINITY).try_pow(&f64::NAN).unwrap_err();
assert!(matches!(
err,
PowRealBaseRealExponentErrors::Input {
source: PowRealBaseRealExponentInputErrors::InvalidBaseAndExponent {
error_base: ErrorsValidationRawReal::IsPosInfinity { .. },
error_exponent: ErrorsValidationRawReal::IsNaN { .. },
..
}
}
))
}
#[test]
fn test_f64_pow_f64_one_exponent() {
let base = 2.0;
let exponent = 1.0;
let expected_result = 2.0;
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_f64_zero_base() {
let base = 0.0;
let exponent = 3.0;
let expected_result = 0.0;
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_f64_nan_base() {
let base = f64::NAN;
let exponent = 3.0;
let result = base.try_pow(&exponent);
assert!(result.is_err());
}
#[test]
fn test_f64_pow_f64_infinity_base() {
let base = f64::INFINITY;
let exponent = 3.0;
let result = base.try_pow(&exponent);
assert!(matches!(
result,
Err(PowRealBaseRealExponentErrors::Input { .. })
));
}
#[test]
fn test_f64_pow_f64_negative_exponent() {
let base = 2.0;
let exponent = -2.0;
let expected_result = 0.25;
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_f64_pow_f64_negative_base_positive_exponent() {
let base = -2.0;
let exponent = 3.0;
let result = base.try_pow(&exponent);
assert!(matches!(
result,
Err(PowRealBaseRealExponentErrors::Input { .. })
));
}
#[test]
fn test_f64_pow_f64_negative_base_negative_exponent() {
let base = -2.0;
let exponent = -3.0;
let result = base.try_pow(&exponent);
assert!(result.is_err());
}
}
mod complex_base {
use super::*;
#[test]
fn test_complex_f64_pow_ok_base_ok_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 2.0;
let expected_result = Complex::new(-4.999999999999999, 11.999999999999998);
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_ok_base_zero_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 0.0;
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base_zero_exponent() {
let base = Complex::new(0.0, 0.0);
let exponent = 0.0;
let expected_result = Complex::new(1.0, 0.0);
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base_negative_exponent() {
let base = Complex::new(0.0, 0.0);
let exponent = -1.0;
let err = base.try_pow(&exponent).unwrap_err();
assert!(matches!(
err,
PowComplexBaseRealExponentErrors::Input {
source:
PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent {
exponent: -1.,
..
}
}
));
}
#[test]
fn test_complex_f64_pow_ok_base_nan_exponent() {
let base = Complex::new(0.0, 0.0);
let exponent = f64::NAN;
let err = base.try_pow(&exponent).unwrap_err();
assert!(matches!(
err,
PowComplexBaseRealExponentErrors::Input {
source: PowComplexBaseRealExponentInputErrors::InvalidExponent {
source: ErrorsValidationRawReal::IsNaN { .. }
}
}
));
}
#[test]
fn test_complex_f64_pow_infinity_base_nan_exponent() {
let base = Complex::new(f64::INFINITY, 0.0);
let exponent = f64::NAN;
let err = base.try_pow(&exponent).unwrap_err();
assert!(matches!(
err,
PowComplexBaseRealExponentErrors::Input {
source: PowComplexBaseRealExponentInputErrors::InvalidBaseAndExponent {
error_base: ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsPosInfinity { .. }
},
error_exponent: ErrorsValidationRawReal::IsNaN { .. },
..
}
}
));
}
#[test]
fn test_complex_f64_pow_ok_base_one_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = 1.0;
let expected_result = Complex::new(2.0, 3.0);
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_zero_base_ok_exponent() {
let base = Complex::new(0.0, 0.0);
let exponent = 3.0;
let expected_result = Complex::new(0.0, 0.0);
assert_eq!(Pow::pow(base, &exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_nan_base_ok_exponent() {
let base = Complex::new(f64::NAN, 0.0);
let exponent = 3.0;
let result = base.try_pow(&exponent);
assert!(result.is_err());
let base = Complex::new(0.0, f64::NAN);
let result = base.try_pow(&exponent);
assert!(result.is_err());
}
#[test]
fn test_complex_f64_pow_infinity_base_ok_exponent() {
let base = Complex::new(f64::INFINITY, 0.0);
let exponent = 3.0;
let result = base.try_pow(&exponent);
assert!(result.is_err());
let base = Complex::new(0.0, f64::INFINITY);
let result = base.try_pow(&exponent);
assert!(result.is_err());
}
#[test]
fn test_complex_f64_pow_ok_base_negative_exponent() {
let base = Complex::new(2.0, 3.0);
let exponent = -2.0;
let expected_result = Complex::new(-0.029585798816568046, -0.07100591715976332);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_negative_base_positive_exponent() {
let base = Complex::new(-2.0, -3.0);
let exponent = 3.0;
let expected_result = Complex::new(46.0, -8.99999999999999);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_f64_pow_negative_base_negative_exponent() {
let base = Complex::new(-2.0, -3.0);
let exponent = -3.0;
let expected_result = Complex::new(0.02093764223941739, 0.004096495220755572);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
}
}
#[cfg(feature = "rug")]
mod rug53 {
use super::*;
use rug::{Complex, Float};
mod real_base {
use super::*;
#[test]
fn test_realrug_pow_valid() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 3.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 8.0)).unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_realrug_pow_zero_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_realrug_pow_one_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_realrug_pow_zero_base() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 3.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_realrug_pow_negative_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.25)).unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_realrug_pow_negative_base_positive_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 3.0)).unwrap();
let result = base.try_pow(&exponent);
assert!(matches!(
result,
Err(PowRealBaseRealExponentErrors::Input { .. })
));
}
#[test]
fn test_realrug_pow_negative_base_negative_exponent() {
let base =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -3.0)).unwrap();
let result = base.try_pow(&exponent);
assert!(matches!(
result,
Err(PowRealBaseRealExponentErrors::Input { .. })
));
}
}
mod complex_base {
use super::*;
#[test]
fn test_complex_rug_float_pow_valid() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 2.0)).unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -5.0), Float::with_val(53, 12.0)),
))
.unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_zero_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(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!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_one_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_zero_base() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 3.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!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 2.0), Float::with_val(53, 3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -2.0)).unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, -0.029585798816568046),
Float::with_val(53, -0.07100591715976332),
),
))
.unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_base_positive_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -2.0), Float::with_val(53, -3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, 3.0)).unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, 46.0), Float::with_val(53, -9.0)),
))
.unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
#[test]
fn test_complex_rug_float_pow_negative_base_negative_exponent() {
let base = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(Float::with_val(53, -2.0), Float::with_val(53, -3.0)),
))
.unwrap();
let exponent =
RealRugStrictFinite::<53>::try_new(Float::with_val(53, -3.0)).unwrap();
let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
53,
(
Float::with_val(53, 2.0937642239417388e-2),
Float::with_val(53, 4.096495220755576e-3),
),
))
.unwrap();
assert_eq!(base.clone().pow(&exponent), expected_result);
assert_eq!(base.try_pow(&exponent).unwrap(), expected_result);
}
}
}
}
}