use malachite_base::num::arithmetic::traits::{
CeilingLogBase, CeilingLogBase2, CheckedLogBase, CheckedLogBase2, FloorLogBase, FloorLogBase2,
Pow,
};
use malachite_base::num::basic::traits::{NegativeOne, One, Two, Zero};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::num::float::NiceFloat;
use malachite_base::test_util::generators::unsigned_gen_var_31;
use malachite_nz::test_util::generators::natural_pair_gen_var_3;
use malachite_q::Rational;
use malachite_q::test_util::generators::{
rational_gen_var_2, rational_gen_var_8, rational_pair_gen_var_7,
rational_unsigned_pair_gen_var_9,
};
use std::str::FromStr;
#[test]
fn test_approx_log() {
let test = |s, out| {
assert_eq!(
NiceFloat(Rational::from_str(s).unwrap().approx_log()),
NiceFloat(out)
);
};
test("1", 0.0);
test("2", std::f64::consts::LN_2);
test("3", 1.0986122886681096);
test("10", 2.3025850929940455);
test("100", 4.605170185988091);
test("1000", 6.907755278982137);
test(
"1000000000000000000000000000000000000000000000000000000000000",
138.15510557964274,
);
test("1/2", -std::f64::consts::LN_2);
test("1/3", -1.0986122886681096);
test("22/7", 1.1451323043030026);
test("936851431250/1397", 20.323708189458696);
}
#[test]
#[should_panic]
fn approx_log_fail() {
Rational::ZERO.approx_log();
}
#[test]
fn test_floor_log_base() {
let test = |n, base, out| {
assert_eq!(
Rational::from_str(n)
.unwrap()
.floor_log_base(&Rational::from_str(base).unwrap()),
out
);
};
test("1", "2", 0);
test("1", "5", 0);
test("2", "2", 1);
test("2", "3", 0);
test("3", "2", 1);
test("3", "3", 1);
test("3", "4", 0);
test("100", "2", 6);
test("100", "3", 4);
test("100", "4", 3);
test("100", "5", 2);
test("100", "10", 2);
test("100", "11", 1);
test(
"999999999999999999999999999999999999999999999999999999999999",
"10",
59,
);
test(
"1000000000000000000000000000000000000000000000000000000000000",
"10",
60,
);
test(
"1000000000000000000000000000000000000000000000000000000000001",
"10",
60,
);
test("1/2", "2", -1);
test("1/3", "2", -2);
test("1/2", "3", -1);
test("1/3", "3", -1);
test("22/7", "3", 1);
test("1/64", "4", -3);
test("22/7", "10", 0);
test("936851431250/1397", "10", 8);
test("1/2", "1/2", 1);
test("1/3", "1/2", 1);
test("1/2", "1/3", 0);
test("1/3", "1/3", 1);
test("22/7", "1/3", -2);
test("1/64", "1/4", 3);
test("22/7", "1/10", -1);
test("936851431250/1397", "1/10", -9);
test("936851431250/1397", "22/7", 17);
test("100", "101/100", 462);
test("100", "100/101", -463);
test("5153632/16807", "22/7", 5);
}
#[test]
#[should_panic]
fn floor_log_base_fail_1() {
Rational::ZERO.floor_log_base(&Rational::TWO);
}
#[test]
#[should_panic]
fn floor_log_base_fail_2() {
Rational::ONE.floor_log_base(&Rational::ZERO);
}
#[test]
#[should_panic]
fn floor_log_base_fail_3() {
Rational::ONE.floor_log_base(&Rational::ONE);
}
#[test]
#[should_panic]
fn floor_log_base_fail_4() {
Rational::NEGATIVE_ONE.floor_log_base(&Rational::TWO);
}
#[test]
fn test_ceiling_log_base() {
let test = |n, base, out| {
assert_eq!(
Rational::from_str(n)
.unwrap()
.ceiling_log_base(&Rational::from_str(base).unwrap()),
out
);
};
test("1", "2", 0);
test("1", "5", 0);
test("2", "2", 1);
test("2", "3", 1);
test("3", "2", 2);
test("3", "3", 1);
test("3", "4", 1);
test("100", "2", 7);
test("100", "3", 5);
test("100", "4", 4);
test("100", "5", 3);
test("100", "10", 2);
test("100", "11", 2);
test(
"999999999999999999999999999999999999999999999999999999999999",
"10",
60,
);
test(
"1000000000000000000000000000000000000000000000000000000000000",
"10",
60,
);
test(
"1000000000000000000000000000000000000000000000000000000000001",
"10",
61,
);
test("1/2", "2", -1);
test("1/3", "2", -1);
test("1/2", "3", 0);
test("1/3", "3", -1);
test("22/7", "3", 2);
test("1/64", "4", -3);
test("22/7", "10", 1);
test("936851431250/1397", "10", 9);
test("1/2", "1/2", 1);
test("1/3", "1/2", 2);
test("1/2", "1/3", 1);
test("1/3", "1/3", 1);
test("22/7", "1/3", -1);
test("1/64", "1/4", 3);
test("22/7", "1/10", 0);
test("936851431250/1397", "1/10", -8);
test("936851431250/1397", "22/7", 18);
test("100", "101/100", 463);
test("100", "100/101", -462);
test("5153632/16807", "22/7", 5);
}
#[test]
#[should_panic]
fn ceiling_log_base_fail_1() {
Rational::ZERO.ceiling_log_base(&Rational::TWO);
}
#[test]
#[should_panic]
fn ceiling_log_base_fail_2() {
Rational::ONE.ceiling_log_base(&Rational::ZERO);
}
#[test]
#[should_panic]
fn ceiling_log_base_fail_3() {
Rational::ONE.ceiling_log_base(&Rational::ONE);
}
#[test]
#[should_panic]
fn ceiling_log_base_fail_4() {
Rational::NEGATIVE_ONE.ceiling_log_base(&Rational::TWO);
}
#[test]
fn test_checked_log_base() {
let test = |n, base, out| {
assert_eq!(
Rational::from_str(n)
.unwrap()
.checked_log_base(&Rational::from_str(base).unwrap()),
out
);
};
test("1", "2", Some(0));
test("1", "5", Some(0));
test("2", "2", Some(1));
test("2", "3", None);
test("3", "2", None);
test("3", "3", Some(1));
test("3", "4", None);
test("100", "2", None);
test("100", "3", None);
test("100", "4", None);
test("100", "5", None);
test("100", "10", Some(2));
test("100", "11", None);
test(
"999999999999999999999999999999999999999999999999999999999999",
"10",
None,
);
test(
"1000000000000000000000000000000000000000000000000000000000000",
"10",
Some(60),
);
test(
"1000000000000000000000000000000000000000000000000000000000001",
"10",
None,
);
test("1/2", "2", Some(-1));
test("1/3", "2", None);
test("1/2", "3", None);
test("1/3", "3", Some(-1));
test("22/7", "3", None);
test("1/64", "4", Some(-3));
test("22/7", "10", None);
test("936851431250/1397", "10", None);
test("1/2", "1/2", Some(1));
test("1/3", "1/2", None);
test("1/2", "1/3", None);
test("1/3", "1/3", Some(1));
test("22/7", "1/3", None);
test("1/64", "1/4", Some(3));
test("22/7", "1/10", None);
test("936851431250/1397", "1/10", None);
test("936851431250/1397", "22/7", None);
test("100", "101/100", None);
test("100", "100/101", None);
test("5153632/16807", "22/7", Some(5));
}
#[test]
#[should_panic]
fn checked_log_base_fail_1() {
Rational::ZERO.checked_log_base(&Rational::TWO);
}
#[test]
#[should_panic]
fn checked_log_base_fail_2() {
Rational::ONE.checked_log_base(&Rational::ZERO);
}
#[test]
#[should_panic]
fn checked_log_base_fail_3() {
Rational::ONE.checked_log_base(&Rational::ONE);
}
#[test]
#[should_panic]
fn checked_log_base_fail_4() {
Rational::NEGATIVE_ONE.checked_log_base(&Rational::TWO);
}
#[test]
fn test_floor_log_base_u64() {
let test = |n, base: u64, out| {
let x = Rational::from_str(n).unwrap();
assert_eq!((&x).floor_log_base(base), out);
assert_eq!((&x).floor_log_base(&Rational::from(base)), out);
};
test("1", 2, 0);
test("1", 5, 0);
test("2", 2, 1);
test("2", 3, 0);
test("3", 3, 1);
test("3", 4, 0);
test("100", 2, 6);
test("100", 3, 4);
test("100", 4, 3);
test("100", 10, 2);
test("100", 11, 1);
test(
"1000000000000000000000000000000000000000000000000000000000000",
10,
60,
);
test("1/2", 2, -1);
test("1/3", 2, -2);
test("1/64", 4, -3);
test("22/7", 10, 0);
test("936851431250/1397", 10, 8);
test("1/1000000", 10, -6);
test("5153632/16807", 5, 3);
}
#[test]
#[should_panic]
fn floor_log_base_u64_fail_1() {
(&Rational::ZERO).floor_log_base(2u64);
}
#[test]
#[should_panic]
fn floor_log_base_u64_fail_2() {
(&Rational::ONE).floor_log_base(1u64);
}
#[test]
#[should_panic]
fn floor_log_base_u64_fail_3() {
(&Rational::NEGATIVE_ONE).floor_log_base(2u64);
}
#[test]
fn test_ceiling_log_base_u64() {
let test = |n, base: u64, out| {
let x = Rational::from_str(n).unwrap();
assert_eq!((&x).ceiling_log_base(base), out);
assert_eq!((&x).ceiling_log_base(&Rational::from(base)), out);
};
test("1", 2, 0);
test("2", 2, 1);
test("3", 3, 1);
test("3", 4, 1);
test("100", 3, 5);
test("100", 4, 4);
test("100", 10, 2);
test("100", 11, 2);
test("1/2", 2, -1);
test("1/3", 2, -1);
test("1/64", 4, -3);
test("22/7", 10, 1);
test("936851431250/1397", 10, 9);
test("1/1000000", 10, -6);
}
#[test]
#[should_panic]
fn ceiling_log_base_u64_fail_1() {
(&Rational::ZERO).ceiling_log_base(2u64);
}
#[test]
#[should_panic]
fn ceiling_log_base_u64_fail_2() {
(&Rational::ONE).ceiling_log_base(1u64);
}
#[test]
fn test_checked_log_base_u64() {
let test = |n, base: u64, out| {
let x = Rational::from_str(n).unwrap();
assert_eq!((&x).checked_log_base(base), out);
assert_eq!((&x).checked_log_base(&Rational::from(base)), out);
};
test("1", 2, Some(0));
test("80", 3, None);
test("81", 3, Some(4));
test("82", 3, None);
test("1000000", 10, Some(6));
test("1/1000000", 10, Some(-6));
test("4294967296", 10, None);
test("4294967296", 2, Some(32));
test("1/9", 3, Some(-2));
test("22/7", 10, None);
test("8/27", 3, None);
}
#[test]
#[should_panic]
fn checked_log_base_u64_fail_1() {
(&Rational::ZERO).checked_log_base(2u64);
}
#[test]
#[should_panic]
fn checked_log_base_u64_fail_2() {
(&Rational::ONE).checked_log_base(1u64);
}
#[test]
fn approx_log_properties() {
rational_gen_var_2().test_properties(|n| {
let log = n.approx_log();
assert!(log.is_finite());
assert!(!log.is_nan());
});
}
#[test]
fn floor_log_base_properties() {
rational_pair_gen_var_7().test_properties(|(n, base)| {
let floor_log = n.floor_log_base(&base);
let power = (&base).pow(floor_log);
if base >= 1u32 {
assert!(power <= n);
assert!(&power * &base > n);
} else {
assert!(power >= n);
assert!(&power * &base < n);
}
let ceiling_log = n.ceiling_log_base(&base);
if power == n {
assert_eq!(ceiling_log, floor_log);
} else {
assert_eq!(ceiling_log, floor_log + 1);
}
});
rational_gen_var_2().test_properties(|n| {
assert_eq!(n.floor_log_base(&Rational::TWO), n.floor_log_base_2());
});
rational_gen_var_8().test_properties(|base| {
assert_eq!(Rational::ONE.floor_log_base(&base), 0);
});
natural_pair_gen_var_3().test_properties(|(n, base)| {
assert_eq!(
n.floor_log_base(&base),
u64::exact_from(Rational::from(n).floor_log_base(&Rational::from(base)))
);
});
}
#[test]
fn ceiling_log_base_properties() {
rational_pair_gen_var_7().test_properties(|(n, base)| {
let ceiling_log = n.ceiling_log_base(&base);
let power = (&base).pow(ceiling_log);
if base >= 1u32 {
assert!(power >= n);
assert!(&power / &base < n);
} else {
assert!(power <= n);
assert!(&power / &base > n);
}
let floor_log = n.floor_log_base(&base);
if power == n {
assert_eq!(floor_log, ceiling_log);
} else {
assert_eq!(floor_log, ceiling_log - 1);
}
});
rational_gen_var_2().test_properties(|n| {
assert_eq!(n.ceiling_log_base(&Rational::TWO), n.ceiling_log_base_2());
});
rational_gen_var_8().test_properties(|base| {
assert_eq!(Rational::ONE.ceiling_log_base(&base), 0);
});
natural_pair_gen_var_3().test_properties(|(n, base)| {
assert_eq!(
n.ceiling_log_base(&base),
u64::exact_from(Rational::from(n).ceiling_log_base(&Rational::from(base)))
);
});
}
#[test]
fn checked_log_base_properties() {
rational_pair_gen_var_7().test_properties(|(n, base)| {
let checked_log = n.checked_log_base(&base);
if let Some(log) = checked_log {
assert_eq!((&base).pow(log), n);
assert_eq!(n.floor_log_base(&base), log);
assert_eq!(n.ceiling_log_base(&base), log);
}
});
rational_gen_var_2().test_properties(|n| {
assert_eq!(n.checked_log_base(&Rational::TWO), n.checked_log_base_2());
});
rational_gen_var_8().test_properties(|base| {
assert_eq!(Rational::ONE.checked_log_base(&base), Some(0));
});
natural_pair_gen_var_3().test_properties(|(n, base)| {
assert_eq!(
n.checked_log_base(&base),
Rational::from(n)
.checked_log_base(&Rational::from(base))
.map(u64::exact_from)
);
});
}
#[test]
fn floor_log_base_u64_properties() {
rational_unsigned_pair_gen_var_9::<u64>().test_properties(|(n, base)| {
let floor_log = (&n).floor_log_base(base);
assert_eq!(floor_log, (&n).floor_log_base(&Rational::from(base)));
let base_q = Rational::from(base);
let power = (&base_q).pow(floor_log);
assert!(power <= n);
assert!(&power * &base_q > n);
assert_eq!((&n).ceiling_log_base(base), {
if power == n { floor_log } else { floor_log + 1 }
});
});
rational_gen_var_2().test_properties(|n| {
assert_eq!((&n).floor_log_base(2u64), n.floor_log_base_2());
});
unsigned_gen_var_31::<u64>().test_properties(|base| {
assert_eq!((&Rational::ONE).floor_log_base(base), 0);
});
}
#[test]
fn ceiling_log_base_u64_properties() {
rational_unsigned_pair_gen_var_9::<u64>().test_properties(|(n, base)| {
let ceiling_log = (&n).ceiling_log_base(base);
assert_eq!(ceiling_log, (&n).ceiling_log_base(&Rational::from(base)));
let base_q = Rational::from(base);
let power = (&base_q).pow(ceiling_log);
assert!(power >= n);
assert!(&power / &base_q < n);
assert_eq!((&n).floor_log_base(base), {
if power == n {
ceiling_log
} else {
ceiling_log - 1
}
});
});
rational_gen_var_2().test_properties(|n| {
assert_eq!((&n).ceiling_log_base(2u64), n.ceiling_log_base_2());
});
unsigned_gen_var_31::<u64>().test_properties(|base| {
assert_eq!((&Rational::ONE).ceiling_log_base(base), 0);
});
}
#[test]
fn checked_log_base_u64_properties() {
rational_unsigned_pair_gen_var_9::<u64>().test_properties(|(n, base)| {
let checked_log = (&n).checked_log_base(base);
assert_eq!(checked_log, (&n).checked_log_base(&Rational::from(base)));
if let Some(log) = checked_log {
assert_eq!(Rational::from(base).pow(log), n);
assert_eq!((&n).floor_log_base(base), log);
assert_eq!((&n).ceiling_log_base(base), log);
}
});
rational_gen_var_2().test_properties(|n| {
assert_eq!((&n).checked_log_base(2u64), n.checked_log_base_2());
});
unsigned_gen_var_31::<u64>().test_properties(|base| {
assert_eq!((&Rational::ONE).checked_log_base(base), Some(0));
});
}