#![cfg(feature = "math_funcs")]
#![allow(clippy::float_cmp)]
#[macro_use]
pub mod common;
use common::*;
use rand::Rng;
use twofloat::TwoFloat;
#[test]
fn recip_test() {
repeated_test(|| {
let source = get_valid_twofloat(|x, _| x.abs() > 1e-300);
let result = source.recip();
assert!(
result.is_valid(),
"Reciprocal of {:?} produced invalid value",
source
);
let difference = (result.recip() - source) / source;
assert!(
difference.abs() < 1e-10,
"{:?}.recip().recip() not close to original value",
source
);
})
}
#[test]
fn sqrt_test() {
repeated_test(|| {
let source = get_valid_twofloat(|x, _| x > 0.0);
let result = source.sqrt();
assert!(
result.is_valid(),
"Square root of {:?} produced invalid value",
source
);
let difference = (result * result - source).abs() / source;
assert!(
difference < 1e-16,
"Square root of {:?} ({:?}) squared gives high relative difference {}",
source,
result,
difference.hi()
);
});
}
#[test]
fn sqrt_negative_test() {
repeated_test(|| {
let source = get_valid_twofloat(|x, _| x < 0.0);
let result = source.sqrt();
assert!(
!result.is_valid(),
"Square root of negative number {:?} gave non-error result",
source
);
});
}
#[test]
fn cbrt_test() {
repeated_test(|| {
let source = get_twofloat();
let result = source.cbrt();
assert!(
result.is_valid(),
"Cube root of {:?} produced invalid value",
source
);
let difference = (result.powi(3) - source).abs() / source;
assert!(
difference < 1e-16,
"Cube root of {:?} ({:?}) squared gives high relative difference {}",
source,
result,
difference.hi()
);
});
}
#[test]
fn powi_0_test() {
repeated_test(|| {
let source = get_valid_twofloat(|x, _| x != 0.0);
let expected = TwoFloat::from(1.0);
let result = source.powi(0);
assert!(
result.is_valid(),
"Result of {:?}.powi(0) produced invalid value",
source
);
assert_eq!(result, expected, "{:?}.powi(0) did not return 1", source);
})
}
#[test]
fn powi_1_test() {
repeated_test(|| {
let source = get_twofloat();
let result = source.powi(1);
assert!(
result.is_valid(),
"{:?}.powi(1) produced invalid value",
source
);
assert_eq!(
result, source,
"{:?}.powi(1) did not return same number",
source
);
});
}
#[test]
fn powi_value_test() {
let mut rng = rand::thread_rng();
repeated_test(|| {
let source = TwoFloat::new_add(rng.gen_range(-128.0..128.0), rng.gen_range(-1.0..1.0));
let exponent = rng.gen_range(1..20);
let mut expected = TwoFloat::from(1.0);
for _ in 0..exponent {
expected *= &source;
}
let result = source.powi(exponent);
assert!(
result.is_valid(),
"{:?}.powi({}) produced invalid value",
source,
exponent
);
let difference = (result - expected) / expected;
assert!(
difference.abs() < 1e-10,
"Value mismatch in {:?}.powi({})",
source,
exponent
);
});
}
#[test]
fn powi_reciprocal_test() {
let mut rng = rand::thread_rng();
repeated_test(|| {
let source = TwoFloat::new_add(rng.gen_range(-128.0..128.0), rng.gen_range(-1.0..1.0));
let exponent = rng.gen_range(1..20);
let expected = 1.0 / source.powi(exponent);
let result = source.powi(-exponent);
assert!(
result.is_valid(),
"{:?}.powi({}) produced invalid value",
source,
-exponent
);
assert_eq!(
result, expected,
"{0:?}.powi({1}) was not reciprocal of {0:?}.powi({2})",
source, -exponent, exponent
);
});
}
#[test]
fn zero_powf_test() {
repeated_test(|| {
let source = get_twofloat();
let result = TwoFloat::from(0.0).powf(source);
if source == 0.0 {
assert!(!result.is_valid(), "0^0 returned valid result");
} else {
assert!(result.is_valid(), "0^{} produced invalid value", source);
assert_eq!(result, 0.0, "0^{} did not return 0", source);
}
})
}
#[test]
fn powf_zero_test() {
repeated_test(|| {
let source = get_twofloat();
let result = source.powf(TwoFloat::from(0.0));
if source == 0.0 {
assert!(!result.is_valid(), "0^0 returned valid result");
} else {
assert!(result.is_valid(), "{}^0 returned invalid value", source);
assert_eq!(result, 1.0, "{}^0 did not return 1", source);
}
});
}
#[test]
fn powf_test() {
let mut rng = rand::thread_rng();
let value_dist = rand::distributions::Uniform::new(1.0f64, 20.0f64);
repeated_test(|| {
let a = rng.sample(value_dist);
let b = rng.sample(value_dist);
let expected = a.powf(b);
let result = TwoFloat::from(a).powf(TwoFloat::from(b));
assert!(result.is_valid(), "{}^{} resulted in invalid value", a, b);
let difference = (result - expected).abs().hi() / expected;
assert!(
difference < 1e-8,
"{}^{} resulted in different value {} vs {}",
a,
b,
result,
expected
);
});
}