use core::cmp::Ordering::{self, *};
use core::str::FromStr;
use malachite_base::num::arithmetic::traits::{PowerOf2, PowerOf2Assign};
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::rounding_modes::exhaustive::exhaustive_rounding_modes;
use malachite_base::test_util::generators::common::GenConfig;
use malachite_base::test_util::generators::{
primitive_float_gen, unsigned_gen_var_11, unsigned_rounding_mode_pair_gen_var_3,
};
use malachite_float::float::arithmetic::power_of_2_of_float::{
primitive_float_power_of_2, primitive_float_power_of_2_rational,
};
use malachite_float::test_util::common::{
parse_hex_string, rug_round_try_from_rounding_mode, to_hex_string,
};
use malachite_float::test_util::float::arithmetic::power_of_2_of_float::{
rug_power_of_2_of_float, rug_power_of_2_of_float_prec, rug_power_of_2_of_float_prec_round,
rug_power_of_2_of_float_round, rug_power_of_2_rational_prec,
rug_power_of_2_rational_prec_round,
};
use malachite_float::test_util::generators::{
float_gen, float_gen_var_12, float_rounding_mode_pair_gen_var_47,
float_unsigned_pair_gen_var_1, float_unsigned_pair_gen_var_4,
float_unsigned_rounding_mode_triple_gen_var_36,
rational_unsigned_rounding_mode_triple_gen_var_10,
};
use malachite_float::{ComparableFloat, ComparableFloatRef, Float};
use malachite_nz::platform::Limb;
use malachite_q::Rational;
use malachite_q::test_util::generators::{rational_gen, rational_unsigned_pair_gen_var_3};
use std::panic::catch_unwind;
#[test]
fn test_power_of_2_of_float_prec_round() {
let test = |s, s_hex, prec: u64, rm, out: &str, out_hex: &str, o_out: Ordering| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (p, o) = Float::power_of_2_of_float_prec_round(x.clone(), prec, rm);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, o_out);
let (p_alt, o_alt) = Float::power_of_2_of_float_prec_round_ref(&x, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&p_alt));
assert_eq!(o_alt, o_out);
let mut p_alt = x.clone();
let o_alt = p_alt.power_of_2_of_float_prec_round_assign(prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&p_alt));
assert_eq!(o_alt, o_out);
if let Ok(rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) =
rug_power_of_2_of_float_prec_round(&rug::Float::exact_from(&x), prec, rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
};
test("NaN", "NaN", 1, Floor, "NaN", "NaN", Equal);
test(
"Infinity", "Infinity", 1, Ceiling, "Infinity", "Infinity", Equal,
);
test("-Infinity", "-Infinity", 1, Nearest, "0.0", "0x0.0", Equal);
test("0.0", "0x0.0", 1, Floor, "1.0", "0x1.0#1", Equal);
test("-0.0", "-0x0.0", 1, Ceiling, "1.0", "0x1.0#1", Equal);
test("3.0", "0x3.0#2", 10, Nearest, "8.0000", "0x8.00#10", Equal);
test("3.0", "0x3.0#2", 10, Floor, "8.0000", "0x8.00#10", Equal);
test("3.0", "0x3.0#2", 10, Ceiling, "8.0000", "0x8.00#10", Equal);
test(
"-1.0",
"-0x1.0#1",
10,
Nearest,
"0.50000",
"0x0.800#10",
Equal,
);
test("10.0", "0xa.0#3", 4, Nearest, "1.02e3", "0x4.0E+2#4", Equal);
test(
"-5.0",
"-0x5.0#3",
20,
Nearest,
"0.031250000",
"0x0.080000#20",
Equal,
);
test("0.50", "0x0.8#1", 1, Floor, "1.0", "0x1.0#1", Less);
test("0.50", "0x0.8#1", 1, Ceiling, "2.0", "0x2.0#1", Greater);
test("0.50", "0x0.8#1", 1, Nearest, "1.0", "0x1.0#1", Less);
test(
"0.50",
"0x0.8#1",
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(
"-0.50",
"-0x0.8#1",
53,
Nearest,
"0.70710678118654757",
"0x0.b504f333f9de68#53",
Greater,
);
test(
"-0.50",
"-0x0.8#1",
10,
Floor,
"0.70703",
"0x0.b50#10",
Less,
);
test(
"-0.50",
"-0x0.8#1",
10,
Ceiling,
"0.70801",
"0x0.b54#10",
Greater,
);
test(
"0.25",
"0x0.4#1",
53,
Nearest,
"1.1892071150027210",
"0x1.306fe0a31b715#53",
Less,
);
test("1.5", "0x1.8#2", 10, Nearest, "2.8281", "0x2.d4#10", Less);
test("1.5", "0x1.8#2", 10, Floor, "2.8281", "0x2.d4#10", Less);
test(
"-1.5",
"-0x1.8#2",
20,
Nearest,
"0.35355330",
"0x0.5a8278#20",
Less,
);
test(
"1.1e9",
"0x4.0E+7#1",
20,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
"1.1e9",
"0x4.0E+7#1",
20,
Floor,
"2.0985767e323228496",
"0x7.ffff8E+268435455#20",
Less,
);
test("-2.1e9", "-0x8.0E+7#1", 20, Nearest, "0.0", "0x0.0", Less);
test(
"-2.1e9",
"-0x8.0E+7#1",
20,
Ceiling,
"2.3825649e-323228497",
"0x1.00000E-268435456#20",
Greater,
);
test("7.9e-31", "0x1.0E-25#1", 1, Nearest, "1.0", "0x1.0#1", Less);
test(
"7.9e-31",
"0x1.0E-25#1",
53,
Nearest,
"1.0000000000000000",
"0x1.0000000000000#53",
Less,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
1,
Nearest,
"2.4e-323228497",
"0x1.0E-268435456#1",
Greater,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
1,
Floor,
"0.0",
"0x0.0",
Less,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
1,
Down,
"0.0",
"0x0.0",
Less,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
1,
Ceiling,
"2.4e-323228497",
"0x1.0E-268435456#1",
Greater,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
1,
Up,
"2.4e-323228497",
"0x1.0E-268435456#1",
Greater,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
20,
Floor,
"0.0",
"0x0.0",
Less,
);
test(
"-1073741824.5000",
"-0x40000000.800#40",
20,
Nearest,
"2.3825649e-323228497",
"0x1.00000E-268435456#20",
Greater,
);
}
#[test]
fn power_of_2_of_float_prec_round_fail() {
assert_panic!(Float::power_of_2_of_float_prec_round(
Float::one_prec(1),
0,
Floor
));
assert_panic!(Float::power_of_2_of_float_prec_round_ref(
&Float::one_prec(1),
0,
Floor
));
assert_panic!({
let mut x = Float::one_prec(1);
x.power_of_2_of_float_prec_round_assign(0, Floor)
});
let half = parse_hex_string("0x0.8#1");
assert_panic!(Float::power_of_2_of_float_prec_round(
half.clone(),
1,
Exact
));
assert_panic!(Float::power_of_2_of_float_prec_round_ref(&half, 1, Exact));
assert_panic!({
let mut x = parse_hex_string("0x0.8#1");
x.power_of_2_of_float_prec_round_assign(1, Exact)
});
}
#[test]
fn power_of_2_of_float_round_fail() {
let half = parse_hex_string("0x0.8#1");
assert_panic!(Float::power_of_2_of_float_round(half.clone(), Exact));
assert_panic!(Float::power_of_2_of_float_round_ref(&half, Exact));
assert_panic!({
let mut x = parse_hex_string("0x0.8#1");
x.power_of_2_of_float_round_assign(Exact)
});
}
#[test]
fn power_of_2_of_float_prec_fail() {
assert_panic!(Float::power_of_2_of_float_prec(Float::NAN, 0));
assert_panic!(Float::power_of_2_of_float_prec_ref(&Float::NAN, 0));
assert_panic!({
let mut x = Float::NAN;
x.power_of_2_of_float_prec_assign(0)
});
}
#[allow(clippy::needless_pass_by_value)]
fn power_of_2_of_float_prec_round_properties_helper(x: Float, prec: u64, rm: RoundingMode) {
let (p, o) = Float::power_of_2_of_float_prec_round(x.clone(), prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::power_of_2_of_float_prec_round_ref(&x, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.power_of_2_of_float_prec_round_assign(prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) =
rug_power_of_2_of_float_prec_round(&rug::Float::exact_from(&x), prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
assert!(p.is_nan() || p.is_sign_positive());
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
if o == Equal {
for rm2 in exhaustive_rounding_modes() {
let (p2, o2) = Float::power_of_2_of_float_prec_round_ref(&x, prec, rm2);
assert_eq!(
ComparableFloat(p2.abs_negative_zero_ref()),
ComparableFloat(p.abs_negative_zero_ref())
);
assert_eq!(o2, Equal);
}
} else {
assert_panic!(Float::power_of_2_of_float_prec_round_ref(&x, prec, Exact));
}
}
#[test]
fn power_of_2_of_float_prec_round_properties() {
float_unsigned_rounding_mode_triple_gen_var_36().test_properties(|(x, prec, rm)| {
power_of_2_of_float_prec_round_properties_helper(x, prec, rm);
});
let mut config = GenConfig::new();
config.insert("mean_precision_n", 2048);
config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
float_unsigned_rounding_mode_triple_gen_var_36().test_properties_with_config(
&config,
|(x, prec, rm)| {
power_of_2_of_float_prec_round_properties_helper(x, prec, rm);
},
);
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
let (p, o) = Float::power_of_2_of_float_prec_round(Float::NAN, prec, rm);
assert!(p.is_nan());
assert_eq!(o, Equal);
assert_eq!(
Float::power_of_2_of_float_prec_round(Float::INFINITY, prec, rm),
(Float::INFINITY, Equal)
);
assert_eq!(
Float::power_of_2_of_float_prec_round(Float::NEGATIVE_INFINITY, prec, rm),
(Float::ZERO, Equal)
);
assert_eq!(
Float::power_of_2_of_float_prec_round(Float::ZERO, prec, rm),
(Float::one_prec(prec), Equal)
);
assert_eq!(
Float::power_of_2_of_float_prec_round(Float::NEGATIVE_ZERO, prec, rm),
(Float::one_prec(prec), Equal)
);
});
}
#[test]
fn power_of_2_of_float_round_properties() {
float_rounding_mode_pair_gen_var_47().test_properties(|(x, rm)| {
let (p, o) = Float::power_of_2_of_float_round(x.clone(), rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::power_of_2_of_float_round_ref(&x, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.power_of_2_of_float_round_assign(rm);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) =
Float::power_of_2_of_float_prec_round_ref(&x, x.significant_bits(), rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
assert!(p.is_nan() || p.is_sign_positive());
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_power_of_2_of_float_round(&rug::Float::exact_from(&x), rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
});
}
#[allow(clippy::needless_pass_by_value)]
fn power_of_2_of_float_prec_properties_helper(x: Float, prec: u64) {
let (p, o) = Float::power_of_2_of_float_prec(x.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::power_of_2_of_float_prec_ref(&x, prec);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.power_of_2_of_float_prec_assign(prec);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::power_of_2_of_float_prec_round_ref(&x, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
assert!(p.is_nan() || p.is_sign_positive());
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
let (rug_p, rug_o) = rug_power_of_2_of_float_prec(&rug::Float::exact_from(&x), prec);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
#[test]
fn power_of_2_of_float_prec_properties() {
float_unsigned_pair_gen_var_1().test_properties(|(x, prec)| {
power_of_2_of_float_prec_properties_helper(x, prec);
});
let mut config = GenConfig::new();
config.insert("mean_precision_n", 2048);
config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
float_unsigned_pair_gen_var_1().test_properties_with_config(&config, |(x, prec)| {
power_of_2_of_float_prec_properties_helper(x, prec);
});
float_unsigned_pair_gen_var_4().test_properties(|(x, prec)| {
power_of_2_of_float_prec_properties_helper(x, prec);
});
}
#[allow(clippy::needless_pass_by_value)]
fn power_of_2_of_float_properties_helper(x: Float) {
let p = Float::power_of_2(x.clone());
assert!(p.is_valid());
let p_alt = Float::power_of_2(&x);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.power_of_2_assign();
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let p_alt = Float::power_of_2_of_float_round_ref(&x, Nearest).0;
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert!(p.is_nan() || p.is_sign_positive());
let rug_p = Float::from(&rug_power_of_2_of_float(&rug::Float::exact_from(&x)));
assert_eq!(ComparableFloatRef(&rug_p), ComparableFloatRef(&p));
}
#[test]
fn power_of_2_of_float_properties() {
float_gen().test_properties(power_of_2_of_float_properties_helper);
float_gen_var_12().test_properties(power_of_2_of_float_properties_helper);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_power_of_2() {
fn test<T: PrimitiveFloat>(x: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_power_of_2(x)), NiceFloat(out));
}
test::<f32>(f32::NAN, f32::NAN);
test::<f32>(f32::INFINITY, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(0.0, 1.0);
test::<f32>(-0.0, 1.0);
test::<f32>(1.0, 2.0);
test::<f32>(-1.0, 0.5);
test::<f32>(0.5, core::f32::consts::SQRT_2);
test::<f32>(-0.5, core::f32::consts::FRAC_1_SQRT_2);
test::<f32>(2.0, 4.0);
test::<f32>(-2.0, 0.25);
test::<f32>(core::f32::consts::PI, 8.824979);
test::<f32>(-core::f32::consts::PI, 0.113314725);
test::<f32>(core::f32::consts::E, 6.5808854);
test::<f32>(-core::f32::consts::E, 0.15195523);
test::<f64>(f64::NAN, f64::NAN);
test::<f64>(f64::INFINITY, f64::INFINITY);
test::<f64>(f64::NEGATIVE_INFINITY, 0.0);
test::<f64>(0.0, 1.0);
test::<f64>(-0.0, 1.0);
test::<f64>(1.0, 2.0);
test::<f64>(-1.0, 0.5);
test::<f64>(0.5, core::f64::consts::SQRT_2);
test::<f64>(-0.5, core::f64::consts::FRAC_1_SQRT_2);
test::<f64>(2.0, 4.0);
test::<f64>(-2.0, 0.25);
test::<f64>(core::f64::consts::PI, 8.824977827076287);
test::<f64>(-core::f64::consts::PI, 0.11331473229676088);
test::<f64>(core::f64::consts::E, 6.5808859910179205);
test::<f64>(-core::f64::consts::E, 0.15195522325791297);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_power_of_2_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_gen::<T>().test_properties(|x| {
let p = primitive_float_power_of_2(x);
assert_eq!(p.is_nan(), x.is_nan());
assert!(p.is_nan() || p >= T::ZERO);
});
}
#[test]
fn primitive_float_power_of_2_properties() {
apply_fn_to_primitive_floats!(primitive_float_power_of_2_properties_helper);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_power_of_2_rational() {
fn test<T: PrimitiveFloat>(s: &str, 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_power_of_2_rational(&u)),
NiceFloat(out)
);
}
test::<f32>("0", 1.0);
test::<f32>("1", 2.0);
test::<f32>("1/2", core::f32::consts::SQRT_2);
test::<f32>("1/3", 1.2599211);
test::<f32>("22/7", 8.832716);
test::<f32>("1000000", f32::INFINITY);
test::<f32>("1/1000000", 1.0000007);
test::<f32>("-1", 0.5);
test::<f32>("-1/2", core::f32::consts::FRAC_1_SQRT_2);
test::<f32>("-1/3", 0.7937005);
test::<f32>("-22/7", 0.11321546);
test::<f32>("-1000000", 0.0);
test::<f64>("0", 1.0);
test::<f64>("1", 2.0);
test::<f64>("1/2", core::f64::consts::SQRT_2);
test::<f64>("1/3", 1.2599210498948732);
test::<f64>("22/7", 8.832716109390498);
test::<f64>("1000000", f64::INFINITY);
test::<f64>("1/1000000", 1.0000006931474208);
test::<f64>("-1", 0.5);
test::<f64>("-1/2", core::f64::consts::FRAC_1_SQRT_2);
test::<f64>("-1/3", 0.7937005259840998);
test::<f64>("-22/7", 0.11321545803298834);
test::<f64>("-1000000", 0.0);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_power_of_2_rational_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
Rational: ExactFrom<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_gen().test_properties(|x| {
let y = primitive_float_power_of_2_rational::<T>(&x);
assert!(y >= T::ZERO);
if x > 0u32 {
assert!(y >= T::ONE);
} else if x < 0u32 {
assert!(y <= T::ONE);
}
});
primitive_float_gen::<T>().test_properties(|x| {
if x.is_finite() {
assert_eq!(
NiceFloat(primitive_float_power_of_2_rational::<T>(
&Rational::exact_from(x)
)),
NiceFloat(primitive_float_power_of_2(x))
);
}
});
}
#[test]
fn primitive_float_power_of_2_rational_properties() {
apply_fn_to_primitive_floats!(primitive_float_power_of_2_rational_properties_helper);
}
#[test]
fn test_power_of_2_rational_prec() {
let test = |s, prec, out: &str, out_hex: &str, out_o| {
let x = Rational::from_str(s).unwrap();
let (f, o) = Float::power_of_2_rational_prec(x.clone(), prec);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
let (f, o) = Float::power_of_2_rational_prec_ref(&x, prec);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
};
test("0", 1, "1.0", "0x1.0#1", Equal);
test("0", 10, "1.0000", "0x1.000#10", Equal);
test("0", 53, "1.0000000000000000", "0x1.0000000000000#53", Equal);
test("1", 1, "2.0", "0x2.0#1", Equal);
test("1", 10, "2.0000", "0x2.00#10", Equal);
test("1", 53, "2.0000000000000000", "0x2.0000000000000#53", Equal);
test("-1", 1, "0.50", "0x0.8#1", Equal);
test("-1", 10, "0.50000", "0x0.800#10", Equal);
test(
"-1",
53,
"0.50000000000000000",
"0x0.80000000000000#53",
Equal,
);
test("1/2", 1, "1.0", "0x1.0#1", Less);
test("1/2", 10, "1.4141", "0x1.6a0#10", Less);
test(
"1/2",
53,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test("-1/2", 1, "0.50", "0x0.8#1", Less);
test("-1/2", 10, "0.70703", "0x0.b50#10", Less);
test(
"-1/2",
53,
"0.70710678118654757",
"0x0.b504f333f9de68#53",
Greater,
);
test("1/3", 1, "1.0", "0x1.0#1", Less);
test("1/3", 10, "1.2598", "0x1.428#10", Less);
test(
"1/3",
53,
"1.2599210498948732",
"0x1.428a2f98d728b#53",
Greater,
);
test("22/7", 1, "8.0", "0x8.0#1", Less);
test("22/7", 10, "8.8281", "0x8.d4#10", Less);
test(
"22/7",
53,
"8.8327161093904980",
"0x8.d52ce208af3e8#53",
Less,
);
test("-22/7", 1, "0.12", "0x0.2#1", Greater);
test("-22/7", 10, "0.11316", "0x0.1cf8#10", Less);
test(
"-22/7",
53,
"0.11321545803298834",
"0x0.1cfbb031a741a5#53",
Greater,
);
test("100", 1, "1.3e30", "0x1.0E+25#1", Equal);
test("100", 10, "1.2677e30", "0x1.000E+25#10", Equal);
test(
"100",
53,
"1.2676506002282294e30",
"0x1.0000000000000E+25#53",
Equal,
);
test("-100", 1, "7.9e-31", "0x1.0E-25#1", Equal);
test("-100", 10, "7.8886e-31", "0x1.000E-25#10", Equal);
test(
"-100",
53,
"7.8886090522101181e-31",
"0x1.0000000000000E-25#53",
Equal,
);
}
#[test]
#[should_panic]
fn power_of_2_rational_prec_fail() {
Float::power_of_2_rational_prec(Rational::from(1), 0);
}
#[test]
#[should_panic]
fn power_of_2_rational_prec_ref_fail() {
Float::power_of_2_rational_prec_ref(&Rational::from(1), 0);
}
#[test]
fn test_power_of_2_rational_prec_round() {
let test = |s, prec, rm, out: &str, out_hex: &str, out_o| {
let x = Rational::from_str(s).unwrap();
let (f, o) = Float::power_of_2_rational_prec_round(x.clone(), prec, rm);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
let (f, o) = Float::power_of_2_rational_prec_round_ref(&x, prec, rm);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
};
let test_big = |x: Rational, prec, rm, out: &str, out_hex: &str, out_o| {
let (f, o) = Float::power_of_2_rational_prec_round(x.clone(), prec, rm);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
let (f, o) = Float::power_of_2_rational_prec_round_ref(&x, prec, rm);
assert!(f.is_valid());
assert_eq!(f.to_string(), out);
assert_eq!(to_hex_string(&f), out_hex);
assert_eq!(o, out_o);
};
test("0", 1, Floor, "1.0", "0x1.0#1", Equal);
test("0", 1, Ceiling, "1.0", "0x1.0#1", Equal);
test("0", 1, Nearest, "1.0", "0x1.0#1", Equal);
test("0", 10, Floor, "1.0000", "0x1.000#10", Equal);
test("0", 10, Ceiling, "1.0000", "0x1.000#10", Equal);
test("0", 10, Nearest, "1.0000", "0x1.000#10", Equal);
test("1", 1, Floor, "2.0", "0x2.0#1", Equal);
test("1", 1, Ceiling, "2.0", "0x2.0#1", Equal);
test("1", 1, Nearest, "2.0", "0x2.0#1", Equal);
test("1", 10, Floor, "2.0000", "0x2.00#10", Equal);
test("1", 10, Ceiling, "2.0000", "0x2.00#10", Equal);
test("1", 10, Nearest, "2.0000", "0x2.00#10", Equal);
test("-1", 1, Floor, "0.50", "0x0.8#1", Equal);
test("-1", 1, Ceiling, "0.50", "0x0.8#1", Equal);
test("-1", 1, Nearest, "0.50", "0x0.8#1", Equal);
test("-1", 10, Floor, "0.50000", "0x0.800#10", Equal);
test("-1", 10, Ceiling, "0.50000", "0x0.800#10", Equal);
test("-1", 10, Nearest, "0.50000", "0x0.800#10", Equal);
test("1/2", 1, Floor, "1.0", "0x1.0#1", Less);
test("1/2", 1, Ceiling, "2.0", "0x2.0#1", Greater);
test("1/2", 1, Nearest, "1.0", "0x1.0#1", Less);
test("1/2", 10, Floor, "1.4141", "0x1.6a0#10", Less);
test("1/2", 10, Ceiling, "1.4160", "0x1.6a8#10", Greater);
test("1/2", 10, Nearest, "1.4141", "0x1.6a0#10", Less);
test("-1/2", 1, Floor, "0.50", "0x0.8#1", Less);
test("-1/2", 1, Ceiling, "1.0", "0x1.0#1", Greater);
test("-1/2", 1, Nearest, "0.50", "0x0.8#1", Less);
test("-1/2", 10, Floor, "0.70703", "0x0.b50#10", Less);
test("-1/2", 10, Ceiling, "0.70801", "0x0.b54#10", Greater);
test("-1/2", 10, Nearest, "0.70703", "0x0.b50#10", Less);
test("1/3", 1, Floor, "1.0", "0x1.0#1", Less);
test("1/3", 1, Ceiling, "2.0", "0x2.0#1", Greater);
test("1/3", 1, Nearest, "1.0", "0x1.0#1", Less);
test("1/3", 10, Floor, "1.2598", "0x1.428#10", Less);
test("1/3", 10, Ceiling, "1.2617", "0x1.430#10", Greater);
test("1/3", 10, Nearest, "1.2598", "0x1.428#10", Less);
test("22/7", 1, Floor, "8.0", "0x8.0#1", Less);
test("22/7", 1, Ceiling, "16.0", "0x1.0E+1#1", Greater);
test("22/7", 1, Nearest, "8.0", "0x8.0#1", Less);
test("22/7", 10, Floor, "8.8281", "0x8.d4#10", Less);
test("22/7", 10, Ceiling, "8.8438", "0x8.d8#10", Greater);
test("22/7", 10, Nearest, "8.8281", "0x8.d4#10", Less);
test("-22/7", 1, Floor, "0.062", "0x0.1#1", Less);
test("-22/7", 1, Ceiling, "0.12", "0x0.2#1", Greater);
test("-22/7", 1, Nearest, "0.12", "0x0.2#1", Greater);
test("-22/7", 10, Floor, "0.11316", "0x0.1cf8#10", Less);
test("-22/7", 10, Ceiling, "0.11328", "0x0.1d00#10", Greater);
test("-22/7", 10, Nearest, "0.11316", "0x0.1cf8#10", Less);
test("100", 1, Floor, "1.3e30", "0x1.0E+25#1", Equal);
test("100", 1, Ceiling, "1.3e30", "0x1.0E+25#1", Equal);
test("100", 1, Nearest, "1.3e30", "0x1.0E+25#1", Equal);
test("100", 10, Floor, "1.2677e30", "0x1.000E+25#10", Equal);
test("100", 10, Ceiling, "1.2677e30", "0x1.000E+25#10", Equal);
test("100", 10, Nearest, "1.2677e30", "0x1.000E+25#10", Equal);
test("-100", 1, Floor, "7.9e-31", "0x1.0E-25#1", Equal);
test("-100", 1, Ceiling, "7.9e-31", "0x1.0E-25#1", Equal);
test("-100", 1, Nearest, "7.9e-31", "0x1.0E-25#1", Equal);
test("-100", 10, Floor, "7.8886e-31", "0x1.000E-25#10", Equal);
test("-100", 10, Ceiling, "7.8886e-31", "0x1.000E-25#10", Equal);
test("-100", 10, Nearest, "7.8886e-31", "0x1.000E-25#10", Equal);
test("0", 10, Exact, "1.0000", "0x1.000#10", Equal);
test("1", 10, Exact, "2.0000", "0x2.00#10", Equal);
test("-1", 10, Exact, "0.50000", "0x0.800#10", Equal);
test("100", 10, Exact, "1.2677e30", "0x1.000E+25#10", Equal);
test("-100", 10, Exact, "7.8886e-31", "0x1.000E-25#10", Equal);
test("17/37", 3, Nearest, "1.5", "0x1.8#3", Greater);
test_big(
Rational::power_of_2(100i64),
20,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test_big(
Rational::power_of_2(100i64),
20,
Floor,
"2.0985767e323228496",
"0x7.ffff8E+268435455#20",
Less,
);
test_big(
-Rational::power_of_2(100i64),
20,
Nearest,
"0.0",
"0x0.0",
Less,
);
test_big(
-Rational::power_of_2(100i64),
20,
Ceiling,
"2.3825649e-323228497",
"0x1.00000E-268435456#20",
Greater,
);
test_big(
Rational::power_of_2(-100i64),
10,
Nearest,
"1.0000",
"0x1.000#10",
Less,
); test_big(
Rational::power_of_2(-100i64),
10,
Ceiling,
"1.0020",
"0x1.008#10",
Greater,
); test_big(
-Rational::power_of_2(-100i64),
10,
Nearest,
"1.0000",
"0x1.000#10",
Greater,
); test_big(
-Rational::power_of_2(-100i64),
10,
Floor,
"0.99902",
"0x0.ffc#10",
Less,
); let min1 = Rational::power_of_2(i64::from(Float::MIN_EXPONENT) - 1);
test_big(min1.clone(), 1, Nearest, "1.0", "0x1.0#1", Less);
test_big(-min1, 1, Nearest, "1.0", "0x1.0#1", Greater);
let big =
Rational::power_of_2(i64::from(Float::MAX_EXPONENT)) + Rational::from_unsigneds(1u32, 2u32);
test_big(big.clone(), 1, Nearest, "Infinity", "Infinity", Greater);
test_big(-big, 1, Nearest, "0.0", "0x0.0", Less);
}
#[test]
fn power_of_2_rational_near_one_compute_huge() {
let prec = u64::exact_from(Float::MAX_EXPONENT) + 1;
let one = Float::one_prec(prec);
let one_plus_ulp = one
.clone()
.add_prec_round(Float::power_of_2(1 - i64::exact_from(prec)), prec, Exact)
.0;
let x = Rational::from(3) * Rational::power_of_2(i64::from(Float::MIN_EXPONENT) - 2);
let (f, o) = Float::power_of_2_rational_prec_round_ref(&x, prec, Nearest);
assert!(f.is_valid());
assert_eq!(ComparableFloatRef(&f), ComparableFloatRef(&one_plus_ulp));
assert_eq!(o, Greater);
let (f, o) = Float::power_of_2_rational_prec_round_ref(&x, prec, Floor);
assert!(f.is_valid());
assert_eq!(ComparableFloatRef(&f), ComparableFloatRef(&one));
assert_eq!(o, Less);
}
#[test]
#[should_panic]
fn power_of_2_rational_prec_round_fail_1() {
Float::power_of_2_rational_prec_round(Rational::from(1), 0, Floor);
}
#[test]
#[should_panic]
fn power_of_2_rational_prec_round_fail_2() {
Float::power_of_2_rational_prec_round(Rational::from_unsigneds(1u32, 2u32), 10, Exact);
}
#[test]
#[should_panic]
fn power_of_2_rational_prec_round_ref_fail() {
Float::power_of_2_rational_prec_round_ref(&Rational::from_unsigneds(1u32, 2u32), 10, Exact);
}
#[allow(clippy::needless_pass_by_value)]
fn power_of_2_rational_prec_round_properties_helper(x: Rational, prec: u64, rm: RoundingMode) {
let (f, o) = Float::power_of_2_rational_prec_round(x.clone(), prec, rm);
assert!(f.is_valid());
let (f_alt, o_alt) = Float::power_of_2_rational_prec_round_ref(&x, prec, rm);
assert!(f_alt.is_valid());
assert_eq!(ComparableFloatRef(&f_alt), ComparableFloatRef(&f));
assert_eq!(o_alt, o);
assert!(f >= 0u32);
if let Ok(rrm) = rug_round_try_from_rounding_mode(rm) {
let (rug_f, rug_o) = rug_power_of_2_rational_prec_round(&x, prec, rrm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_f)),
ComparableFloatRef(&f)
);
assert_eq!(rug_o, o);
}
if f.is_normal() {
assert_eq!(f.get_prec(), Some(prec));
if x > 0u32 {
assert!(f >= 1u32);
} else if x < 0u32 {
assert!(f <= 1u32);
}
}
if o == Equal {
for rm in exhaustive_rounding_modes() {
let (s, oo) = Float::power_of_2_rational_prec_round_ref(&x, prec, rm);
assert_eq!(
ComparableFloat(s.abs_negative_zero_ref()),
ComparableFloat(f.abs_negative_zero_ref())
);
assert_eq!(oo, Equal);
}
} else {
assert_panic!(Float::power_of_2_rational_prec_round_ref(&x, prec, Exact));
}
}
#[test]
fn power_of_2_rational_prec_round_properties() {
rational_unsigned_rounding_mode_triple_gen_var_10().test_properties(|(x, prec, rm)| {
power_of_2_rational_prec_round_properties_helper(x, prec, rm);
});
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
let (f, o) = Float::power_of_2_rational_prec_round(Rational::ZERO, prec, rm);
assert_eq!(ComparableFloat(f), ComparableFloat(Float::one_prec(prec)));
assert_eq!(o, Equal);
});
}
#[allow(clippy::needless_pass_by_value)]
fn power_of_2_rational_prec_properties_helper(x: Rational, prec: u64) {
let (f, o) = Float::power_of_2_rational_prec(x.clone(), prec);
assert!(f.is_valid());
let (f_alt, o_alt) = Float::power_of_2_rational_prec_ref(&x, prec);
assert!(f_alt.is_valid());
assert_eq!(ComparableFloatRef(&f_alt), ComparableFloatRef(&f));
assert_eq!(o_alt, o);
let (f_alt, o_alt) = Float::power_of_2_rational_prec_round_ref(&x, prec, Nearest);
assert_eq!(ComparableFloatRef(&f_alt), ComparableFloatRef(&f));
assert_eq!(o_alt, o);
assert!(f >= 0u32);
let (rug_f, rug_o) = rug_power_of_2_rational_prec(&x, prec);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_f)),
ComparableFloatRef(&f)
);
assert_eq!(rug_o, o);
if f.is_normal() {
assert_eq!(f.get_prec(), Some(prec));
if x > 0u32 {
assert!(f >= 1u32);
} else if x < 0u32 {
assert!(f <= 1u32);
}
}
}
#[test]
fn power_of_2_rational_prec_properties() {
rational_unsigned_pair_gen_var_3().test_properties(|(x, prec)| {
power_of_2_rational_prec_properties_helper(x, prec);
});
unsigned_gen_var_11().test_properties(|prec| {
let (f, o) = Float::power_of_2_rational_prec(Rational::ZERO, prec);
assert_eq!(ComparableFloat(f), ComparableFloat(Float::one_prec(prec)));
assert_eq!(o, Equal);
});
}