use uninum::{Number, num};
#[test]
fn test_basic_pow() {
assert_eq!(
Number::from(2u64).pow(&Number::from(3u64)),
Number::from(8u64)
);
assert_eq!(
Number::from(10u64).pow(&Number::from(2u64)),
Number::from(100u64)
);
assert_eq!(
Number::from(-2i64).pow(&Number::from(3u64)),
Number::from(-8i64)
);
assert_eq!(
Number::from(-2i64).pow(&Number::from(4u64)),
Number::from(16i64)
);
assert_eq!(
Number::from(42u64).pow(&Number::from(0u64)),
Number::from(1u64)
);
assert_eq!(
Number::from(42u64).pow(&Number::from(1u64)),
Number::from(42u64)
);
assert_eq!(num!(3.16).pow(&Number::from(0u64)), num!(1.0));
assert_eq!(
Number::from(0u64).pow(&Number::from(0u64)),
Number::from(1u64)
); assert_eq!(
Number::from(0u64).pow(&Number::from(5u64)),
Number::from(0u64)
);
assert_eq!(
Number::from(0i64).pow(&Number::from(3u64)),
Number::from(0i64)
);
}
#[test]
fn test_pow_overflow() {
assert_eq!(
Number::from(1000u64).pow(&Number::from(3u64)),
Number::from(1_000_000_000u64)
);
assert_eq!(
Number::from(2u64).pow(&Number::from(32u64)),
Number::from(4_294_967_296u64)
);
assert_eq!(
Number::from(u64::MAX).pow(&Number::from(1u64)),
Number::from(u64::MAX)
);
let result = Number::from(100u64).pow(&Number::from(5u64));
if let Some(n) = result.try_get_u64() {
assert_eq!(n, 10_000_000_000);
} else if let Some(f) = result.try_get_f64() {
assert_eq!(f, 10_000_000_000.0);
} else {
panic!("Unexpected result type for 100^5");
}
}
#[test]
fn test_pow_float_exponents() {
let result = num!(4.0).pow(&num!(0.5));
assert_eq!(result, num!(2.0));
let result = num!(8.0).pow(&num!(1.0 / 3.0));
if let Some(f) = result.try_get_f64() {
assert!((f - 2.0).abs() < 1e-10);
} else {
panic!("Expected F64 result for cube root");
}
let result = Number::from(4u64).pow(&num!(0.5));
assert_eq!(result, num!(2.0));
let base = Number::from(10u64);
let exp = Number::from(100u64);
let result = base.pow(&exp);
assert!(result.try_get_f64().is_some());
let exp = Number::from(3i64);
let result = Number::from(2u64).pow(&exp);
assert_eq!(result, Number::from(8u64));
let exp = Number::from(4i64);
let result = Number::from(3u64).pow(&exp);
assert_eq!(result, Number::from(81u64));
let exp = num!(5.0);
let result = Number::from(2u64).pow(&exp);
assert_eq!(result, Number::from(32u64));
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let exp = Number::from(Decimal::new(3, 0));
let result = Number::from(4u64).pow(&exp);
assert_eq!(result, Number::from(64u64));
}
}
#[test]
fn test_pow_negative_exponents() {
assert_eq!(Number::from(2u64).pow(&Number::from(-3i64)), num!(0.125));
assert_eq!(Number::from(10u64).pow(&Number::from(-2i64)), num!(0.01));
assert_eq!(num!(4.0).pow(&Number::from(-1i64)), num!(0.25));
assert_eq!(num!(2.0).pow(&Number::from(-3i64)), num!(0.125));
let exp = Number::from(-2i64);
let result = Number::from(4u64).pow(&exp);
assert_eq!(result, num!(0.0625));
let exp = num!(-3.0);
let result = Number::from(2u64).pow(&exp);
assert_eq!(result, num!(0.125));
let base = Number::from(10u64);
assert_eq!(base.clone().pow(&Number::from(-1i64)), num!(0.1));
assert_eq!(base.pow(&Number::from(-3i64)), num!(0.001));
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let exp = Number::from(Decimal::new(-2, 0));
let result = Number::from(5u64).pow(&exp);
assert_eq!(result, num!(0.04));
}
}
#[test]
fn test_pow_special_cases() {
assert_eq!(
Number::from(0u64).pow(&Number::from(-1i64)),
num!(f64::INFINITY)
);
assert_eq!(num!(0.0).pow(&Number::from(-2i64)), num!(f64::INFINITY));
assert_eq!(
num!(-0.0).pow(&Number::from(-3i64)),
num!(f64::NEG_INFINITY)
);
let result = Number::from(-4i64).pow(&num!(0.5));
assert!(result.is_nan());
let result = num!(-2.0).pow(&num!(1.5));
assert!(result.is_nan());
assert_eq!(
Number::from(0u64).pow(&Number::from(1u64)),
Number::from(0u64)
);
assert_eq!(
Number::from(0u64).pow(&Number::from(100u64)),
Number::from(0u64)
);
assert_eq!(num!(0.0).pow(&Number::from(5u64)), num!(0.0));
assert_eq!(
Number::from(0u64).pow(&Number::from(0u64)),
Number::from(1u64)
);
assert_eq!(num!(0.0).pow(&Number::from(0u64)), num!(1.0));
assert_eq!(
Number::from(0u64).pow(&Number::from(-1i64)),
num!(f64::INFINITY)
);
assert_eq!(num!(0.0).pow(&Number::from(-5i64)), num!(f64::INFINITY));
}
#[test]
fn test_pow_special_floats() {
let inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
let nan = num!(f64::NAN);
assert_eq!(inf.clone().pow(&Number::from(2u64)), num!(f64::INFINITY));
assert_eq!(inf.clone().pow(&num!(0.5)), num!(f64::INFINITY));
assert_eq!(inf.clone().pow(&Number::from(-1i64)), num!(0.0));
assert_eq!(inf.clone().pow(&num!(-0.5)), num!(0.0));
assert_eq!(
neg_inf.clone().pow(&Number::from(2u64)),
num!(f64::INFINITY)
);
assert_eq!(
neg_inf.clone().pow(&Number::from(3u64)),
num!(f64::NEG_INFINITY)
);
assert!(nan.clone().pow(&Number::from(2u64)).is_nan());
assert!(Number::from(2u64).pow(&nan.clone()).is_nan());
assert_eq!(inf.clone().pow(&Number::from(0u64)), num!(1.0));
assert_eq!(nan.clone().pow(&Number::from(0u64)), num!(1.0));
assert_eq!(num!(1.0).pow(&inf), num!(1.0));
assert_eq!(num!(1.0).pow(&nan), num!(1.0));
let nan_exp = num!(f64::NAN);
assert_eq!(Number::from(1u64).pow(&nan_exp.clone()), Number::from(1u64));
assert_eq!(num!(1.0).pow(&nan_exp.clone()), num!(1.0));
assert_eq!(Number::from(1i64).pow(&nan_exp.clone()), Number::from(1i64));
assert!(Number::from(2u64).pow(&nan_exp.clone()).is_nan());
assert!(num!(0.5).pow(&nan_exp.clone()).is_nan());
assert!(Number::from(0u64).pow(&nan_exp.clone()).is_nan());
assert!(Number::from(-1i64).pow(&nan_exp.clone()).is_nan());
let almost_one = num!(1.0000000000000002);
assert!(almost_one.pow(&nan_exp).is_nan());
let nan_result = Number::from(0u64).pow(&num!(f64::NAN));
assert!(nan_result.is_nan());
let inf_result = Number::from(0u64).pow(&Number::from(-2i64));
assert_eq!(inf_result, num!(f64::INFINITY));
let neg_inf_result = num!(-0.0).pow(&Number::from(-3i64));
assert_eq!(neg_inf_result, num!(f64::NEG_INFINITY));
let recip_result = Number::from(4u64).pow(&Number::from(-1i64));
assert_eq!(recip_result, num!(0.25));
}
#[test]
fn test_pow_by_squaring_edge_cases() {
assert_eq!(
Number::from(3u64).pow(&Number::from(4u64)),
Number::from(81u64)
); assert_eq!(
Number::from(2u64).pow(&Number::from(16u64)),
Number::from(65536u64)
); assert_eq!(
Number::from(5u64).pow(&Number::from(8u64)),
Number::from(390625u64)
);
assert_eq!(
Number::from(2u64).pow(&Number::from(5u64)),
Number::from(32u64)
); assert_eq!(
Number::from(3u64).pow(&Number::from(7u64)),
Number::from(2187u64)
);
assert_eq!(
Number::from(3u64).pow(&Number::from(13u64)),
Number::from(1594323u64)
); }
#[test]
fn test_pow_mixed_types() {
assert_eq!(
Number::from(10u64).pow(&Number::from(2i64)),
Number::from(100u64)
);
assert_eq!(
Number::from(-3i64).pow(&Number::from(2u64)),
Number::from(9i64)
);
assert_eq!(num!(10.0).pow(&Number::from(-2i64)), num!(0.01));
assert_eq!(
Number::from(3u64).pow(&Number::from(3u64)),
Number::from(27u64)
);
assert_eq!(
Number::from(4u64).pow(&Number::from(2i64)),
Number::from(16u64)
);
}
#[test]
fn test_pow_chains() {
let result = Number::from(2u64)
.pow(&Number::from(3u64))
.pow(&Number::from(2u64));
assert_eq!(result, Number::from(64u64));
let result = Number::from(2u64)
.pow(&Number::from(8u64))
.pow(&Number::from(2u64));
assert_eq!(result, Number::from(65536u64));
}
#[test]
fn test_pow_extreme_values() {
let result = num!(0.1).pow(&Number::from(100u64));
if let Some(f) = result.try_get_f64() {
assert!(f < 1e-50);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Expected F64 or Decimal result");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64 result");
}
}
let result = num!(0.9).pow(&Number::from(1000u64));
if let Some(f) = result.try_get_f64() {
assert!(f < 1e-10);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Expected F64 or Decimal result");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64 result");
}
}
let result = num!(1.0001).pow(&Number::from(10000u64));
if let Some(f) = result.try_get_f64() {
assert!((f - std::f64::consts::E).abs() < 0.1);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Expected F64 or Decimal result");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64 result");
}
}
let subnormal = num!(f64::MIN_POSITIVE / 2.0);
let result = subnormal.pow(&Number::from(2u64));
assert!(result.try_get_f64().is_some());
let result = Number::from(2u64).pow(&Number::from(1000u64));
assert!(result.try_get_f64().is_some());
let result = Number::from(10u64).pow(&Number::from(100u64));
assert!(result.try_get_f64().is_some());
let result = num!(1.1).pow(&Number::from(10000u64));
assert!(result.try_get_f64().is_some());
let result = num!(0.9).pow(&Number::from(10000u64));
#[cfg(feature = "decimal")]
assert!(result.try_get_f64().is_some() || result.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_f64().is_some());
}
#[test]
fn test_pow_negative_zero() {
let neg_zero = num!(-0.0);
let pos_zero = num!(0.0);
let result = neg_zero.clone().pow(&Number::from(2u64));
if let Some(f) = result.try_get_f64() {
assert_eq!(f, 0.0);
}
let result = neg_zero.clone().pow(&Number::from(3u64));
if let Some(f) = result.try_get_f64() {
assert_eq!(f, 0.0);
}
let result = neg_zero.clone().pow(&Number::from(-3i64));
assert_eq!(result, num!(f64::NEG_INFINITY));
let result = neg_zero.pow(&Number::from(-2i64));
assert_eq!(result, num!(f64::INFINITY));
let result = pos_zero.pow(&Number::from(-5i64));
assert_eq!(result, num!(f64::INFINITY));
}
#[test]
fn test_pow_negative_zero_with_float_integer_exponent() {
let neg_zero = num!(-0.0);
let result = neg_zero.pow(&num!(3.0));
assert!(matches!(result.try_get_f64(), Some(v) if v == 0.0 && v.is_sign_negative()));
}
#[test]
fn test_pow_more_special_floats() {
let denormal = num!(f64::MIN_POSITIVE / 10.0);
let result = denormal.clone().pow(&Number::from(1u64));
assert_eq!(result, denormal);
let max_f64 = num!(f64::MAX);
let result = max_f64.pow(&Number::from(0u64));
assert_eq!(result, num!(1.0));
let result = num!(0.0001).pow(&num!(0.5));
if let Some(f) = result.try_get_f64() {
assert!((f - 0.01).abs() < 1e-10);
} else {
panic!("Expected F64 result");
}
}
#[test]
fn test_pow_integer_behavior() {
assert!(
Number::from(2u64)
.pow(&Number::from(10u64))
.try_get_u64()
.is_some()
);
assert!(
Number::from(-3i64)
.pow(&Number::from(5u64))
.try_get_i64()
.is_some()
);
let result = Number::from(-10i64).pow(&Number::from(3u64));
assert_eq!(result, Number::from(-1000i64));
let result = Number::from(2u64).pow(&Number::from(63u64));
#[cfg(feature = "decimal")]
assert!(
result.try_get_u64().is_some()
|| result.try_get_f64().is_some()
|| result.try_get_decimal().is_some()
);
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_u64().is_some() || result.try_get_f64().is_some());
}
#[test]
fn test_pow_negative_base_edge_cases() {
assert_eq!(
Number::from(-5i64).pow(&Number::from(2u64)),
Number::from(25i64)
);
assert_eq!(
Number::from(-5i64).pow(&Number::from(4u64)),
Number::from(625i64)
);
assert_eq!(
Number::from(3i64).pow(&Number::from(2i64)),
Number::from(9i64)
);
assert_eq!(num!(-2.5).pow(&Number::from(2u64)), num!(6.25));
assert_eq!(num!(-2.5).pow(&Number::from(3u64)), num!(-15.625));
let result = num!(-8.0).pow(&num!(0.9999999999));
assert!(result.is_nan());
let result = num!(-1.0).pow(&num!(2.0 + 0.00001));
assert!(result.is_nan());
assert_eq!(num!(-2.0).pow(&num!(3.0)), num!(-8.0));
assert_eq!(num!(-2.0).pow(&num!(4.0)), num!(16.0));
assert!(num!(-2.0).pow(&num!(3.1)).is_nan());
assert!(num!(-2.0).pow(&num!(3.5)).is_nan());
assert!(num!(-2.0).pow(&num!(3.999999)).is_nan());
assert!(num!(-2.0).pow(&num!(3.0000001)).is_nan());
assert!(Number::from(-4i64).pow(&num!(0.5)).is_nan());
assert!(Number::from(-4i64).pow(&num!(1.5)).is_nan());
assert_eq!(Number::from(-4i64).pow(&num!(2.0)), Number::from(16i64));
}
#[cfg(feature = "decimal")]
#[test]
fn test_pow_with_decimal() {
use rust_decimal::Decimal;
let two = Number::from(Decimal::new(2, 0));
let three = Number::from(3u64);
let result = two.pow(&three);
assert!(result.try_get_decimal().is_some());
if let Some(d) = result.try_get_decimal() {
assert_eq!(d.to_string(), "8");
}
let base = Number::from(Decimal::new(15, 1)); let exp = Number::from(2u64);
let result = base.pow(&exp);
assert!(result.try_get_decimal().is_some());
if let Some(d) = result.try_get_decimal() {
assert_eq!(d.to_string(), "2.25");
}
let zero = Number::from(Decimal::ZERO);
let result = zero.pow(&Number::from(0u64));
assert!(result.try_get_decimal().is_some());
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::from(1));
}
let dec_exp = Number::from(Decimal::new(3, 0));
let result = Number::from(-2i64).pow(&dec_exp);
assert_eq!(result, Number::from(-8i64));
let two = Number::from(Decimal::new(2, 0));
let result = two.pow(&Number::from(-2i64));
if let Some(_d) = result.try_get_decimal() {
} else if let Some(f) = result.try_get_f64() {
assert_eq!(f, 0.25);
} else {
panic!("Unexpected result type");
}
let four = Number::from(Decimal::new(4, 0));
let result = four.pow(&num!(0.5));
if let Some(_d) = result.try_get_decimal() {
} else if let Some(f) = result.try_get_f64() {
assert_eq!(f, 2.0);
} else {
panic!("Unexpected result type");
}
let large = Number::from(Decimal::new(999999999, 0));
let result = large.pow(&Number::from(1u64));
assert!(result.try_get_decimal().is_some());
let neg = Number::from(Decimal::new(-5, 0));
let result = neg.pow(&Number::from(3u64));
if let Some(d) = result.try_get_decimal() {
assert_eq!(d.to_string(), "-125");
}
let small = Number::from(Decimal::new(1, 10)); let result = small.pow(&Number::from(2u64));
assert!(result.try_get_decimal().is_some());
let precise = Number::from(Decimal::from_str_exact("1.234567890123456789012345678").unwrap());
let result = precise.pow(&Number::from(1u64));
assert!(result.try_get_decimal().is_some());
let neg_dec = Number::from(Decimal::new(-25, 1)); let even_result = neg_dec.clone().pow(&Number::from(2u64));
let odd_result = neg_dec.pow(&Number::from(3u64));
if let Some(d) = even_result.try_get_decimal() {
assert!(d.is_sign_positive());
}
if let Some(d) = odd_result.try_get_decimal() {
assert!(d.is_sign_negative());
}
let dec_base = Number::from(Decimal::new(2, 0));
let nan_exp = num!(f64::NAN);
assert!(dec_base.pow(&nan_exp).is_nan());
let zero_dec = Number::from(Decimal::ZERO);
let result = zero_dec.pow(&Number::from(-1i64));
assert_eq!(result, num!(f64::INFINITY));
let max_dec = Number::from(Decimal::MAX);
let result = max_dec.pow(&Number::from(2u64));
assert!(result.try_get_f64().is_some());
let dec = Number::from(Decimal::new(4, 0));
let result = dec.pow(&num!(0.5));
assert_eq!(result, num!(2.0));
}
#[test]
fn test_pow_positive_i64_exponent() {
assert_eq!(
Number::from(3u64).pow(&Number::from(4i64)),
Number::from(81u64)
);
assert_eq!(
Number::from(-2i64).pow(&Number::from(5i64)),
Number::from(-32i64)
);
assert_eq!(num!(2.0).pow(&Number::from(3i64)), num!(8.0));
assert_eq!(
Number::from(5u64).pow(&Number::from(3i64)),
Number::from(125u64)
);
assert_eq!(
Number::from(-3i64).pow(&Number::from(2i64)),
Number::from(9i64)
);
assert_eq!(
Number::from(1u64).pow(&Number::from(i64::MAX)),
Number::from(1u64)
);
let result = Number::from(2u64).pow(&Number::from(-1000i64));
if let Some(f) = result.try_get_f64() {
assert!(f < 1e-300 && f > 0.0);
} else {
panic!("Expected F64 result for large negative exponent");
}
}
#[test]
fn test_pow_mul_ref_overflow_scenarios() {
let result = Number::from(65536u64).pow(&Number::from(2u64)); assert_eq!(result, Number::from(4294967296u64));
let result = Number::from(256u64).pow(&Number::from(2u64)); assert_eq!(result, Number::from(65536u64));
let result = Number::from(1024u64).pow(&Number::from(3u64)); assert_eq!(result, Number::from(1073741824u64));
let result = Number::from(-32768i64).pow(&Number::from(2u64));
let expected = 32768.0 * 32768.0;
if let Some(n) = result.try_get_i64() {
assert_eq!(n, expected as i64);
} else if let Some(f) = result.try_get_f64() {
assert_eq!(f, expected);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Unexpected result type: {result:?}");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Unexpected result type: {result:?}");
}
}
}
#[test]
fn test_pow_reciprocal_path() {
assert_eq!(Number::from(4u64).pow(&Number::from(-1i64)), num!(0.25));
assert_eq!(Number::from(100u64).pow(&Number::from(-1i64)), num!(0.01));
assert_eq!(Number::from(10u64).pow(&Number::from(-2i64)), num!(0.01));
assert_eq!(Number::from(5u64).pow(&Number::from(-2i64)), num!(0.04));
let result = Number::from(2u64).pow(&Number::from(-10i64));
assert_eq!(result, num!(1.0 / 1024.0));
let recip = Number::from(4u64).pow(&Number::from(-1i64));
let double_recip = recip.pow(&Number::from(-1i64));
assert_eq!(double_recip, num!(4.0));
}