use core::cmp::Ordering::{self, *};
use malachite_base::num::arithmetic::traits::{IsPowerOf2, LogBase, LogBaseAssign, Reciprocal};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity, NegativeZero, Zero};
use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
use malachite_base::num::float::NiceFloat;
use malachite_base::num::logic::traits::SignificantBits;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_base::test_util::generators::common::GenConfig;
use malachite_base::test_util::generators::primitive_float_unsigned_pair_gen_var_4;
use malachite_float::arithmetic::log_base::{
primitive_float_log_base, primitive_float_log_base_rational,
};
use malachite_float::arithmetic::log_base_power_of_2::{
primitive_float_log_base_power_of_2, primitive_float_log_base_power_of_2_rational,
};
use malachite_float::test_util::arithmetic::log_base::{
rug_log_base, rug_log_base_prec_round, rug_log_base_rational_prec_round,
};
use malachite_float::test_util::common::rug_round_try_from_rounding_mode;
use malachite_float::test_util::generators::{
float_unsigned_rounding_mode_triple_gen_var_27, float_unsigned_rounding_mode_triple_gen_var_28,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_5,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_6,
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_1,
};
use malachite_float::{ComparableFloatRef, Float};
use malachite_nz::platform::Limb;
use malachite_q::Rational;
use malachite_q::test_util::generators::rational_unsigned_pair_gen_var_9;
use std::panic::catch_unwind;
use std::str::FromStr;
fn check(x: &Float, base: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
let (log, o) = x.clone().log_base_prec_round(base, prec, rm);
assert!(log.is_valid());
let (log_alt, o_alt) = x.log_base_prec_round_ref(base, prec, rm);
assert!(log_alt.is_valid());
assert_eq!(ComparableFloatRef(&log_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.log_base_prec_round_assign(base, prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
if base.is_power_of_2() {
let (alt, o2) =
x.log_base_power_of_2_prec_round_ref(i64::from(base.trailing_zeros()), prec, rm);
assert_eq!(ComparableFloatRef(&alt), ComparableFloatRef(&log));
assert_eq!(o2, o);
}
if log.is_normal() {
assert_eq!(log.get_prec(), Some(prec));
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_log, rug_o) =
rug_log_base_prec_round(&rug::Float::exact_from(x), base, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_log)),
ComparableFloatRef(&log),
);
assert_eq!(rug_o, o);
}
(log, o)
}
#[test]
fn test_log_base_prec_round() {
let test = |x: Float, base: u64, prec: u64, rm: RoundingMode, out: &str, o_out: Ordering| {
let (log, o) = check(&x, base, prec, rm);
assert_eq!(log.to_string(), out);
assert_eq!(o, o_out);
};
test(Float::from(1000), 10, 10, Exact, "3.0", Equal);
test(Float::from(100), 10, 10, Exact, "2.0", Equal);
test(Float::from(81), 3, 10, Exact, "4.0", Equal);
test(Float::from(243), 3, 10, Nearest, "5.0", Equal); test(Float::from(16807), 7, 10, Nearest, "5.0", Equal); test(Float::from(1), 10, 10, Exact, "0.0", Equal);
test(Float::from(64), 4, 10, Nearest, "3.0", Equal); test(Float::from(8), 2, 10, Exact, "3.0", Equal);
test(Float::from(1000000), 8, 10, Nearest, "6.64", Less); test(Float::from(3), 9, 10, Exact, "0.5", Equal); test(Float::from(81), 9, 10, Exact, "2.0", Equal); test(Float::from(50), 10, 10, Floor, "1.697", Less);
test(Float::from(50), 10, 10, Ceiling, "1.699", Greater);
test(Float::from(50), 10, 10, Nearest, "1.699", Greater);
test(Float::from(2), 3, 20, Nearest, "0.63093", Greater);
test(Float::from(1) >> 3, 3, 20, Nearest, "-1.89279", Less); test(Float::NAN, 10, 10, Nearest, "NaN", Equal);
test(Float::INFINITY, 10, 10, Nearest, "Infinity", Equal);
test(Float::NEGATIVE_INFINITY, 10, 10, Nearest, "NaN", Equal);
test(Float::ZERO, 10, 10, Nearest, "-Infinity", Equal);
test(Float::NEGATIVE_ZERO, 10, 10, Nearest, "-Infinity", Equal);
test(-Float::from(5), 10, 10, Nearest, "NaN", Equal);
}
#[test]
fn test_log_base_directed_consistency() {
let inputs: &[(Float, u64, u64)] = &[
(Float::from(1000), 10, 30),
(Float::from(50), 10, 30),
(Float::from(81), 3, 30),
(Float::from(2), 3, 30),
(Float::from(7), 5, 40),
(Float::from(8), 2, 30), (Float::from(64), 4, 30), (Float::from(1) >> 5, 3, 30), (Float::from(5) >> 1, 3, 30), (Float::from(3) << 1000, 5, 10), ];
for (x, base, prec) in inputs {
let (floor, _) = check(x, *base, *prec, Floor);
let (ceiling, _) = check(x, *base, *prec, Ceiling);
let (nearest, _) = check(x, *base, *prec, Nearest);
let _ = check(x, *base, *prec, Down);
let _ = check(x, *base, *prec, Up);
if floor.is_normal() && ceiling.is_normal() {
assert!(
floor <= nearest,
"{x} base {base}: floor {floor} > nearest {nearest}"
);
assert!(
nearest <= ceiling,
"{x} base {base}: nearest {nearest} > ceiling {ceiling}"
);
}
}
}
#[test]
fn test_log_base() {
let test = |x: Float, base: u64, out: &str| {
let log = x.clone().log_base(base);
assert!(log.is_valid());
assert_eq!(log.to_string(), out);
let log_alt = (&x).log_base(base);
assert!(log_alt.is_valid());
assert_eq!(ComparableFloatRef(&log_alt), ComparableFloatRef(&log));
let mut x_alt = x.clone();
x_alt.log_base_assign(base);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&log));
assert_eq!(
ComparableFloatRef(&Float::from(&rug_log_base(
&rug::Float::exact_from(&x),
base
))),
ComparableFloatRef(&log),
);
let _ = x.significant_bits();
};
test(Float::from(1000), 10, "3.0");
test(Float::from(81), 3, "4.0");
test(Float::from(1), 10, "0.0");
test(Float::NAN, 10, "NaN");
test(Float::INFINITY, 10, "Infinity");
test(Float::ZERO, 10, "-Infinity");
}
#[test]
fn log_base_prec_round_fail() {
assert_panic!(Float::from(10).log_base_prec_round(10, 0, Nearest));
assert_panic!(Float::from(10).log_base_prec_round_ref(10, 0, Nearest));
assert_panic!(Float::from(10).log_base_prec_round(1, 10, Nearest));
assert_panic!(Float::from(10).log_base_prec_round(0, 10, Nearest));
assert_panic!(Float::from(10).log_base(1));
assert_panic!(Float::from(50).log_base_prec_round(10, 10, Exact));
assert_panic!(Float::from(2).log_base_prec_round(3, 10, Exact));
}
fn check_prec(x: &Float, base: u64, prec: u64) {
let (log, o) = x.clone().log_base_prec(base, prec);
assert!(log.is_valid());
let (log_ref, o_ref) = x.log_base_prec_ref(base, prec);
assert_eq!(ComparableFloatRef(&log_ref), ComparableFloatRef(&log));
assert_eq!(o_ref, o);
let mut x_alt = x.clone();
let o_alt = x_alt.log_base_prec_assign(base, prec);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
let (expected, eo) = check(x, base, prec, Nearest);
assert_eq!(ComparableFloatRef(&log), ComparableFloatRef(&expected));
assert_eq!(o, eo);
}
fn check_round(x: &Float, base: u64, rm: RoundingMode) {
let prec = x.significant_bits();
let (expected, eo) = check(x, base, prec, rm);
let (log, o) = x.clone().log_base_round(base, rm);
assert!(log.is_valid());
assert_eq!(ComparableFloatRef(&log), ComparableFloatRef(&expected));
assert_eq!(o, eo);
let (log_ref, o_ref) = x.log_base_round_ref(base, rm);
assert_eq!(ComparableFloatRef(&log_ref), ComparableFloatRef(&log));
assert_eq!(o_ref, o);
let mut x_alt = x.clone();
let o_alt = x_alt.log_base_round_assign(base, rm);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
}
#[test]
fn log_base_prec_round_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_5().test_properties(
|(x, base, prec, rm)| {
check(&x, base, prec, rm);
},
);
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_6().test_properties(
|(x, base, prec, rm)| {
check(&x, base, prec, rm);
},
);
}
#[test]
fn log_base_prec_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_5().test_properties(
|(x, base, prec, _rm)| {
check_prec(&x, base, prec);
},
);
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_6().test_properties(
|(x, base, prec, _rm)| {
check_prec(&x, base, prec);
},
);
}
#[test]
fn log_base_round_properties() {
float_unsigned_rounding_mode_triple_gen_var_27().test_properties(|(x, base, rm)| {
check_round(&x, base, rm);
});
float_unsigned_rounding_mode_triple_gen_var_28().test_properties(|(x, base, rm)| {
check_round(&x, base, rm);
});
}
#[test]
fn log_base_properties() {
let f = |x: Float, base: u64| {
let prec = x.significant_bits();
let (expected, _) = check(&x, base, prec, Nearest);
let log = x.clone().log_base(base);
assert!(log.is_valid());
assert_eq!(ComparableFloatRef(&log), ComparableFloatRef(&expected));
let log_ref = (&x).log_base(base);
assert_eq!(ComparableFloatRef(&log_ref), ComparableFloatRef(&log));
let mut x_alt = x.clone();
x_alt.log_base_assign(base);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&log));
};
float_unsigned_rounding_mode_triple_gen_var_27().test_properties(|(x, base, _rm)| {
f(x, base);
});
float_unsigned_rounding_mode_triple_gen_var_28().test_properties(|(x, base, _rm)| {
f(x, base);
});
}
#[allow(clippy::needless_pass_by_value)]
fn log_base_rational_prec_round_properties_helper(
x: Rational,
base: u64,
prec: u64,
rm: RoundingMode,
) {
let (log, o) = Float::log_base_rational_prec_round(x.clone(), base, prec, rm);
assert!(log.is_valid());
let (log_alt, o_alt) = Float::log_base_rational_prec_round_ref(&x, base, prec, rm);
assert!(log_alt.is_valid());
assert_eq!(ComparableFloatRef(&log_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
if base.is_power_of_2() {
let (alt, o2) = Float::log_base_power_of_2_rational_prec_round_ref(
&x,
i64::from(base.trailing_zeros()),
prec,
rm,
);
assert_eq!(ComparableFloatRef(&alt), ComparableFloatRef(&log));
assert_eq!(o2, o);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_log, rug_o) = rug_log_base_rational_prec_round(&x, base, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_log)),
ComparableFloatRef(&log),
);
assert_eq!(rug_o, o);
}
if x != 0u32 {
let (log_recip, o_recip) =
Float::log_base_rational_prec_round((&x).reciprocal(), base, prec, -rm);
assert!(log_recip.is_valid());
assert_eq!(
ComparableFloatRef(&(-log_recip).abs_negative_zero()),
ComparableFloatRef(&log.abs_negative_zero_ref())
);
assert_eq!(o_recip.reverse(), o);
}
if log.is_normal() {
assert_eq!(log.get_prec(), Some(prec));
if x > 1u32 && o > Less {
assert!(log > 0u32);
} else if x > 0u32 && x < 1u32 && o < Greater {
assert!(log < 0u32);
}
}
}
#[test]
fn log_base_rational_prec_round_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(x, base, prec, rm)| {
log_base_rational_prec_round_properties_helper(x, base, prec, rm);
},
);
let mut config = GenConfig::new();
config.insert("mean_bits_n", 2048);
config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_1().test_properties_with_config(
&config,
|(x, base, prec, rm)| {
log_base_rational_prec_round_properties_helper(x, base, prec, rm);
},
);
}
#[test]
fn log_base_rational_prec_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(x, base, prec, _rm)| {
let (log, o) = Float::log_base_rational_prec(x.clone(), base, prec);
assert!(log.is_valid());
let (log_ref, o_ref) = Float::log_base_rational_prec_ref(&x, base, prec);
assert_eq!(ComparableFloatRef(&log_ref), ComparableFloatRef(&log));
assert_eq!(o_ref, o);
let (expected, eo) = Float::log_base_rational_prec_round(x, base, prec, Nearest);
assert_eq!(ComparableFloatRef(&log), ComparableFloatRef(&expected));
assert_eq!(o, eo);
},
);
}
#[test]
fn test_log_base_rational_prec_round() {
let test =
|n: i64, d: u64, base: u64, prec: u64, rm: RoundingMode, out: &str, o_out: Ordering| {
let x = Rational::from_signeds(n, i64::exact_from(d));
let (log, o) = Float::log_base_rational_prec_round(x.clone(), base, prec, rm);
assert!(log.is_valid());
assert_eq!(log.to_string(), out);
assert_eq!(o, o_out);
let (log_alt, o_alt) = Float::log_base_rational_prec_round_ref(&x, base, prec, rm);
assert_eq!(ComparableFloatRef(&log_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rl, ro) = rug_log_base_rational_prec_round(&x, base, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rl)),
ComparableFloatRef(&log)
);
assert_eq!(ro, o);
}
};
test(3, 5, 10, 20, Floor, "-0.221849", Less);
test(3, 5, 10, 20, Ceiling, "-0.2218487", Greater);
test(3, 5, 10, 20, Nearest, "-0.2218487", Greater);
test(2, 1, 3, 20, Floor, "0.630929", Less);
test(2, 1, 3, 20, Ceiling, "0.63093", Greater);
test(2, 1, 3, 20, Nearest, "0.63093", Greater);
test(1, 8, 3, 20, Floor, "-1.89279", Less);
test(1, 8, 3, 20, Ceiling, "-1.892788", Greater);
test(1, 8, 3, 20, Nearest, "-1.89279", Less);
test(7, 1, 5, 30, Floor, "1.209061954", Less);
test(7, 1, 5, 30, Ceiling, "1.209061956", Greater);
test(7, 1, 5, 30, Nearest, "1.209061956", Greater);
test(50, 1, 10, 10, Floor, "1.697", Less);
test(50, 1, 10, 10, Ceiling, "1.699", Greater);
test(50, 1, 10, 10, Nearest, "1.699", Greater);
test(1, 100, 10, 10, Floor, "-2.0", Equal);
test(1, 100, 10, 10, Ceiling, "-2.0", Equal);
test(1, 100, 10, 10, Nearest, "-2.0", Equal);
test(1, 100, 10, 10, Exact, "-2.0", Equal);
test(22, 7, 3, 15, Floor, "1.0423", Less);
test(22, 7, 3, 15, Ceiling, "1.04236", Greater);
test(22, 7, 3, 15, Nearest, "1.04236", Greater);
test(3, 1, 9, 10, Floor, "0.5", Equal);
test(3, 1, 9, 10, Ceiling, "0.5", Equal);
test(3, 1, 9, 10, Nearest, "0.5", Equal);
test(3, 1, 9, 10, Exact, "0.5", Equal);
test(1, 9, 3, 10, Floor, "-2.0", Equal);
test(1, 9, 3, 10, Ceiling, "-2.0", Equal);
test(1, 9, 3, 10, Nearest, "-2.0", Equal);
test(1, 9, 3, 10, Exact, "-2.0", Equal);
test(1000, 1, 10, 10, Floor, "3.0", Equal);
test(1000, 1, 10, 10, Ceiling, "3.0", Equal);
test(1000, 1, 10, 10, Nearest, "3.0", Equal);
test(1000, 1, 10, 10, Exact, "3.0", Equal);
test(5, 2, 4, 20, Floor, "0.660964", Less);
test(5, 2, 4, 20, Ceiling, "0.660965", Greater);
test(5, 2, 4, 20, Nearest, "0.660964", Less);
test(0, 1, 10, 10, Nearest, "-Infinity", Equal);
test(0, 1, 10, 10, Exact, "-Infinity", Equal);
test(-3, 1, 10, 10, Nearest, "NaN", Equal);
test(1, 1, 10, 10, Exact, "0.0", Equal);
}
#[test]
fn test_log_base_rational_prec() {
let test = |n: i64, d: u64, base: u64, prec: u64, out: &str, o_out: Ordering| {
let x = Rational::from_signeds(n, i64::exact_from(d));
let (log, o) = Float::log_base_rational_prec(x.clone(), base, prec);
assert!(log.is_valid());
assert_eq!(log.to_string(), out);
assert_eq!(o, o_out);
let (log_alt, o_alt) = Float::log_base_rational_prec_ref(&x, base, prec);
assert_eq!(ComparableFloatRef(&log_alt), ComparableFloatRef(&log));
assert_eq!(o_alt, o);
};
test(3, 5, 10, 20, "-0.2218487", Greater);
test(2, 1, 3, 20, "0.63093", Greater);
test(1, 8, 3, 20, "-1.89279", Less);
test(7, 1, 5, 30, "1.209061956", Greater);
test(50, 1, 10, 10, "1.699", Greater);
test(1, 100, 10, 10, "-2.0", Equal);
test(22, 7, 3, 15, "1.04236", Greater);
test(3, 1, 9, 10, "0.5", Equal);
test(1, 9, 3, 10, "-2.0", Equal);
test(1000, 1, 10, 10, "3.0", Equal);
test(5, 2, 4, 20, "0.660964", Less);
test(0, 1, 10, 10, "-Infinity", Equal);
test(1, 1, 10, 10, "0.0", Equal);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_log_base() {
fn test<T: PrimitiveFloat>(x: T, base: u64, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_log_base(x, base)), NiceFloat(out));
}
test::<f32>(f32::NAN, 10, f32::NAN);
test::<f32>(f32::INFINITY, 10, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 10, f32::NAN);
test::<f32>(0.0, 10, f32::NEGATIVE_INFINITY);
test::<f32>(-0.0, 10, f32::NEGATIVE_INFINITY);
test::<f32>(1.0, 10, 0.0);
test::<f32>(100.0, 10, 2.0); test::<f32>(1000.0, 10, 3.0); test::<f32>(8.0, 2, 3.0); test::<f32>(9.0, 3, 2.0); test::<f32>(50.0, 10, 1.6989699602127075); test::<f32>(2.0, 10, std::f32::consts::LOG10_2); test::<f32>(50.0, 7, 2.0103821754455566); test::<f32>(-1.0, 10, f32::NAN);
test::<f64>(f64::NAN, 10, f64::NAN);
test::<f64>(f64::INFINITY, 10, f64::INFINITY);
test::<f64>(f64::NEGATIVE_INFINITY, 10, f64::NAN);
test::<f64>(0.0, 10, f64::NEGATIVE_INFINITY);
test::<f64>(-0.0, 10, f64::NEGATIVE_INFINITY);
test::<f64>(1.0, 10, 0.0);
test::<f64>(100.0, 10, 2.0); test::<f64>(1000.0, 10, 3.0); test::<f64>(8.0, 2, 3.0); test::<f64>(9.0, 3, 2.0); test::<f64>(50.0, 10, 1.6989700043360187); test::<f64>(2.0, 10, std::f64::consts::LOG10_2); test::<f64>(50.0, 7, 2.0103821378018543); test::<f64>(-1.0, 10, f64::NAN);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_log_base_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_unsigned_pair_gen_var_4::<T, u64>().test_properties(|(x, base)| {
if base < 2 {
return;
}
let y = primitive_float_log_base(x, base);
if base.is_power_of_2() {
assert_eq!(
NiceFloat(y),
NiceFloat(primitive_float_log_base_power_of_2(
x,
i64::exact_from(base.trailing_zeros())
))
);
}
});
}
#[test]
fn primitive_float_log_base_properties() {
apply_fn_to_primitive_floats!(primitive_float_log_base_properties_helper);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_log_base_rational() {
fn test<T: PrimitiveFloat>(s: &str, base: u64, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
let u = Rational::from_str(s).unwrap();
assert_eq!(
NiceFloat(primitive_float_log_base_rational(&u, base)),
NiceFloat(out)
);
}
test::<f32>("0", 10, f32::NEGATIVE_INFINITY);
test::<f32>("1", 10, 0.0);
test::<f32>("1000", 10, 3.0); test::<f32>("1/1000", 10, -3.0); test::<f32>("9", 3, 2.0); test::<f32>("1/9", 3, -2.0); test::<f32>("8", 2, 3.0); test::<f32>("50", 10, 1.6989699602127075); test::<f32>("1/3", 10, -0.4771212637424469); test::<f32>("-1", 10, f32::NAN);
test::<f32>("-22/7", 10, f32::NAN);
test::<f64>("0", 10, f64::NEGATIVE_INFINITY);
test::<f64>("1", 10, 0.0);
test::<f64>("1000", 10, 3.0); test::<f64>("1/1000", 10, -3.0); test::<f64>("9", 3, 2.0); test::<f64>("1/9", 3, -2.0); test::<f64>("8", 2, 3.0); test::<f64>("50", 10, 1.6989700043360187); test::<f64>("1/3", 10, -0.47712125471966244); test::<f64>("-1", 10, f64::NAN);
test::<f64>("-22/7", 10, f64::NAN);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_log_base_rational_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_unsigned_pair_gen_var_9::<u64>().test_properties(|(x, base)| {
let y = primitive_float_log_base_rational::<T>(&x, base);
if base.is_power_of_2() {
assert_eq!(
NiceFloat(y),
NiceFloat(primitive_float_log_base_power_of_2_rational::<T>(
&x,
i64::exact_from(base.trailing_zeros())
))
);
}
});
}
#[test]
fn primitive_float_log_base_rational_properties() {
apply_fn_to_primitive_floats!(primitive_float_log_base_rational_properties_helper);
}