use malachite_base::num::arithmetic::traits::{IsPowerOf2, PowerOf2};
use malachite_base::num::basic::traits::Infinity;
use malachite_base::num::comparison::traits::PartialOrdAbs;
use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom};
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_base::rounding_modes::exhaustive::exhaustive_rounding_modes;
use malachite_base::test_util::generators::{
signed_gen, signed_gen_var_5, signed_unsigned_pair_gen_var_19, signed_unsigned_pair_gen_var_20,
unsigned_gen, unsigned_gen_var_5,
};
use malachite_float::test_util::arithmetic::power_of_2::{
power_of_2_i64_naive, power_of_2_prec_naive, power_of_2_prec_round_naive, power_of_2_u64_naive,
};
use malachite_float::test_util::arithmetic::shl_round::rug_shl_prec_round_signed;
use malachite_float::test_util::common::{rug_round_try_from_rounding_mode, to_hex_string};
use malachite_float::test_util::generators::{
signed_unsigned_rounding_mode_triple_gen_var_5, signed_unsigned_rounding_mode_triple_gen_var_6,
};
use malachite_float::{ComparableFloat, ComparableFloatRef, Float};
use std::cmp::Ordering::{self, *};
use std::panic::catch_unwind;
#[test]
fn test_power_of_2_prec_round() {
let test = |i: i64, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, o_out| {
let (p, o) = Float::power_of_2_prec_round(i, prec, rm);
assert!(p.is_valid());
assert_eq!(o, o_out);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
let (p_alt, o_alt) = power_of_2_prec_round_naive(i, prec, rm);
assert_eq!(p_alt.to_string(), out);
assert_eq!(to_hex_string(&p_alt), out_hex);
assert_eq!(o_alt, o_out);
if let Ok(rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, o) = rug_shl_prec_round_signed(
&rug::Float::with_val(1, 1),
i32::exact_from(i),
prec,
rm,
);
let p = Float::exact_from(&rug_p);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, o_out);
}
};
test(0, 1, Floor, "1.0", "0x1.0#1", Equal);
test(0, 1, Ceiling, "1.0", "0x1.0#1", Equal);
test(0, 1, Down, "1.0", "0x1.0#1", Equal);
test(0, 1, Up, "1.0", "0x1.0#1", Equal);
test(0, 1, Nearest, "1.0", "0x1.0#1", Equal);
test(0, 1, Exact, "1.0", "0x1.0#1", Equal);
test(
0,
100,
Floor,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(
0,
100,
Ceiling,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(
0,
100,
Down,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(
0,
100,
Up,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(
0,
100,
Nearest,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(
0,
100,
Exact,
"1.0",
"0x1.0000000000000000000000000#100",
Equal,
);
test(1, 1, Floor, "2.0", "0x2.0#1", Equal);
test(1, 1, Ceiling, "2.0", "0x2.0#1", Equal);
test(1, 1, Down, "2.0", "0x2.0#1", Equal);
test(1, 1, Up, "2.0", "0x2.0#1", Equal);
test(1, 1, Nearest, "2.0", "0x2.0#1", Equal);
test(1, 1, Exact, "2.0", "0x2.0#1", Equal);
test(
1,
100,
Floor,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(
1,
100,
Ceiling,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(
1,
100,
Down,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(
1,
100,
Up,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(
1,
100,
Nearest,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(
1,
100,
Exact,
"2.0",
"0x2.0000000000000000000000000#100",
Equal,
);
test(100, 1, Floor, "1.0e30", "0x1.0E+25#1", Equal);
test(100, 1, Ceiling, "1.0e30", "0x1.0E+25#1", Equal);
test(100, 1, Down, "1.0e30", "0x1.0E+25#1", Equal);
test(100, 1, Up, "1.0e30", "0x1.0E+25#1", Equal);
test(100, 1, Nearest, "1.0e30", "0x1.0E+25#1", Equal);
test(100, 1, Exact, "1.0e30", "0x1.0E+25#1", Equal);
test(
100,
100,
Floor,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(
100,
100,
Ceiling,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(
100,
100,
Down,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(
100,
100,
Up,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(
100,
100,
Nearest,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(
100,
100,
Exact,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(1073741822, 1, Floor, "too_big", "0x4.0E+268435455#1", Equal);
test(
1073741822,
1,
Ceiling,
"too_big",
"0x4.0E+268435455#1",
Equal,
);
test(1073741822, 1, Down, "too_big", "0x4.0E+268435455#1", Equal);
test(1073741822, 1, Up, "too_big", "0x4.0E+268435455#1", Equal);
test(
1073741822,
1,
Nearest,
"too_big",
"0x4.0E+268435455#1",
Equal,
);
test(1073741822, 1, Exact, "too_big", "0x4.0E+268435455#1", Equal);
test(
1073741822,
100,
Floor,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(
1073741822,
100,
Ceiling,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(
1073741822,
100,
Down,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(
1073741822,
100,
Up,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(
1073741822,
100,
Nearest,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(
1073741822,
100,
Exact,
"too_big",
"0x4.0000000000000000000000000E+268435455#100",
Equal,
);
test(1073741823, 1, Floor, "too_big", "0x4.0E+268435455#1", Less);
test(1073741823, 1, Ceiling, "Infinity", "Infinity", Greater);
test(1073741823, 1, Down, "too_big", "0x4.0E+268435455#1", Less);
test(1073741823, 1, Up, "Infinity", "Infinity", Greater);
test(1073741823, 1, Nearest, "Infinity", "Infinity", Greater);
test(
1073741823,
100,
Floor,
"too_big",
"0x7.ffffffffffffffffffffffff8E+268435455#100",
Less,
);
test(1073741823, 100, Ceiling, "Infinity", "Infinity", Greater);
test(
1073741823,
100,
Down,
"too_big",
"0x7.ffffffffffffffffffffffff8E+268435455#100",
Less,
);
test(1073741823, 100, Up, "Infinity", "Infinity", Greater);
test(1073741823, 100, Nearest, "Infinity", "Infinity", Greater);
test(-1, 1, Floor, "0.5", "0x0.8#1", Equal);
test(-1, 1, Ceiling, "0.5", "0x0.8#1", Equal);
test(-1, 1, Down, "0.5", "0x0.8#1", Equal);
test(-1, 1, Up, "0.5", "0x0.8#1", Equal);
test(-1, 1, Nearest, "0.5", "0x0.8#1", Equal);
test(-1, 1, Exact, "0.5", "0x0.8#1", Equal);
test(
-1,
100,
Floor,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(
-1,
100,
Ceiling,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(
-1,
100,
Down,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(
-1,
100,
Up,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(
-1,
100,
Nearest,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(
-1,
100,
Exact,
"0.5",
"0x0.8000000000000000000000000#100",
Equal,
);
test(-100, 1, Floor, "8.0e-31", "0x1.0E-25#1", Equal);
test(-100, 1, Ceiling, "8.0e-31", "0x1.0E-25#1", Equal);
test(-100, 1, Down, "8.0e-31", "0x1.0E-25#1", Equal);
test(-100, 1, Up, "8.0e-31", "0x1.0E-25#1", Equal);
test(-100, 1, Nearest, "8.0e-31", "0x1.0E-25#1", Equal);
test(-100, 1, Exact, "8.0e-31", "0x1.0E-25#1", Equal);
test(
-1073741824,
1,
Floor,
"too_small",
"0x1.0E-268435456#1",
Equal,
);
test(
-1073741824,
1,
Ceiling,
"too_small",
"0x1.0E-268435456#1",
Equal,
);
test(
-1073741824,
1,
Down,
"too_small",
"0x1.0E-268435456#1",
Equal,
);
test(-1073741824, 1, Up, "too_small", "0x1.0E-268435456#1", Equal);
test(
-1073741824,
1,
Nearest,
"too_small",
"0x1.0E-268435456#1",
Equal,
);
test(
-1073741824,
1,
Exact,
"too_small",
"0x1.0E-268435456#1",
Equal,
);
test(
-1073741824,
100,
Floor,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(
-1073741824,
100,
Ceiling,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(
-1073741824,
100,
Down,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(
-1073741824,
100,
Up,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(
-1073741824,
100,
Nearest,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(
-1073741824,
100,
Exact,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Equal,
);
test(-1073741825, 1, Floor, "0.0", "0x0.0", Less);
test(
-1073741825,
1,
Ceiling,
"too_small",
"0x1.0E-268435456#1",
Greater,
);
test(-1073741825, 1, Down, "0.0", "0x0.0", Less);
test(
-1073741825,
1,
Up,
"too_small",
"0x1.0E-268435456#1",
Greater,
);
test(-1073741825, 1, Nearest, "0.0", "0x0.0", Less);
test(-1073741825, 100, Floor, "0.0", "0x0.0", Less);
test(
-1073741825,
100,
Ceiling,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Greater,
);
test(-1073741825, 100, Down, "0.0", "0x0.0", Less);
test(
-1073741825,
100,
Up,
"too_small",
"0x1.0000000000000000000000000E-268435456#100",
Greater,
);
test(-1073741825, 100, Nearest, "0.0", "0x0.0", Less);
}
#[test]
fn power_of_2_prec_round_fail() {
assert_panic!(Float::power_of_2_prec_round(0, 0, Floor));
assert_panic!(Float::power_of_2_prec_round(1073741823, 1, Exact));
assert_panic!(Float::power_of_2_prec_round(1073741823, 100, Exact));
assert_panic!(Float::power_of_2_prec_round(-1073741825, 1, Exact));
assert_panic!(Float::power_of_2_prec_round(-1073741825, 100, Exact));
}
fn power_of_2_prec_round_properties_helper(i: i64, prec: u64, rm: RoundingMode) {
let (p, o) = Float::power_of_2_prec_round(i, prec, rm);
assert!(p.is_valid());
assert!(p.is_finite() || p == Float::INFINITY || p.is_positive_zero());
assert!(p >= 0u32);
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
} else {
assert_eq!(o, if p > 0 { Greater } else { Less });
}
if i.lt_abs(&1_000_000_000) {
let (p_alt, o_alt) = power_of_2_prec_round_naive(i, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if rm == Exact {
assert_eq!(o, Equal);
} else {
let rm = rug_round_try_from_rounding_mode(rm).unwrap();
if i32::convertible_from(i) {
let (rug_p, rug_o) = rug_shl_prec_round_signed(
&rug::Float::with_val(1, 1),
i32::exact_from(i),
prec,
rm,
);
assert_eq!(
ComparableFloat(Float::exact_from(&rug_p)),
ComparableFloat(p)
);
assert_eq!(rug_o, o);
}
}
}
#[test]
fn power_of_2_prec_round_properties() {
signed_unsigned_rounding_mode_triple_gen_var_5().test_properties(|(i, prec, rm)| {
power_of_2_prec_round_properties_helper(i, prec, rm);
});
signed_unsigned_rounding_mode_triple_gen_var_6().test_properties(|(i, prec, rm)| {
power_of_2_prec_round_properties_helper(i, prec, rm);
});
}
#[test]
fn test_power_of_2_prec() {
let test = |i: i64, prec: u64, out: &str, out_hex: &str, o_out: Ordering| {
let (p, o) = Float::power_of_2_prec(i, prec);
assert!(p.is_valid());
assert_eq!(o, o_out);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
let (p_alt, o_alt) = power_of_2_prec_naive(i, prec);
assert_eq!(p_alt.to_string(), out);
assert_eq!(to_hex_string(&p_alt), out_hex);
assert_eq!(o_alt, o_out);
let rug_p = rug::Float::with_val(u32::exact_from(prec), 1) << i32::exact_from(i);
let p = Float::exact_from(&rug_p);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
};
test(0, 1, "1.0", "0x1.0#1", Equal);
test(0, 100, "1.0", "0x1.0000000000000000000000000#100", Equal);
test(1, 1, "2.0", "0x2.0#1", Equal);
test(1, 100, "2.0", "0x2.0000000000000000000000000#100", Equal);
test(100, 1, "1.0e30", "0x1.0E+25#1", Equal);
test(
100,
100,
"1267650600228229401496703205376.0",
"0x10000000000000000000000000.0#100",
Equal,
);
test(1073741822, 1, "too_big", "0x4.0E+268435455#1", Equal);
test(1073741823, 1, "Infinity", "Infinity", Greater);
test(-1, 1, "0.5", "0x0.8#1", Equal);
test(-1, 100, "0.5", "0x0.8000000000000000000000000#100", Equal);
test(-100, 1, "8.0e-31", "0x1.0E-25#1", Equal);
test(
-100,
100,
"7.88860905221011805411728565283e-31",
"0x1.0000000000000000000000000E-25#100",
Equal,
);
test(-1073741824, 1, "too_small", "0x1.0E-268435456#1", Equal);
test(-1073741825, 1, "0.0", "0x0.0", Less);
}
#[test]
#[should_panic]
fn power_of_2_prec_fail() {
Float::power_of_2_prec(0, 0);
}
fn power_of_2_prec_properties_helper(i: i64, prec: u64) {
let (p, o) = Float::power_of_2_prec(i, prec);
assert!(p.is_valid());
assert!(p.is_finite() || p == Float::INFINITY || p.is_positive_zero());
assert!(p >= 0u32);
assert_eq!(Float::power_of_2(i), p);
let (p_alt, o_alt) = Float::power_of_2_prec_round(i, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o, o_alt);
if p.is_normal() {
assert_eq!(o, Equal);
assert_eq!(p.get_prec(), Some(prec));
assert!(p.is_power_of_2());
} else {
assert_eq!(o, if p > 0 { Greater } else { Less });
}
if i.lt_abs(&1_000_000_000) {
let (p_alt, o_alt) = power_of_2_prec_naive(i, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if o == Equal {
for rm in exhaustive_rounding_modes() {
let (p_alt, o_alt) = Float::power_of_2_prec_round(i, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, Equal);
}
}
if let Ok(i) = i32::try_from(i) {
let rug_p = rug::Float::with_val(u32::exact_from(prec), 1) << i;
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
}
}
#[test]
fn power_of_2_prec_properties() {
signed_unsigned_pair_gen_var_19::<i64, u64>().test_properties(|(i, prec)| {
power_of_2_prec_properties_helper(i, prec);
});
signed_unsigned_pair_gen_var_20::<i64, u64>().test_properties(|(i, prec)| {
power_of_2_prec_properties_helper(i, prec);
});
}
#[test]
fn test_power_of_2() {
let test = |i: i64, out: &str, out_hex: &str| {
let p = Float::power_of_2(i);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
let p_alt = power_of_2_i64_naive(i);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let rug_p = rug::Float::with_val(1, 1) << i32::exact_from(i);
let p = Float::exact_from(&rug_p);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
};
test(0, "1.0", "0x1.0#1");
test(1, "2.0", "0x2.0#1");
test(2, "4.0", "0x4.0#1");
test(3, "8.0", "0x8.0#1");
test(1073741822, "too_big", "0x4.0E+268435455#1");
test(1073741823, "Infinity", "Infinity");
test(-1, "0.5", "0x0.8#1");
test(-2, "0.2", "0x0.4#1");
test(-3, "0.1", "0x0.2#1");
test(-100, "8.0e-31", "0x1.0E-25#1");
test(-1073741824, "too_small", "0x1.0E-268435456#1");
test(-1073741825, "0.0", "0x0.0");
let test = |u: u64, out: &str, out_hex: &str| {
let p = Float::power_of_2(u);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
let p_alt = power_of_2_u64_naive(u);
assert_eq!(p_alt.to_string(), out);
assert_eq!(to_hex_string(&p_alt), out_hex);
let rug_p = rug::Float::with_val(1, 1) << u32::exact_from(u);
let p = Float::exact_from(&rug_p);
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
};
test(0, "1.0", "0x1.0#1");
test(1, "2.0", "0x2.0#1");
test(2, "4.0", "0x4.0#1");
test(3, "8.0", "0x8.0#1");
test(100, "1.0e30", "0x1.0E+25#1");
test(1073741822, "too_big", "0x4.0E+268435455#1");
test(1073741823, "Infinity", "Infinity");
}
fn power_of_2_properties_signed_helper(i: i64) {
let p = Float::power_of_2(i);
assert!(p.is_valid());
assert!(p.is_finite() || p == Float::INFINITY || p.is_positive_zero());
assert!(p >= 0u32);
if p.is_normal() {
assert!(p.is_power_of_2());
assert_eq!(p.get_prec(), Some(1));
}
assert_eq!(
ComparableFloatRef(&Float::power_of_2_prec(i, 1).0),
ComparableFloatRef(&p)
);
if i >= 0 {
assert_eq!(
ComparableFloatRef(&Float::power_of_2(i.unsigned_abs())),
ComparableFloatRef(&p)
);
}
if i.lt_abs(&1_000_000_000) {
let p_alt = power_of_2_i64_naive(i);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
}
if let Ok(i) = u32::try_from(i) {
let rug_p = rug::Float::with_val(1, 1) << i;
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
}
}
fn power_of_2_properties_unsigned_helper(u: u64) {
let p = Float::power_of_2(u);
assert!(p.is_valid());
assert!(p.is_finite() || p == Float::INFINITY || p.is_positive_zero());
assert!(p >= 0u32);
if p.is_normal() {
assert!(p.is_power_of_2());
assert_eq!(p.get_prec(), Some(1));
}
if u < 1_000_000_000 {
let p_alt = power_of_2_u64_naive(u);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
}
if let Ok(u) = u32::try_from(u) {
let rug_p = rug::Float::with_val(1, 1) << u;
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
}
}
#[test]
fn power_of_2_properties() {
signed_gen_var_5().test_properties(|i| {
power_of_2_properties_signed_helper(i);
});
signed_gen().test_properties(|i| {
power_of_2_properties_signed_helper(i);
});
unsigned_gen_var_5().test_properties(|u| {
power_of_2_properties_unsigned_helper(u);
});
unsigned_gen().test_properties(|u| {
power_of_2_properties_unsigned_helper(u);
});
}