use malachite_base::apply_fn_to_primitive_floats;
use malachite_base::assert_panic;
use malachite_base::num::arithmetic::traits::{CheckedRoot, IsPowerOf2, Pow, PowAssign, PowerOf2};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::traits::{
Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, Zero,
};
use malachite_base::num::conversion::traits::{ExactFrom, IsInteger, 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::{
primitive_float_pair_gen, primitive_float_unsigned_pair_gen_var_1,
primitive_float_unsigned_pair_gen_var_4,
};
use malachite_float::float::arithmetic::pow::{
primitive_float_pow, primitive_float_pow_integer, primitive_float_pow_rational,
primitive_float_pow_u, primitive_float_rational_pow, primitive_float_unsigned_pow,
};
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::pow::{
rug_pow, rug_pow_integer, rug_pow_integer_prec, rug_pow_integer_prec_round,
rug_pow_integer_round, rug_pow_prec, rug_pow_prec_round, rug_pow_round, rug_pow_s,
rug_pow_s_prec, rug_pow_s_prec_round, rug_pow_s_round, rug_pow_u, rug_pow_u_prec,
rug_pow_u_prec_round, rug_pow_u_round, rug_unsigned_pow_rational_prec_round,
};
use malachite_float::test_util::generators::{
float_float_unsigned_rounding_mode_quadruple_gen_var_9,
float_float_unsigned_rounding_mode_quadruple_gen_var_10, float_float_unsigned_triple_gen_var_1,
float_integer_pair_gen, float_integer_unsigned_rounding_mode_quadruple_gen_var_1,
float_integer_unsigned_rounding_mode_quadruple_gen_var_2,
float_integer_unsigned_triple_gen_var_1, float_pair_gen, float_pair_gen_var_10,
float_rational_pair_gen_var_1, float_rational_unsigned_rounding_mode_quadruple_gen_var_1,
float_rational_unsigned_rounding_mode_quadruple_gen_var_15,
float_rational_unsigned_rounding_mode_quadruple_gen_var_16,
float_rational_unsigned_triple_gen_var_1, float_signed_pair_gen,
float_signed_unsigned_rounding_mode_quadruple_gen_var_11,
float_signed_unsigned_rounding_mode_quadruple_gen_var_12,
float_signed_unsigned_triple_gen_var_1, float_unsigned_pair_gen,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_9,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_10,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_11,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_12,
float_unsigned_unsigned_triple_gen_var_1,
rational_rational_unsigned_rounding_mode_quadruple_gen_var_3,
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_2,
unsigned_unsigned_unsigned_rounding_mode_quadruple_gen_var_1,
};
use malachite_float::{ComparableFloat, ComparableFloatRef, Float};
use malachite_nz::integer::Integer;
use malachite_nz::test_util::generators::integer_primitive_float_pair_gen;
use malachite_q::Rational;
use malachite_q::test_util::generators::rational_primitive_float_pair_gen;
use std::cmp::Ordering::{self, *};
use std::panic::catch_unwind;
use std::str::FromStr;
#[test]
fn test_pow_special_values() {
let test = |x: Float, y: Float, out: Float, o_out: Ordering| {
let (p, o) = x.pow_prec_round_ref_ref(&y, 10, Nearest);
assert_eq!(ComparableFloat(p), ComparableFloat(out));
assert_eq!(o, o_out);
};
let one = || Float::one_prec(10);
test(Float::NAN, Float::ZERO, one(), Equal);
test(Float::INFINITY, Float::ZERO, one(), Equal);
test(Float::NEGATIVE_ZERO, Float::ZERO, one(), Equal);
test(Float::from(3.0), Float::ZERO, one(), Equal);
test(Float::ONE, Float::NAN, one(), Equal);
test(Float::ONE, Float::INFINITY, one(), Equal);
test(Float::NAN, Float::ONE, Float::NAN, Equal);
test(Float::from(2.0), Float::NAN, Float::NAN, Equal);
test(-Float::ONE, Float::INFINITY, one(), Equal);
test(-Float::ONE, Float::NEGATIVE_INFINITY, one(), Equal);
test(Float::from(2.0), Float::INFINITY, Float::INFINITY, Equal);
test(
Float::from(2.0),
Float::NEGATIVE_INFINITY,
Float::ZERO,
Equal,
);
test(Float::from(0.5), Float::INFINITY, Float::ZERO, Equal);
test(
Float::from(0.5),
Float::NEGATIVE_INFINITY,
Float::INFINITY,
Equal,
);
test(Float::INFINITY, Float::from(2.0), Float::INFINITY, Equal);
test(Float::INFINITY, Float::from(-2.0), Float::ZERO, Equal);
test(
Float::NEGATIVE_INFINITY,
Float::from(3.0),
Float::NEGATIVE_INFINITY,
Equal,
);
test(
Float::NEGATIVE_INFINITY,
Float::from(2.0),
Float::INFINITY,
Equal,
);
test(
Float::NEGATIVE_INFINITY,
Float::from(-3.0),
Float::NEGATIVE_ZERO,
Equal,
);
test(
Float::NEGATIVE_INFINITY,
Float::from(-2.0),
Float::ZERO,
Equal,
);
test(Float::ZERO, Float::from(3.0), Float::ZERO, Equal);
test(
Float::NEGATIVE_ZERO,
Float::from(3.0),
Float::NEGATIVE_ZERO,
Equal,
);
test(Float::NEGATIVE_ZERO, Float::from(2.0), Float::ZERO, Equal);
test(Float::ZERO, Float::from(-3.0), Float::INFINITY, Equal);
test(
Float::NEGATIVE_ZERO,
Float::from(-3.0),
Float::NEGATIVE_INFINITY,
Equal,
);
test(
Float::NEGATIVE_ZERO,
Float::from(-2.0),
Float::INFINITY,
Equal,
);
test(Float::from(-2.0), Float::from(0.5), Float::NAN, Equal);
}
#[test]
fn test_pow() {
let test = |s, s_hex, t, t_hex, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let y = parse_hex_string(t_hex);
assert_eq!(y.to_string(), t);
let (p, o) = x.pow_prec_round(y, 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);
};
test(
"2.0",
"0x2.0#1",
"0.50",
"0x0.8#1",
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(
"3.0",
"0x3.0#2",
"100.0",
"0x64.0#5",
53,
Nearest,
"5.1537752073201132e47",
"0x5.a4653ca673768E+39#53",
Less,
);
test(
"2.0",
"0x2.0#1",
"10.0",
"0xa.0#3",
53,
Nearest,
"1024.0000000000000",
"0x400.00000000000#53",
Equal,
);
test(
"0.50",
"0x0.8#1",
"2.0",
"0x2.0#1",
53,
Nearest,
"0.25000000000000000",
"0x0.40000000000000#53",
Equal,
);
test(
"10.0",
"0xa.0#3",
"-1.0",
"-0x1.0#1",
53,
Nearest,
"0.10000000000000001",
"0x0.1999999999999a#53",
Greater,
);
test(
"2.0",
"0x2.0#1",
"0.50",
"0x0.8#1",
53,
Floor,
"1.4142135623730949",
"0x1.6a09e667f3bcc#53",
Less,
);
test(
"1.5",
"0x1.8#2",
"1.5",
"0x1.8#2",
53,
Nearest,
"1.8371173070873836",
"0x1.d64d51e0db1c6#53",
Greater,
);
test(
"-2.0",
"-0x2.0#1",
"3.0",
"0x3.0#2",
53,
Nearest,
"-8.0000000000000000",
"-0x8.0000000000000#53",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
"-3.0",
"-0x3.0#2",
53,
Nearest,
"-0.12500000000000000",
"-0x0.20000000000000#53",
Equal,
);
}
#[test]
fn test_pow_integer_underflow_boundary() {
let emin = i64::from(Float::MIN_EXPONENT);
let x = Float::from(0.75f64);
let log2_x = 0.75f64.log2();
#[allow(clippy::cast_possible_truncation)]
let z_mid = (((emin as f64) - 1.5) / log2_x) as i64;
for dz in [-8i64, -2, -1, 0, 1, 2, 8] {
let z = z_mid + dz;
let y = Float::exact_from(&malachite_nz::integer::Integer::from(z));
let (p, o) = x.pow_prec_round_ref_ref(&y, 5, Nearest);
let (rug_p, rug_o) = rug_pow_prec_round(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
5,
rug::float::Round::Nearest,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
#[test]
fn test_pow_exact_bottom_binade() {
let j: i64 = -214748367;
let (x, o) = Float::from_unsigned_prec(25u32, 5);
assert_eq!(o, Equal);
let x = x << (2 * j);
let y = Float::from(2.5f64);
for prec in [12u64, 13, 20, 53] {
let (p, o) = x.pow_prec_round_ref_ref(&y, prec, Nearest);
assert_eq!(o, Equal);
assert_eq!(
i64::from(p.get_exponent().unwrap()),
i64::from(Float::MIN_EXPONENT)
);
let (rug_p, rug_o) = rug_pow_prec_round(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
prec,
rug::float::Round::Nearest,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
#[test]
fn test_pow_early_underflow_bound_equality() {
let x = Float::from(4.0f64);
let y = -(Float::exact_from(&malachite_nz::natural::Natural::from(1u32)) << 29u32);
for rm in [Floor, Ceiling, Down, Up, Nearest, Exact] {
let (p, o) = x.pow_prec_round_ref_ref(&y, 10, rm);
assert_eq!(o, Equal);
assert_eq!(
i64::from(p.get_exponent().unwrap()),
i64::from(Float::MIN_EXPONENT)
);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_pow_prec_round(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
10,
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
}
#[test]
fn test_pow_coverage() {
let test = |s, s_hex, t, t_hex, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let y = parse_hex_string(t_hex);
assert_eq!(y.to_string(), t);
let (p, o) = x.pow_prec_round(y, 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);
};
test(
"1.5",
"0x1.8#2",
"6.2e-61",
"0x1.0E-50#1",
10,
Nearest,
"1.0000",
"0x1.000#10",
Less,
);
test(
"1.5",
"0x1.8#2",
"6.2e-61",
"0x1.0E-50#1",
10,
Up,
"1.0020",
"0x1.008#10",
Greater,
);
test(
"1.5",
"0x1.8#2",
"-6.2e-61",
"-0x1.0E-50#1",
10,
Floor,
"0.99902",
"0x0.ffc#10",
Less,
);
test(
"1.5",
"0x1.8#2",
"-6.2e-61",
"-0x1.0E-50#1",
10,
Nearest,
"1.0000",
"0x1.000#10",
Greater,
);
test(
"-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000005",
"-0x1.0000000000000000000000000000000000000000000000000000000000000000000001#281",
"20370359763344860862684456884093781610514683936659362506361404493543812997633367061833973\
77.0",
"0x1000000000000000000000000000000000000000000000000000000000000000000000000001.0#301",
10,
Nearest,
"-5.8943e455390",
"-0xa.84E+378193#10",
Greater,
);
test(
"2.0",
"0x2.0#1",
"-1073741825.0",
"-0x40000001.0#31",
5,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"3.0",
"0x3.0#2",
"677453079.50",
"0x28611d17.8#32",
2,
Nearest,
"2.0e323227263",
"0x8.0E+268434431#2",
Less,
);
test(
"3.0",
"0x3.0#2",
"-1048576.5",
"-0x100000.8#22",
10,
Nearest,
"7.3203e-500299",
"0x2.f7E-415489#10",
Less,
);
test(
"1.5",
"0x1.8#2",
"1048576.5",
"0x100000.8#22",
10,
Nearest,
"1.4331e184645",
"0x3.d1E+153344#10",
Greater,
);
test(
"0.75",
"0x0.c#2",
"2587095930.0",
"0x9a33f37a.0#31",
10,
Floor,
"0.0",
"0x0.0",
Less,
);
test(
"0.75",
"0x0.c#2",
"2587095930.0",
"0x9a33f37a.0#31",
10,
Up,
"2.3826e-323228497",
"0x1.000E-268435456#10",
Greater,
);
test(
"1.5",
"0x1.8#2",
"-1835573822.0",
"-0x6d68a23e.0#30",
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"1.5",
"0x1.8#2",
"-1835573822.0",
"-0x6d68a23e.0#30",
10,
Floor,
"0.0",
"0x0.0",
Less,
);
test(
"0.75",
"0x0.c#2",
"8.6e9",
"0x2.0E+8#1",
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
}
#[allow(clippy::needless_pass_by_value)]
fn pow_prec_round_properties_helper(
x: Float,
y: Float,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = x.pow_prec_round_ref_ref(&y, prec, Nearest);
if o == Equal {
let (pe, oe) = x.pow_prec_round_ref_ref(&y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.pow_prec_round_ref_ref(&y, prec, Exact));
}
return;
}
let (p, o) = x.clone().pow_prec_round(y.clone(), prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_prec_round_val_ref(&y, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_prec_round_ref_val(y.clone(), prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_prec_round_ref_ref(&y, 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.pow_prec_round_assign(y.clone(), prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_prec_round_assign_ref(&y, 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_pow_prec_round(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
prec,
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p),
);
assert_eq!(rug_o, o);
}
if x.is_normal() && x.is_sign_negative() && y.is_normal() && !(&y).is_integer() {
assert!(p.is_nan());
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn pow_prec_round_properties() {
float_float_unsigned_rounding_mode_quadruple_gen_var_9().test_properties(|(x, y, prec, rm)| {
pow_prec_round_properties_helper(x, y, prec, rm, false);
});
float_float_unsigned_rounding_mode_quadruple_gen_var_10().test_properties(
|(x, y, prec, rm)| {
pow_prec_round_properties_helper(x, y, prec, rm, true);
},
);
}
#[test]
fn pow_prec_properties() {
float_float_unsigned_triple_gen_var_1().test_properties(|(x, y, prec)| {
let (p, o) = x.clone().pow_prec(y.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_prec_ref_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_prec_round_ref_ref(&y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (rug_p, rug_o) = rug_pow_prec(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
prec,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p),
);
assert_eq!(rug_o, o);
});
}
#[test]
fn pow_properties() {
float_pair_gen().test_properties(|(x, y)| {
let p = x.clone().pow(y.clone());
assert!(p.is_valid());
let p_alt = x.clone().pow(&y);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = (&x).pow(y.clone());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = (&x).pow(&y);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(y.clone());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(&y);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let rug_p = rug_pow(&rug::Float::exact_from(&x), &rug::Float::exact_from(&y));
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p),
);
let prec = x.significant_bits().max(y.significant_bits());
let (p1, _) = x.pow_prec_round_ref_val(Float::ONE, prec, Nearest);
let (x_rounded, _) = Float::from_float_prec_round_ref(&x, prec, Nearest);
assert_eq!(ComparableFloatRef(&p1), ComparableFloatRef(&x_rounded));
});
float_pair_gen_var_10().test_properties(|(x, y)| {
let p = (&x).pow(&y);
assert!(p.is_valid());
let rug_p = rug_pow(&rug::Float::exact_from(&x), &rug::Float::exact_from(&y));
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p),
);
});
}
#[test]
fn pow_round_properties() {
float_pair_gen().test_properties(|(x, y)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().pow_round(y.clone(), rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_round_ref_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p_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_pow_round(
&rug::Float::exact_from(&x),
&rug::Float::exact_from(&y),
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p),
);
assert_eq!(rug_o, o);
}
}
});
}
#[test]
fn test_powr_special_values() {
let test = |x: Float, y: Float, out: Float, o_out: Ordering| {
let (p, o) = x.powr_prec_round_ref_ref(&y, 10, Nearest);
assert!(p.is_valid());
assert_eq!(ComparableFloat(p), ComparableFloat(out));
assert_eq!(o, o_out);
};
let one = || Float::one_prec(10);
test(Float::INFINITY, Float::ZERO, Float::NAN, Equal);
test(Float::ZERO, Float::ZERO, Float::NAN, Equal);
test(Float::NEGATIVE_ZERO, Float::ZERO, Float::NAN, Equal);
test(Float::from(3.0), Float::ZERO, one(), Equal);
test(Float::NAN, Float::ZERO, Float::NAN, Equal);
test(Float::NAN, Float::ONE, Float::NAN, Equal);
test(Float::ONE, Float::from(3.0), one(), Equal);
test(Float::ONE, Float::NAN, one(), Equal);
test(Float::ONE, Float::INFINITY, Float::NAN, Equal);
test(Float::ONE, Float::NEGATIVE_INFINITY, Float::NAN, Equal);
test(Float::from(-2.0), Float::from(3.0), Float::NAN, Equal);
test(Float::from(-2.0), Float::from(0.5), Float::NAN, Equal);
test(
Float::NEGATIVE_INFINITY,
Float::from(3.0),
Float::NAN,
Equal,
);
test(-Float::ONE, Float::INFINITY, Float::NAN, Equal);
test(Float::from(2.0), Float::INFINITY, Float::INFINITY, Equal);
test(
Float::from(2.0),
Float::NEGATIVE_INFINITY,
Float::ZERO,
Equal,
);
test(Float::from(0.5), Float::INFINITY, Float::ZERO, Equal);
test(
Float::from(0.5),
Float::NEGATIVE_INFINITY,
Float::INFINITY,
Equal,
);
test(Float::INFINITY, Float::from(2.0), Float::INFINITY, Equal);
test(Float::INFINITY, Float::from(-2.0), Float::ZERO, Equal);
test(Float::ZERO, Float::from(3.0), Float::ZERO, Equal);
test(Float::ZERO, Float::from(-3.0), Float::INFINITY, Equal);
test(Float::NEGATIVE_ZERO, Float::from(3.0), Float::ZERO, Equal);
test(Float::NEGATIVE_ZERO, Float::from(2.0), Float::ZERO, Equal);
test(
Float::NEGATIVE_ZERO,
Float::from(-3.0),
Float::INFINITY,
Equal,
);
test(
Float::NEGATIVE_ZERO,
Float::from(-2.0),
Float::INFINITY,
Equal,
);
}
#[test]
fn test_powr() {
let test = |s, s_hex, t, t_hex, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let y = parse_hex_string(t_hex);
assert_eq!(y.to_string(), t);
let (p, o) = x.powr_prec_round(y, 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);
};
test(
"2.0",
"0x2.0#1",
"0.50",
"0x0.8#1",
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(
"3.0",
"0x3.0#2",
"100.0",
"0x64.0#5",
53,
Nearest,
"5.1537752073201132e47",
"0x5.a4653ca673768E+39#53",
Less,
);
test(
"2.0",
"0x2.0#1",
"10.0",
"0xa.0#3",
53,
Nearest,
"1024.0000000000000",
"0x400.00000000000#53",
Equal,
);
test(
"0.50",
"0x0.8#1",
"2.0",
"0x2.0#1",
53,
Nearest,
"0.25000000000000000",
"0x0.40000000000000#53",
Equal,
);
test(
"10.0",
"0xa.0#3",
"-1.0",
"-0x1.0#1",
53,
Nearest,
"0.10000000000000001",
"0x0.1999999999999a#53",
Greater,
);
}
#[allow(clippy::needless_pass_by_value)]
fn powr_prec_round_properties_helper(
x: Float,
y: Float,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = x.powr_prec_round_ref_ref(&y, prec, Nearest);
if o == Equal {
let (pe, oe) = x.powr_prec_round_ref_ref(&y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.powr_prec_round_ref_ref(&y, prec, Exact));
}
return;
}
let (p, o) = x.clone().powr_prec_round(y.clone(), prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().powr_prec_round_val_ref(&y, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_prec_round_ref_val(y.clone(), prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_prec_round_ref_ref(&y, 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.powr_prec_round_assign(y.clone(), prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.powr_prec_round_assign_ref(&y, prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if x.is_normal() && x.is_sign_positive() && !(x == 1u32 && y.is_infinite()) {
let (pp, op) = x.pow_prec_round_ref_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&pp));
assert_eq!(o, op);
}
if x.is_nan() || (x.is_sign_negative() && x != 0u32) {
assert!(p.is_nan());
}
if x == 0u32 && x.is_sign_negative() && y.is_normal() {
assert!(p.is_sign_positive());
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn powr_prec_round_properties() {
float_float_unsigned_rounding_mode_quadruple_gen_var_9().test_properties(|(x, y, prec, rm)| {
powr_prec_round_properties_helper(x, y, prec, rm, false);
});
float_float_unsigned_rounding_mode_quadruple_gen_var_10().test_properties(
|(x, y, prec, rm)| {
powr_prec_round_properties_helper(x, y, prec, rm, true);
},
);
}
#[test]
fn powr_prec_properties() {
float_float_unsigned_triple_gen_var_1().test_properties(|(x, y, prec)| {
let (p, o) = x.clone().powr_prec(y.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().powr_prec_val_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_prec_ref_val(y.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_prec_ref_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.powr_prec_assign(y.clone(), prec);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.powr_prec_assign_ref(&y, prec);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_prec_round_ref_ref(&y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if x.is_normal() && x.is_sign_positive() && !(x == 1u32 && y.is_infinite()) {
let (pp, op) = x.pow_prec_ref_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&pp));
assert_eq!(o, op);
}
});
}
#[test]
fn powr_round_properties() {
float_pair_gen().test_properties(|(x, y)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().powr_round(y.clone(), rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().powr_round_val_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_round_ref_val(y.clone(), rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.powr_round_ref_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.powr_round_assign(y.clone(), rm);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.powr_round_assign_ref(&y, rm);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if x.is_normal() && x.is_sign_positive() && !(x == 1u32 && y.is_infinite()) {
let (pp, op) = x.pow_round_ref_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&pp));
assert_eq!(o, op);
}
}
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_pow() {
fn test<T: PrimitiveFloat>(x: T, y: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_pow(x, y)), NiceFloat(out));
}
test::<f32>(f32::NAN, f32::NAN, f32::NAN);
test::<f32>(f32::NAN, f32::INFINITY, f32::NAN);
test::<f32>(f32::NAN, f32::NEGATIVE_INFINITY, f32::NAN);
test::<f32>(f32::NAN, 0.0, 1.0);
test::<f32>(f32::NAN, -0.0, 1.0);
test::<f32>(f32::NAN, 1.0, f32::NAN);
test::<f32>(f32::NAN, -1.0, f32::NAN);
test::<f32>(f32::NAN, 2.0, f32::NAN);
test::<f32>(f32::NAN, -3.0, f32::NAN);
test::<f32>(f32::INFINITY, f32::NAN, f32::NAN);
test::<f32>(f32::INFINITY, f32::INFINITY, f32::INFINITY);
test::<f32>(f32::INFINITY, f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(f32::INFINITY, 0.0, 1.0);
test::<f32>(f32::INFINITY, -0.0, 1.0);
test::<f32>(f32::INFINITY, 1.0, f32::INFINITY);
test::<f32>(f32::INFINITY, -1.0, 0.0);
test::<f32>(f32::INFINITY, 2.0, f32::INFINITY);
test::<f32>(f32::INFINITY, -3.0, 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, f32::NAN, f32::NAN);
test::<f32>(f32::NEGATIVE_INFINITY, f32::INFINITY, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, 0.0, 1.0);
test::<f32>(f32::NEGATIVE_INFINITY, -0.0, 1.0);
test::<f32>(f32::NEGATIVE_INFINITY, 1.0, f32::NEGATIVE_INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, -1.0, -0.0);
test::<f32>(f32::NEGATIVE_INFINITY, 2.0, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, -3.0, -0.0);
test::<f32>(0.0, f32::NAN, f32::NAN);
test::<f32>(0.0, f32::INFINITY, 0.0);
test::<f32>(0.0, f32::NEGATIVE_INFINITY, f32::INFINITY);
test::<f32>(0.0, 0.0, 1.0);
test::<f32>(0.0, -0.0, 1.0);
test::<f32>(0.0, 1.0, 0.0);
test::<f32>(0.0, -1.0, f32::INFINITY);
test::<f32>(0.0, 2.0, 0.0);
test::<f32>(0.0, -3.0, f32::INFINITY);
test::<f32>(-0.0, f32::NAN, f32::NAN);
test::<f32>(-0.0, f32::INFINITY, 0.0);
test::<f32>(-0.0, f32::NEGATIVE_INFINITY, f32::INFINITY);
test::<f32>(-0.0, 0.0, 1.0);
test::<f32>(-0.0, -0.0, 1.0);
test::<f32>(-0.0, 1.0, -0.0);
test::<f32>(-0.0, -1.0, f32::NEGATIVE_INFINITY);
test::<f32>(-0.0, 2.0, 0.0);
test::<f32>(-0.0, -3.0, f32::NEGATIVE_INFINITY);
test::<f32>(1.0, f32::NAN, 1.0);
test::<f32>(1.0, f32::INFINITY, 1.0);
test::<f32>(1.0, f32::NEGATIVE_INFINITY, 1.0);
test::<f32>(1.0, 0.0, 1.0);
test::<f32>(1.0, -0.0, 1.0);
test::<f32>(1.0, 1.0, 1.0);
test::<f32>(1.0, -1.0, 1.0);
test::<f32>(1.0, 2.0, 1.0);
test::<f32>(1.0, -3.0, 1.0);
test::<f32>(-1.0, f32::NAN, f32::NAN);
test::<f32>(-1.0, f32::INFINITY, 1.0);
test::<f32>(-1.0, f32::NEGATIVE_INFINITY, 1.0);
test::<f32>(-1.0, 0.0, 1.0);
test::<f32>(-1.0, -0.0, 1.0);
test::<f32>(-1.0, 1.0, -1.0);
test::<f32>(-1.0, -1.0, -1.0);
test::<f32>(-1.0, 2.0, 1.0);
test::<f32>(-1.0, -3.0, -1.0);
test::<f32>(2.0, f32::NAN, f32::NAN);
test::<f32>(2.0, f32::INFINITY, f32::INFINITY);
test::<f32>(2.0, f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(2.0, 0.0, 1.0);
test::<f32>(2.0, -0.0, 1.0);
test::<f32>(2.0, 1.0, 2.0);
test::<f32>(2.0, -1.0, 0.5);
test::<f32>(2.0, 2.0, 4.0);
test::<f32>(2.0, -3.0, 0.125);
test::<f32>(-3.0, f32::NAN, f32::NAN);
test::<f32>(-3.0, f32::INFINITY, f32::INFINITY);
test::<f32>(-3.0, f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(-3.0, 0.0, 1.0);
test::<f32>(-3.0, -0.0, 1.0);
test::<f32>(-3.0, 1.0, -3.0);
test::<f32>(-3.0, -1.0, -0.33333334);
test::<f32>(-3.0, 2.0, 9.0);
test::<f32>(-3.0, -3.0, -0.037037037);
test::<f32>(3.0, 2.5, 15.588457);
test::<f32>(2.0, 0.5, core::f32::consts::SQRT_2);
test::<f32>(1.5, 100.0, 4.065612e17);
test::<f32>(2.0, 128.0, f32::INFINITY);
test::<f32>(2.0, -150.0, 0.0);
test::<f64>(3.0, 2.5, 15.588457268119896);
test::<f64>(2.0, 0.5, core::f64::consts::SQRT_2);
test::<f64>(10.0, -0.5, 0.31622776601683794);
test::<f64>(0.5, 0.5, core::f64::consts::FRAC_1_SQRT_2);
test::<f64>(1.5, 100.0, 4.065611775352152e17);
test::<f64>(0.9999999999, 10000000000.0, 0.36787941071456814);
test::<f64>(-2.0, 3.0, -8.0);
test::<f64>(-2.0, 0.5, f64::NAN);
test::<f64>(1.0e300, 2.0, f64::INFINITY);
test::<f64>(1.0e-300, 2.0, 0.0);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_pow_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_pair_gen::<T>().test_properties(|(x, y)| {
primitive_float_pow(x, y);
});
}
#[test]
fn primitive_float_pow_properties() {
apply_fn_to_primitive_floats!(primitive_float_pow_properties_helper);
}
#[test]
fn test_pow_sliver_of_one() {
let p = u64::try_from(-i64::from(Float::MIN_EXPONENT) + 3).unwrap();
let eps = Rational::power_of_2(i64::from(Float::MIN_EXPONENT) - 2);
let sliver = |xr: Rational| Float::from_rational_prec_round(xr, p, Exact).0;
let test = |x: Float, y: Float, out: &str, out_hex: &str, o_out| {
let (r, o) = x.pow_prec_round_ref_ref(&y, 64, Nearest);
assert!(r.is_valid());
assert_eq!(r.to_string(), out);
assert_eq!(to_hex_string(&r), out_hex);
assert_eq!(o, o_out);
};
let y = Float::power_of_2(60i64);
test(
sliver(Rational::ONE + &eps),
y.clone(),
"1.00000000000000000000",
"0x1.0000000000000000#64",
Less,
);
test(
sliver(Rational::ONE - &eps),
y.clone(),
"1.00000000000000000000",
"0x1.0000000000000000#64",
Greater,
);
test(
sliver(-(Rational::ONE + &eps)),
y,
"1.00000000000000000000",
"0x1.0000000000000000#64",
Less,
);
let y_odd =
Float::from_rational_prec_round(Rational::power_of_2(60i64) + Rational::ONE, 61, Exact).0;
test(
sliver(-(Rational::ONE + &eps)),
y_odd,
"-1.00000000000000000000",
"-0x1.0000000000000000#64",
Greater,
);
}
#[test]
fn test_rational_pow() {
let test = |s: &str,
t: &str,
t_hex: &str,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out| {
let x = Rational::from_str(s).unwrap();
let y = parse_hex_string(t_hex);
assert_eq!(y.to_string(), t);
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, 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);
};
test(
"3/2",
"0.50",
"0x0.8#1",
20,
Nearest,
"1.2247448",
"0x1.3988e#20",
Less,
);
test(
"2/3",
"2.5",
"0x2.8#3",
20,
Floor,
"0.36288691",
"0x0.5ce628#20",
Less,
);
test(
"-3/2",
"3.0",
"0x3.0#2",
20,
Nearest,
"-3.3750000",
"-0x3.60000#20",
Equal,
);
test("-3/2", "0.50", "0x0.8#1", 20, Nearest, "NaN", "NaN", Equal);
test(
"9/4",
"0.50",
"0x0.8#1",
20,
Nearest,
"1.5000000",
"0x1.80000#20",
Equal,
);
test(
"1/4",
"0.75",
"0x0.c#2",
20,
Nearest,
"0.35355330",
"0x0.5a8278#20",
Less,
);
test(
"3/7",
"40.0",
"0x28.0#3",
30,
Nearest,
"1.9095392443e-15",
"0x8.998c820E-13#30",
Greater,
);
test(
"5/4",
"0.50",
"0x0.8#1",
20,
Nearest,
"1.1180344",
"0x1.1e378#20",
Greater,
);
test(
"2/3",
"1.1e12",
"0x1.0E+10#1",
32,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"2/3",
"1.1e12",
"0x1.0E+10#1",
32,
Up,
"2.3825649049e-323228497",
"0x1.00000000E-268435456#32",
Greater,
);
let test2 = |x: Rational, t_hex: &str, prec: u64, out_hex: &str, o_out| {
let y = parse_hex_string(t_hex);
let (r, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Nearest);
assert!(r.is_valid());
assert_eq!(to_hex_string(&r), out_hex);
assert_eq!(o, o_out);
};
let tiny = Rational::from_unsigneds(1u32, 3u32).pow(100i64);
test2(
Rational::from(4u32) - &tiny,
"0x0.8#1",
5,
"0x2.0#5",
Greater,
);
test2(Rational::from(9u32) + &tiny, "0x0.8#1", 5, "0x3.0#5", Less);
}
#[test]
fn test_rational_pow_extreme() {
let test = |x: &Rational,
t: &str,
t_hex: &str,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out| {
let y = parse_hex_string(t_hex);
assert_eq!(y.to_string(), t);
let (p, o) = Float::rational_pow_prec_round_ref_ref(x, &y, 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 e = i64::from(Float::MAX_EXPONENT) + 1;
let mi = i64::from(Float::MIN_EXPONENT);
test(
&(Rational::from(3u32) * Rational::power_of_2(e)),
"0.25",
"0x0.4#1",
20,
Nearest,
"1.8837326e80807124",
"0x1.50ea4E+67108864#20",
Greater,
);
test(
&(Rational::from(81u32) * Rational::power_of_2(e)),
"0.25",
"0x0.4#1",
20,
Nearest,
"4.2939805e80807124",
"0x3.00000E+67108864#20",
Equal,
);
test(
&(Rational::from(5u32) * Rational::power_of_2(-e)),
"-0.50",
"-0x0.8#1",
20,
Nearest,
"9.1620505e161614247",
"0x7.27c98E+134217727#20",
Greater,
);
test(
&(Rational::ONE - Rational::power_of_2(mi - 2)),
"1.2e18",
"0x1.0E+15#1",
64,
Nearest,
"1.00000000000000000000",
"0x1.0000000000000000#64",
Greater,
);
test(
&((Rational::ONE + Rational::from_unsigneds(1u32, 3u32).pow(500i64))
* Rational::power_of_2(e)),
"0.25",
"0x0.4#1",
20,
Nearest,
"1.4313268e80807124",
"0x1.00000E+67108864#20",
Less,
);
test(
&(Rational::ONE + Rational::power_of_2(-70000i64)),
"1.2e18",
"0x1.0E+15#1",
64,
Nearest,
"1.00000000000000000000",
"0x1.0000000000000000#64",
Less,
);
test(
&(Rational::ONE + Rational::from_unsigneds(1u32, 3u32).pow(500i64)),
"5.3e210",
"0x1.0E+175#1",
64,
Nearest,
"1.00000000000000000000",
"0x1.0000000000000000#64",
Less,
);
test(
&((Rational::ONE - Rational::from_unsigneds(1u32, 3u32).pow(500i64))
* Rational::power_of_2(e)),
"0.25",
"0x0.4#1",
20,
Nearest,
"1.4313268e80807124",
"0x1.00000E+67108864#20",
Greater,
);
}
#[test]
fn test_rational_pow_exact_bound_regression() {
let x = Rational::from_unsigneds(4u32, 83521u32);
let y = Float::from(-1.5);
let exact = Rational::from_unsigneds(24137569u32, 8u32);
for prec in [21u64, 24, 25, 30] {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, rm);
let (ep, eo) = Float::from_rational_prec_round(exact.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&ep));
assert_eq!(o, eo);
}
}
let x = Rational::from_unsigneds(4u32, 289u32);
let y = Float::from(-2.5);
let exact = Rational::from_unsigneds(1419857u32, 32u32);
for prec in [21u64, 25] {
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Exact);
let (ep, _) = Float::from_rational_prec_round(exact.clone(), prec, Exact);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&ep));
assert_eq!(o, Equal);
}
let e = -(1i64 << 30) - 100;
let x = Rational::from(83521u32) << e;
let y = Float::from(0.75);
for prec in [12u64, 13, 20] {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, rm);
let (ep, eo) = Float::from(4913u32).shl_prec_round(3 * e / 4, prec, rm);
assert_eq!(ComparableFloatRef(&p), ComparableFloatRef(&ep));
assert_eq!(o, eo);
}
}
}
#[allow(clippy::needless_pass_by_value)]
fn rational_pow_prec_round_properties_helper(x: Rational, y: Float, prec: u64, rm: RoundingMode) {
if rm == Exact {
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Nearest);
if o == Equal {
let (pe, oe) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Exact));
}
return;
}
let (p, o) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::rational_pow_prec_round(x.clone(), y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_prec_round_val_ref(x.clone(), &y, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_prec_round_ref_val(&x, y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if x != 0u32 && y.is_finite() {
let bits = x.numerator_ref().significant_bits() + x.denominator_ref().significant_bits();
if x.denominator_ref().is_power_of_2() && bits < 10000 {
let xf = Float::from_rational_prec_round_ref(&x, bits, Floor).0;
if Rational::exact_from(&xf) == x {
let (p_alt, o_alt) = xf.pow_prec_round_val_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
}
}
if y.is_finite()
&& !y.is_zero()
&& (&y).is_integer()
&& y.significant_bits() < 20
&& let Ok(z) = i64::try_from(&Integer::rounding_from(&y, Nearest).0)
&& z.unsigned_abs() < 100
&& x != 0u32
{
let (p_alt, o_alt) = Float::from_rational_prec_round((&x).pow(z), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if o == Equal && p.is_normal() {
for rm2 in [Floor, Ceiling, Down, Up, Nearest] {
let (p_alt, o_alt) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, rm2);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, Equal);
}
}
if x < 0u32 && y.is_normal() && !(&y).is_integer() {
assert!(p.is_nan());
}
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn rational_pow_prec_round_properties() {
float_rational_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(y, x, prec, rm)| {
rational_pow_prec_round_properties_helper(x, y, prec, rm);
},
);
}
#[test]
fn rational_pow_prec_properties() {
float_rational_unsigned_triple_gen_var_1::<u64>().test_properties(|(y, x, prec)| {
let (p, o) = Float::rational_pow_prec_ref_ref(&x, &y, prec);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::rational_pow_prec(x.clone(), y.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_prec_val_ref(x.clone(), &y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_prec_ref_val(&x, y.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_prec_round_ref_ref(&x, &y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_rational_pow() {
fn test<T: PrimitiveFloat>(s: &str, y: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
let x = Rational::from_str(s).unwrap();
assert_eq!(
NiceFloat(primitive_float_rational_pow(&x, y)),
NiceFloat(out)
);
}
test::<f32>("0", f32::NAN, f32::NAN);
test::<f32>("0", f32::INFINITY, 0.0);
test::<f32>("0", f32::NEGATIVE_INFINITY, f32::INFINITY);
test::<f32>("0", 0.0, 1.0);
test::<f32>("0", -0.0, 1.0);
test::<f32>("0", 2.0, 0.0);
test::<f32>("0", -3.0, f32::INFINITY);
test::<f32>("1", f32::NAN, 1.0);
test::<f32>("1", f32::INFINITY, 1.0);
test::<f32>("1", f32::NEGATIVE_INFINITY, 1.0);
test::<f32>("1", 0.0, 1.0);
test::<f32>("1", -0.0, 1.0);
test::<f32>("1", 2.0, 1.0);
test::<f32>("1", -3.0, 1.0);
test::<f32>("-1", f32::NAN, f32::NAN);
test::<f32>("-1", f32::INFINITY, 1.0);
test::<f32>("-1", f32::NEGATIVE_INFINITY, 1.0);
test::<f32>("-1", 0.0, 1.0);
test::<f32>("-1", -0.0, 1.0);
test::<f32>("-1", 2.0, 1.0);
test::<f32>("-1", -3.0, -1.0);
test::<f32>("2", f32::NAN, f32::NAN);
test::<f32>("2", f32::INFINITY, f32::INFINITY);
test::<f32>("2", f32::NEGATIVE_INFINITY, 0.0);
test::<f32>("2", 0.0, 1.0);
test::<f32>("2", -0.0, 1.0);
test::<f32>("2", 2.0, 4.0);
test::<f32>("2", -3.0, 0.125);
test::<f32>("1/2", f32::NAN, f32::NAN);
test::<f32>("1/2", f32::INFINITY, 0.0);
test::<f32>("1/2", f32::NEGATIVE_INFINITY, f32::INFINITY);
test::<f32>("1/2", 0.0, 1.0);
test::<f32>("1/2", -0.0, 1.0);
test::<f32>("1/2", 2.0, 0.25);
test::<f32>("1/2", -3.0, 8.0);
test::<f64>("3/2", 2.5, 2.7556759606310752);
test::<f64>("2/3", -2.5, 2.7556759606310752);
test::<f64>("9/4", 0.5, 1.5);
test::<f64>("1/4", 0.75, 0.3535533905932738);
test::<f64>("-3/2", 3.0, -3.375);
test::<f64>("-3/2", 0.5, f64::NAN);
test::<f64>("3/2", 1000.0, 1.2338405969061735e176);
test::<f64>("2/3", 1000.0, 8.104774656527566e-177);
test::<f32>("3/2", 2.5, 2.755676);
test::<f32>("2", 200.0, f32::INFINITY);
test::<f32>("1/2", 200.0, 0.0);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_rational_pow_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_primitive_float_pair_gen::<T>().test_properties(|(x, y)| {
primitive_float_rational_pow::<T>(&x, y);
});
}
#[test]
fn primitive_float_rational_pow_properties() {
apply_fn_to_primitive_floats!(primitive_float_rational_pow_properties_helper);
}
#[allow(clippy::needless_pass_by_value)]
fn pow_integer_prec_round_properties_helper(
x: Float,
z: Integer,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = x.pow_integer_prec_round_ref_ref(&z, prec, Nearest);
if o == Equal {
let (pe, oe) = x.pow_integer_prec_round_ref_ref(&z, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.pow_integer_prec_round_ref_ref(&z, prec, Exact));
}
return;
}
let (p, o) = x.clone().pow_integer_prec_round(z.clone(), prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_integer_prec_round_val_ref(&z, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_prec_round_ref_val(z.clone(), prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_prec_round_ref_ref(&z, 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.pow_integer_prec_round_assign(z.clone(), prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_integer_prec_round_assign_ref(&z, 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_pow_integer_prec_round(
&rug::Float::exact_from(&x),
&rug::Integer::from(&z),
prec,
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn pow_integer_prec_round_properties() {
float_integer_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(x, z, prec, rm)| {
pow_integer_prec_round_properties_helper(x, z, prec, rm, false);
},
);
float_integer_unsigned_rounding_mode_quadruple_gen_var_2().test_properties(
|(x, z, prec, rm)| {
pow_integer_prec_round_properties_helper(x, z, prec, rm, true);
},
);
}
#[test]
fn pow_integer_prec_properties() {
float_integer_unsigned_triple_gen_var_1::<u64>().test_properties(|(x, z, prec)| {
let (p, o) = x.clone().pow_integer_prec(z.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_integer_prec_val_ref(&z, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_prec_ref_val(z.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_prec_ref_ref(&z, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_prec_round_ref_ref(&z, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (rug_p, rug_o) =
rug_pow_integer_prec(&rug::Float::exact_from(&x), &rug::Integer::from(&z), prec);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
});
}
#[test]
fn pow_integer_round_properties() {
float_integer_pair_gen().test_properties(|(x, z)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().pow_integer_round(z.clone(), rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_integer_round_val_ref(&z, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_round_ref_val(z.clone(), rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_integer_round_ref_ref(&z, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_integer_round_assign(z.clone(), rm);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_integer_round_assign_ref(&z, rm);
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_pow_integer_round(
&rug::Float::exact_from(&x),
&rug::Integer::from(&z),
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
});
}
#[test]
fn pow_integer_properties() {
float_integer_pair_gen().test_properties(|(x, z)| {
let p = x.clone().pow(z.clone());
assert!(p.is_valid());
let p_alt = x.clone().pow(&z);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = (&x).pow(z.clone());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = (&x).pow(&z);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(z.clone());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(&z);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let (p_alt, _) = x.pow_integer_round_ref_ref(&z, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let rug_p = rug_pow_integer(&rug::Float::exact_from(&x), &rug::Integer::from(&z));
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
});
}
#[test]
fn test_pow_integer() {
let test = |s, s_hex, z: i64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (p, o) = x.pow_integer_prec_round(Integer::from(z), 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);
};
test(
"3.0",
"0x3.0#2",
5,
20,
Nearest,
"243.00000",
"0xf3.000#20",
Equal,
);
test(
"2.0",
"0x2.0#1",
10,
10,
Nearest,
"1024.0",
"0x400.0#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
3,
10,
Nearest,
"-8.0000",
"-0x8.00#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
4,
10,
Nearest,
"16.000",
"0x10.00#10",
Equal,
);
test(
"1.5",
"0x1.8#2",
2,
10,
Nearest,
"2.2500",
"0x2.40#10",
Equal,
);
test(
"3.0",
"0x3.0#2",
-2,
10,
Floor,
"0.11108",
"0x0.1c70#10",
Less,
);
test(
"3.0",
"0x3.0#2",
-2,
10,
Ceiling,
"0.11121",
"0x0.1c78#10",
Greater,
);
test("3.0", "0x3.0#2", 5, 2, Floor, "1.9e2", "0xc.0E+1#2", Less);
test(
"3.0",
"0x3.0#2",
5,
2,
Ceiling,
"2.6e2",
"0x1.0E+2#2",
Greater,
);
test(
"-3.0",
"-0x3.0#2",
-1,
10,
Nearest,
"-0.33350",
"-0x0.556#10",
Less,
);
test(
"5.0",
"0x5.0#3",
0,
10,
Nearest,
"1.0000",
"0x1.000#10",
Equal,
);
test(
"-5.0",
"-0x5.0#3",
0,
10,
Nearest,
"1.0000",
"0x1.000#10",
Equal,
);
test(
"-1.0", "-0x1.0#1", 7, 5, Nearest, "-1.00", "-0x1.0#5", Equal,
);
test("-1.0", "-0x1.0#1", 8, 5, Nearest, "1.00", "0x1.0#5", Equal);
test(
"2.0",
"0x2.0#3",
100000000000,
5,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
"2.0",
"0x2.0#3",
-100000000000,
5,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"2.0",
"0x2.0#3",
-100000000000,
5,
Up,
"2.38e-323228497",
"0x1.0E-268435456#5",
Greater,
);
}
#[test]
fn test_pow_integer_special_values() {
let test = |base: Float, z: i64, out: &str, out_hex: &str| {
let (p, o) = base.pow_integer_prec_round(Integer::from(z), 1, Nearest);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, Equal);
};
test(Float::NAN, 0, "1.0", "0x1.0#1");
test(Float::NAN, 2, "NaN", "NaN");
test(Float::NAN, 3, "NaN", "NaN");
test(Float::NAN, -2, "NaN", "NaN");
test(Float::NAN, -3, "NaN", "NaN");
test(Float::INFINITY, 0, "1.0", "0x1.0#1");
test(Float::INFINITY, 2, "Infinity", "Infinity");
test(Float::INFINITY, 3, "Infinity", "Infinity");
test(Float::INFINITY, -2, "0.0", "0x0.0");
test(Float::INFINITY, -3, "0.0", "0x0.0");
test(Float::NEGATIVE_INFINITY, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_INFINITY, 2, "Infinity", "Infinity");
test(Float::NEGATIVE_INFINITY, 3, "-Infinity", "-Infinity");
test(Float::NEGATIVE_INFINITY, -2, "0.0", "0x0.0");
test(Float::NEGATIVE_INFINITY, -3, "-0.0", "-0x0.0");
test(Float::ZERO, 0, "1.0", "0x1.0#1");
test(Float::ZERO, 2, "0.0", "0x0.0");
test(Float::ZERO, 3, "0.0", "0x0.0");
test(Float::ZERO, -2, "Infinity", "Infinity");
test(Float::ZERO, -3, "Infinity", "Infinity");
test(Float::NEGATIVE_ZERO, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ZERO, 2, "0.0", "0x0.0");
test(Float::NEGATIVE_ZERO, 3, "-0.0", "-0x0.0");
test(Float::NEGATIVE_ZERO, -2, "Infinity", "Infinity");
test(Float::NEGATIVE_ZERO, -3, "-Infinity", "-Infinity");
test(Float::ONE, 0, "1.0", "0x1.0#1");
test(Float::ONE, 2, "1.0", "0x1.0#1");
test(Float::ONE, 3, "1.0", "0x1.0#1");
test(Float::ONE, -2, "1.0", "0x1.0#1");
test(Float::ONE, -3, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 2, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 3, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, -2, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, -3, "-1.0", "-0x1.0#1");
}
#[test]
fn test_pow_integer_extreme() {
let max_e = i64::from(Float::MAX_EXPONENT);
let min_e = i64::from(Float::MIN_EXPONENT);
let test = |base: Float, z: i64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let (p, o) = base.pow_integer_prec_round(Integer::from(z), 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);
};
test(
Float::power_of_2(max_e - 1),
1,
10,
Nearest,
"1.0493e323228496",
"0x4.00E+268435455#10",
Equal,
);
test(
Float::power_of_2(max_e - 1),
2,
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
Float::power_of_2(max_e - 1),
2,
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
test(
Float::power_of_2(min_e),
2,
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
Float::power_of_2(min_e),
2,
5,
Up,
"2.38e-323228497",
"0x1.0E-268435456#5",
Greater,
);
test(
Float::power_of_2(min_e),
-1,
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_pow_integer() {
fn test<T: PrimitiveFloat>(x: T, z: i64, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_pow_integer(x, &Integer::from(z))),
NiceFloat(out)
);
}
test::<f32>(f32::NAN, 0, 1.0);
test::<f32>(f32::NAN, 2, f32::NAN);
test::<f32>(f32::NAN, 3, f32::NAN);
test::<f32>(f32::NAN, -2, f32::NAN);
test::<f32>(f32::NAN, -3, f32::NAN);
test::<f32>(f32::INFINITY, 0, 1.0);
test::<f32>(f32::INFINITY, 2, f32::INFINITY);
test::<f32>(f32::INFINITY, 3, f32::INFINITY);
test::<f32>(f32::INFINITY, -2, 0.0);
test::<f32>(f32::INFINITY, -3, 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, 0, 1.0);
test::<f32>(f32::NEGATIVE_INFINITY, 2, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 3, f32::NEGATIVE_INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, -2, 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, -3, -0.0);
test::<f32>(0.0, 0, 1.0);
test::<f32>(0.0, 2, 0.0);
test::<f32>(0.0, 3, 0.0);
test::<f32>(0.0, -2, f32::INFINITY);
test::<f32>(0.0, -3, f32::INFINITY);
test::<f32>(-0.0, 0, 1.0);
test::<f32>(-0.0, 2, 0.0);
test::<f32>(-0.0, 3, -0.0);
test::<f32>(-0.0, -2, f32::INFINITY);
test::<f32>(-0.0, -3, f32::NEGATIVE_INFINITY);
test::<f32>(1.0, 0, 1.0);
test::<f32>(1.0, 2, 1.0);
test::<f32>(1.0, 3, 1.0);
test::<f32>(1.0, -2, 1.0);
test::<f32>(1.0, -3, 1.0);
test::<f32>(-1.0, 0, 1.0);
test::<f32>(-1.0, 2, 1.0);
test::<f32>(-1.0, 3, -1.0);
test::<f32>(-1.0, -2, 1.0);
test::<f32>(-1.0, -3, -1.0);
test::<f32>(3.0, 5, 243.0);
test::<f32>(2.0, 10, 1024.0);
test::<f32>(-2.0, 3, -8.0);
test::<f32>(2.0, -3, 0.125);
test::<f32>(2.0, 200, f32::INFINITY);
test::<f32>(0.5, 200, 0.0);
test::<f64>(3.0, 5, 243.0);
test::<f64>(2.0, -3, 0.125);
test::<f64>(1.5, 100, 4.065611775352152e17);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_pow_integer_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
integer_primitive_float_pair_gen::<T>().test_properties(|(z, x)| {
primitive_float_pow_integer::<T>(x, &z);
});
}
#[test]
fn primitive_float_pow_integer_properties() {
apply_fn_to_primitive_floats!(primitive_float_pow_integer_properties_helper);
}
#[test]
fn test_pow_u() {
let test = |s, s_hex, n: u64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (p, o) = x.pow_u_prec_round(n, 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);
};
test(
"3.0",
"0x3.0#2",
0,
10,
Nearest,
"1.0000",
"0x1.000#10",
Equal,
);
test(
"3.0",
"0x3.0#2",
1,
10,
Nearest,
"3.0000",
"0x3.00#10",
Equal,
);
test("1.2", "0x1.4#3", 1, 2, Nearest, "1.0", "0x1.0#2", Less);
test(
"3.0",
"0x3.0#2",
2,
10,
Nearest,
"9.0000",
"0x9.00#10",
Equal,
);
test("3.0", "0x3.0#2", 2, 2, Nearest, "8.0", "0x8.0#2", Less);
test(
"3.0",
"0x3.0#2",
5,
20,
Nearest,
"243.00000",
"0xf3.000#20",
Equal,
);
test("3.0", "0x3.0#2", 5, 2, Floor, "1.9e2", "0xc.0E+1#2", Less);
test(
"3.0",
"0x3.0#2",
5,
2,
Ceiling,
"2.6e2",
"0x1.0E+2#2",
Greater,
);
test(
"1.5",
"0x1.8#2",
3,
10,
Nearest,
"3.3750",
"0x3.60#10",
Equal,
);
test(
"1.50",
"0x1.8#4",
10,
20,
Nearest,
"57.665039",
"0x39.aa40#20",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
3,
10,
Nearest,
"-8.0000",
"-0x8.00#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
4,
10,
Nearest,
"16.000",
"0x10.00#10",
Equal,
);
test(
"-3.0",
"-0x3.0#2",
3,
10,
Nearest,
"-27.000",
"-0x1b.00#10",
Equal,
);
test(
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
2,
53,
Nearest,
"2.0000000000000004",
"0x2.0000000000002#53",
Greater,
);
test(
"2.0",
"0x2.0#3",
100000000000,
5,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
"2.0",
"0x2.0#3",
100000000000,
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
test(
"0.50",
"0x0.8#3",
100000000000,
5,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"0.50",
"0x0.8#3",
100000000000,
5,
Up,
"2.38e-323228497",
"0x1.0E-268435456#5",
Greater,
);
test(
"-269104312292334.3027",
"-0xf4bfbaf113ee.4d8#57",
11,
123,
Floor,
"-5.35953645660602053838906676724924628060e158",
"-0x9.c253fc20bc736c88c0172ae629606cE+131#123",
Less,
);
test(
"-0.00781249999999999999999999999999990",
"-0x0.01ffffffffffffffffffffffffff8#106",
72,
5,
Down,
"1.85e-152",
"0xf.8E-127#5",
Less,
);
}
#[test]
fn test_pow_u_special_values() {
let test = |base: Float, n: u64, out: &str, out_hex: &str| {
let (p, o) = base.pow_u_prec_round(n, 1, Nearest);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, Equal);
};
test(Float::NAN, 0, "1.0", "0x1.0#1");
test(Float::NAN, 1, "NaN", "NaN");
test(Float::NAN, 2, "NaN", "NaN");
test(Float::NAN, 3, "NaN", "NaN");
test(Float::NAN, 4, "NaN", "NaN");
test(Float::INFINITY, 0, "1.0", "0x1.0#1");
test(Float::INFINITY, 1, "Infinity", "Infinity");
test(Float::INFINITY, 2, "Infinity", "Infinity");
test(Float::INFINITY, 3, "Infinity", "Infinity");
test(Float::INFINITY, 4, "Infinity", "Infinity");
test(Float::NEGATIVE_INFINITY, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_INFINITY, 1, "-Infinity", "-Infinity");
test(Float::NEGATIVE_INFINITY, 2, "Infinity", "Infinity");
test(Float::NEGATIVE_INFINITY, 3, "-Infinity", "-Infinity");
test(Float::NEGATIVE_INFINITY, 4, "Infinity", "Infinity");
test(Float::ZERO, 0, "1.0", "0x1.0#1");
test(Float::ZERO, 1, "0.0", "0x0.0");
test(Float::ZERO, 2, "0.0", "0x0.0");
test(Float::ZERO, 3, "0.0", "0x0.0");
test(Float::ZERO, 4, "0.0", "0x0.0");
test(Float::NEGATIVE_ZERO, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ZERO, 1, "-0.0", "-0x0.0");
test(Float::NEGATIVE_ZERO, 2, "0.0", "0x0.0");
test(Float::NEGATIVE_ZERO, 3, "-0.0", "-0x0.0");
test(Float::NEGATIVE_ZERO, 4, "0.0", "0x0.0");
test(Float::ONE, 0, "1.0", "0x1.0#1");
test(Float::ONE, 1, "1.0", "0x1.0#1");
test(Float::ONE, 2, "1.0", "0x1.0#1");
test(Float::ONE, 3, "1.0", "0x1.0#1");
test(Float::ONE, 4, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 1, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, 2, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 3, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, 4, "1.0", "0x1.0#1");
}
#[test]
fn test_pow_u_extreme() {
let max_e = i64::from(Float::MAX_EXPONENT);
let min_e = i64::from(Float::MIN_EXPONENT);
let test = |base: Float, n: u64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let (p, o) = base.pow_u_prec_round(n, 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);
};
test(
Float::power_of_2(max_e - 1),
1,
10,
Nearest,
"1.0493e323228496",
"0x4.00E+268435455#10",
Equal,
);
test(
Float::power_of_2(max_e - 1),
2,
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
Float::power_of_2(max_e - 1),
2,
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
test(
Float::power_of_2(max_e - 1),
3,
10,
Ceiling,
"Infinity",
"Infinity",
Greater,
);
test(
Float::power_of_2(min_e),
2,
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
Float::power_of_2(min_e),
2,
5,
Up,
"2.38e-323228497",
"0x1.0E-268435456#5",
Greater,
);
test(
Float::power_of_2(min_e),
3,
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
-Float::power_of_2(max_e - 1),
3,
10,
Nearest,
"-Infinity",
"-Infinity",
Less,
);
}
#[allow(clippy::needless_pass_by_value)]
fn pow_u_prec_round_properties_helper(
x: Float,
n: u64,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = x.pow_u_prec_round_ref(n, prec, Nearest);
if o == Equal {
let (pe, oe) = x.pow_u_prec_round_ref(n, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.pow_u_prec_round_ref(n, prec, Exact));
}
return;
}
let (p, o) = x.clone().pow_u_prec_round(n, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_u_prec_round_ref(n, 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.pow_u_prec_round_assign(n, prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (pi, oi) = x.pow_integer_prec_round_ref_ref(&Integer::from(n), prec, rm);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_pow_u_prec_round(&rug::Float::exact_from(&x), n, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn pow_u_prec_round_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_9().test_properties(
|(x, n, prec, rm)| {
pow_u_prec_round_properties_helper(x, n, prec, rm, false);
},
);
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_10().test_properties(
|(x, n, prec, rm)| {
pow_u_prec_round_properties_helper(x, n, prec, rm, true);
},
);
}
#[test]
fn pow_u_prec_properties() {
float_unsigned_unsigned_triple_gen_var_1::<u64, u64>().test_properties(|(x, n, prec)| {
let (p, o) = x.clone().pow_u_prec(n, prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_u_prec_ref(n, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_u_prec_round_ref(n, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (pi, oi) = x.pow_integer_prec_ref_ref(&Integer::from(n), prec);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
let (rug_p, rug_o) = rug_pow_u_prec(&rug::Float::exact_from(&x), n, prec);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
});
}
#[test]
fn pow_u_round_properties() {
float_unsigned_pair_gen::<u64>().test_properties(|(x, n)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().pow_u_round(n, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_u_round_ref(n, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_u_round_assign(n, rm);
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_pow_u_round(&rug::Float::exact_from(&x), n, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
});
}
#[test]
fn pow_u_properties() {
float_unsigned_pair_gen::<u64>().test_properties(|(x, n)| {
let p = x.clone().pow(n);
assert!(p.is_valid());
let p_alt = (&x).pow(n);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(n);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let (p_alt, _) = x.pow_u_round_ref(n, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let rug_p = rug_pow_u(&rug::Float::exact_from(&x), n);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_pow_u() {
fn test<T: PrimitiveFloat>(x: T, n: u64, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_pow_u(x, n)), NiceFloat(out));
}
test::<f32>(f32::NAN, 0, 1.0);
test::<f32>(f32::NAN, 1, f32::NAN);
test::<f32>(f32::NAN, 2, f32::NAN);
test::<f32>(f32::NAN, 3, f32::NAN);
test::<f32>(f32::NAN, 4, f32::NAN);
test::<f32>(f32::INFINITY, 0, 1.0);
test::<f32>(f32::INFINITY, 1, f32::INFINITY);
test::<f32>(f32::INFINITY, 2, f32::INFINITY);
test::<f32>(f32::INFINITY, 3, f32::INFINITY);
test::<f32>(f32::INFINITY, 4, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 0, 1.0);
test::<f32>(f32::NEGATIVE_INFINITY, 1, f32::NEGATIVE_INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 2, f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 3, f32::NEGATIVE_INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, 4, f32::INFINITY);
test::<f32>(0.0, 0, 1.0);
test::<f32>(0.0, 1, 0.0);
test::<f32>(0.0, 2, 0.0);
test::<f32>(0.0, 3, 0.0);
test::<f32>(0.0, 4, 0.0);
test::<f32>(-0.0, 0, 1.0);
test::<f32>(-0.0, 1, -0.0);
test::<f32>(-0.0, 2, 0.0);
test::<f32>(-0.0, 3, -0.0);
test::<f32>(-0.0, 4, 0.0);
test::<f32>(1.0, 0, 1.0);
test::<f32>(1.0, 1, 1.0);
test::<f32>(1.0, 2, 1.0);
test::<f32>(1.0, 3, 1.0);
test::<f32>(1.0, 4, 1.0);
test::<f32>(-1.0, 0, 1.0);
test::<f32>(-1.0, 1, -1.0);
test::<f32>(-1.0, 2, 1.0);
test::<f32>(-1.0, 3, -1.0);
test::<f32>(-1.0, 4, 1.0);
test::<f32>(3.0, 5, 243.0);
test::<f32>(2.0, 10, 1024.0);
test::<f32>(-2.0, 3, -8.0);
test::<f32>(1.1, 2, 1.21);
test::<f32>(2.0, 200, f32::INFINITY);
test::<f32>(0.5, 200, 0.0);
test::<f64>(3.0, 5, 243.0);
test::<f64>(-2.0, 3, -8.0);
test::<f64>(1.1, 2, 1.2100000000000002);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_pow_u_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_1::<T, u64>().test_properties(|(x, n)| {
primitive_float_pow_u::<T>(x, n);
});
}
#[test]
fn primitive_float_pow_u_properties() {
apply_fn_to_primitive_floats!(primitive_float_pow_u_properties_helper);
}
#[test]
fn test_pow_s() {
let test = |s, s_hex, n: i64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (p, o) = x.pow_s_prec_round(n, 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);
};
test(
"3.0",
"0x3.0#2",
0,
10,
Nearest,
"1.0000",
"0x1.000#10",
Equal,
);
test(
"3.0",
"0x3.0#2",
1,
10,
Nearest,
"3.0000",
"0x3.00#10",
Equal,
);
test(
"3.0",
"0x3.0#2",
5,
20,
Nearest,
"243.00000",
"0xf3.000#20",
Equal,
);
test("3.0", "0x3.0#2", 5, 2, Floor, "1.9e2", "0xc.0E+1#2", Less);
test(
"3.0",
"0x3.0#2",
5,
2,
Ceiling,
"2.6e2",
"0x1.0E+2#2",
Greater,
);
test(
"-2.0",
"-0x2.0#1",
3,
10,
Nearest,
"-8.0000",
"-0x8.00#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
4,
10,
Nearest,
"16.000",
"0x10.00#10",
Equal,
);
test(
"2.0",
"0x2.0#1",
-3,
10,
Nearest,
"0.12500",
"0x0.200#10",
Equal,
);
test(
"3.0",
"0x3.0#2",
-2,
10,
Floor,
"0.11108",
"0x0.1c70#10",
Less,
);
test(
"3.0",
"0x3.0#2",
-2,
10,
Ceiling,
"0.11121",
"0x0.1c78#10",
Greater,
);
test(
"-2.0",
"-0x2.0#2",
-3,
10,
Nearest,
"-0.12500",
"-0x0.200#10",
Equal,
);
test(
"-2.0",
"-0x2.0#2",
-4,
10,
Nearest,
"0.062500",
"0x0.1000#10",
Equal,
);
test(
"1.50",
"0x1.8#4",
-10,
20,
Nearest,
"0.017341524",
"0x0.04707e8#20",
Less,
);
test(
"-3.0",
"-0x3.0#2",
-1,
10,
Nearest,
"-0.33350",
"-0x0.556#10",
Less,
);
test(
"4.0",
"0x4.0#1",
-3,
5,
Nearest,
"0.0156",
"0x0.040#5",
Equal,
);
test(
"2.0",
"0x2.0#3",
-100000000000,
5,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
"0.50",
"0x0.8#3",
-100000000000,
5,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
"0.50",
"0x0.8#3",
-100000000000,
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
}
#[test]
fn test_pow_s_special_values() {
let test = |base: Float, n: i64, out: &str, out_hex: &str| {
let (p, o) = base.pow_s_prec_round(n, 1, Nearest);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, Equal);
};
test(Float::NAN, 0, "1.0", "0x1.0#1");
test(Float::NAN, 1, "NaN", "NaN");
test(Float::NAN, 2, "NaN", "NaN");
test(Float::NAN, 3, "NaN", "NaN");
test(Float::NAN, -1, "NaN", "NaN");
test(Float::NAN, -2, "NaN", "NaN");
test(Float::NAN, -3, "NaN", "NaN");
test(Float::INFINITY, 0, "1.0", "0x1.0#1");
test(Float::INFINITY, 1, "Infinity", "Infinity");
test(Float::INFINITY, 2, "Infinity", "Infinity");
test(Float::INFINITY, 3, "Infinity", "Infinity");
test(Float::INFINITY, -1, "0.0", "0x0.0");
test(Float::INFINITY, -2, "0.0", "0x0.0");
test(Float::INFINITY, -3, "0.0", "0x0.0");
test(Float::NEGATIVE_INFINITY, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_INFINITY, 1, "-Infinity", "-Infinity");
test(Float::NEGATIVE_INFINITY, 2, "Infinity", "Infinity");
test(Float::NEGATIVE_INFINITY, 3, "-Infinity", "-Infinity");
test(Float::NEGATIVE_INFINITY, -1, "-0.0", "-0x0.0");
test(Float::NEGATIVE_INFINITY, -2, "0.0", "0x0.0");
test(Float::NEGATIVE_INFINITY, -3, "-0.0", "-0x0.0");
test(Float::ZERO, 0, "1.0", "0x1.0#1");
test(Float::ZERO, 1, "0.0", "0x0.0");
test(Float::ZERO, 2, "0.0", "0x0.0");
test(Float::ZERO, 3, "0.0", "0x0.0");
test(Float::ZERO, -1, "Infinity", "Infinity");
test(Float::ZERO, -2, "Infinity", "Infinity");
test(Float::ZERO, -3, "Infinity", "Infinity");
test(Float::NEGATIVE_ZERO, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ZERO, 1, "-0.0", "-0x0.0");
test(Float::NEGATIVE_ZERO, 2, "0.0", "0x0.0");
test(Float::NEGATIVE_ZERO, 3, "-0.0", "-0x0.0");
test(Float::NEGATIVE_ZERO, -1, "-Infinity", "-Infinity");
test(Float::NEGATIVE_ZERO, -2, "Infinity", "Infinity");
test(Float::NEGATIVE_ZERO, -3, "-Infinity", "-Infinity");
test(Float::ONE, 0, "1.0", "0x1.0#1");
test(Float::ONE, 1, "1.0", "0x1.0#1");
test(Float::ONE, 2, "1.0", "0x1.0#1");
test(Float::ONE, 3, "1.0", "0x1.0#1");
test(Float::ONE, -1, "1.0", "0x1.0#1");
test(Float::ONE, -2, "1.0", "0x1.0#1");
test(Float::ONE, -3, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 0, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 1, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, 2, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, 3, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, -1, "-1.0", "-0x1.0#1");
test(Float::NEGATIVE_ONE, -2, "1.0", "0x1.0#1");
test(Float::NEGATIVE_ONE, -3, "-1.0", "-0x1.0#1");
}
#[test]
fn test_pow_s_extreme() {
let max_e = i64::from(Float::MAX_EXPONENT);
let min_e = i64::from(Float::MIN_EXPONENT);
let test = |base: Float, n: i64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let (p, o) = base.pow_s_prec_round(n, 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);
};
test(
Float::power_of_2(min_e),
-1,
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
Float::power_of_2(max_e - 1),
-2,
10,
Nearest,
"0.0",
"0x0.0",
Less,
);
test(
Float::power_of_2(max_e - 1),
-2,
5,
Up,
"2.38e-323228497",
"0x1.0E-268435456#5",
Greater,
);
test(
-Float::power_of_2(min_e),
-1,
10,
Nearest,
"-Infinity",
"-Infinity",
Less,
);
test(
Float::power_of_2(min_e),
-3,
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
}
#[allow(clippy::needless_pass_by_value)]
fn pow_s_prec_round_properties_helper(
x: Float,
n: i64,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = x.pow_s_prec_round_ref(n, prec, Nearest);
if o == Equal {
let (pe, oe) = x.pow_s_prec_round_ref(n, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.pow_s_prec_round_ref(n, prec, Exact));
}
return;
}
let (p, o) = x.clone().pow_s_prec_round(n, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_s_prec_round_ref(n, 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.pow_s_prec_round_assign(n, prec, rm);
assert!(x_alt.is_valid());
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (pi, oi) = x.pow_integer_prec_round_ref_ref(&Integer::from(n), prec, rm);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_pow_s_prec_round(&rug::Float::exact_from(&x), n, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn pow_s_prec_round_properties() {
float_signed_unsigned_rounding_mode_quadruple_gen_var_11().test_properties(
|(x, n, prec, rm)| {
pow_s_prec_round_properties_helper(x, n, prec, rm, false);
},
);
float_signed_unsigned_rounding_mode_quadruple_gen_var_12().test_properties(
|(x, n, prec, rm)| {
pow_s_prec_round_properties_helper(x, n, prec, rm, true);
},
);
}
#[test]
fn pow_s_prec_properties() {
float_signed_unsigned_triple_gen_var_1::<i64, u64>().test_properties(|(x, n, prec)| {
let (p, o) = x.clone().pow_s_prec(n, prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_s_prec_ref(n, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_s_prec_round_ref(n, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (pi, oi) = x.pow_integer_prec_ref_ref(&Integer::from(n), prec);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
let (rug_p, rug_o) = rug_pow_s_prec(&rug::Float::exact_from(&x), n, prec);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
});
}
#[test]
fn pow_s_round_properties() {
float_signed_pair_gen::<i64>().test_properties(|(x, n)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().pow_s_round(n, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.pow_s_round_ref(n, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut x_alt = x.clone();
let o_alt = x_alt.pow_s_round_assign(n, rm);
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_pow_s_round(&rug::Float::exact_from(&x), n, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
}
});
}
#[test]
fn pow_s_properties() {
float_signed_pair_gen::<i64>().test_properties(|(x, n)| {
let p = x.clone().pow(n);
assert!(p.is_valid());
let p_alt = (&x).pow(n);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut x_alt = x.clone();
x_alt.pow_assign(n);
assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&p));
let (p_alt, _) = x.pow_s_round_ref(n, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let rug_p = rug_pow_s(&rug::Float::exact_from(&x), n);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
});
}
#[test]
fn test_unsigned_pow_unsigned() {
let test = |x: u64, y: u64, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let (p, o) = Float::unsigned_pow_unsigned_prec_round(x, y, 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);
};
test(0, 0, 10, Nearest, "1.0000", "0x1.000#10", Equal);
test(5, 0, 10, Nearest, "1.0000", "0x1.000#10", Equal);
test(5, 1, 10, Nearest, "5.0000", "0x5.00#10", Equal);
test(5, 1, 2, Nearest, "4.0", "0x4.0#2", Less);
test(0, 3, 10, Nearest, "0.0", "0x0.0", Equal);
test(1, 100, 10, Nearest, "1.0000", "0x1.000#10", Equal);
test(2, 10, 20, Nearest, "1024.0000", "0x400.000#20", Equal);
test(3, 5, 20, Nearest, "243.00000", "0xf3.000#20", Equal);
test(10, 3, 20, Nearest, "1000.0000", "0x3e8.000#20", Equal);
test(3, 5, 2, Floor, "1.9e2", "0xc.0E+1#2", Less);
test(3, 5, 2, Ceiling, "2.6e2", "0x1.0E+2#2", Greater);
test(
7,
20,
30,
Nearest,
"7.9792266289e16",
"0x1.1b7aa4b8E+14#30",
Less,
);
test(
12,
24,
200,
Nearest,
"79496847203390844133441536.000000000000000000000000000000000000",
"0x41c21cb8e1000000000000.00000000000000000000000000000#200",
Equal,
);
test(3, 1000000000, 5, Nearest, "Infinity", "Infinity", Greater);
test(
3,
1000000000,
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
test(2, 10000000000, 10, Nearest, "Infinity", "Infinity", Greater);
test(3, 6, 1, Down, "5.1e2", "0x2.0E+2#1", Less);
test(263, 15, 1, Nearest, "1.3e36", "0x1.0E+30#1", Less);
test(281, 6, 2, Nearest, "4.2e14", "0x1.8E+12#2", Less);
test(205, 63, 4, Down, "4.06e145", "0xd.0E+120#4", Less);
test(205, 63, 4, Nearest, "4.37e145", "0xe.0E+120#4", Greater);
test(410, 63, 4, Floor, "3.74e164", "0x6.8E+136#4", Less);
}
fn u64_as_float(k: u64) -> Float {
Float::from_unsigned_prec(k, k.significant_bits().max(1)).0
}
#[test]
fn unsigned_pow_unsigned_prec_round_properties() {
unsigned_unsigned_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(x, y, prec, rm)| {
if rm == Exact {
let (p, o) = Float::unsigned_pow_unsigned_prec_round(x, y, prec, Nearest);
if o == Equal {
let (pe, oe) = Float::unsigned_pow_unsigned_prec_round(x, y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(Float::unsigned_pow_unsigned_prec_round(x, y, prec, Exact));
}
return;
}
let (p, o) = Float::unsigned_pow_unsigned_prec_round(x, y, prec, rm);
assert!(p.is_valid());
let kf = u64_as_float(x);
let (pi, oi) = kf.pow_integer_prec_round_ref_ref(&Integer::from(y), prec, rm);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_pow_integer_prec_round(
&rug::Float::exact_from(&kf),
&rug::Integer::from(y),
prec,
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
},
);
}
#[test]
fn unsigned_pow_unsigned_prec_properties() {
unsigned_unsigned_unsigned_rounding_mode_quadruple_gen_var_1().test_properties(
|(x, y, prec, _)| {
let (p, o) = Float::unsigned_pow_unsigned_prec(x, y, prec);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::unsigned_pow_unsigned_prec_round(x, y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let kf = u64_as_float(x);
let (pi, oi) = kf.pow_integer_prec_ref_ref(&Integer::from(y), prec);
assert_eq!(ComparableFloatRef(&pi), ComparableFloatRef(&p));
assert_eq!(oi, o);
},
);
}
#[test]
fn test_unsigned_pow() {
let test = |x: u64, s, s_hex, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let y = parse_hex_string(s_hex);
assert_eq!(y.to_string(), s);
let (p, o) = Float::unsigned_pow_prec_round(x, y, 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);
};
test(
2,
"0.50",
"0x0.8#1",
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(
3,
"2.5",
"0x2.8#3",
53,
Nearest,
"15.588457268119896",
"0xf.96a522b1ab200#53",
Greater,
);
test(
3,
"2.5",
"0x2.8#3",
53,
Floor,
"15.588457268119894",
"0xf.96a522b1ab1f8#53",
Less,
);
test(
2,
"-1.0",
"-0x1.0#1",
10,
Nearest,
"0.50000",
"0x0.800#10",
Equal,
);
test(
10,
"-0.50",
"-0x0.8#1",
53,
Nearest,
"0.31622776601683794",
"0x0.50f44d8921243c#53",
Greater,
);
test(
3,
"5.0",
"0x5.0#3",
20,
Nearest,
"243.00000",
"0xf3.000#20",
Equal,
);
test(3, "5.0", "0x5.0#3", 2, Floor, "1.9e2", "0xc.0E+1#2", Less);
test(
2,
"1.2",
"0x1.4#3",
10,
Nearest,
"2.3789",
"0x2.61#10",
Greater,
);
test(
2,
"1.1e12",
"0x1.0E+10#1",
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(
100,
"9.1e-13",
"0x1.0E-10#1",
20,
Nearest,
"1.0000000",
"0x1.00000#20",
Less,
);
}
#[test]
fn test_unsigned_pow_special_values() {
let test = |x: u64, y: Float, out: &str, out_hex: &str| {
let (p, o) = Float::unsigned_pow_prec_round(x, y, 1, Nearest);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, Equal);
};
test(0, Float::NAN, "NaN", "NaN");
test(0, Float::INFINITY, "0.0", "0x0.0");
test(0, Float::NEGATIVE_INFINITY, "Infinity", "Infinity");
test(0, Float::ZERO, "1.0", "0x1.0#1");
test(0, Float::NEGATIVE_ZERO, "1.0", "0x1.0#1");
test(1, Float::NAN, "1.0", "0x1.0#1");
test(1, Float::INFINITY, "1.0", "0x1.0#1");
test(1, Float::NEGATIVE_INFINITY, "1.0", "0x1.0#1");
test(1, Float::ZERO, "1.0", "0x1.0#1");
test(1, Float::NEGATIVE_ZERO, "1.0", "0x1.0#1");
test(2, Float::NAN, "NaN", "NaN");
test(2, Float::INFINITY, "Infinity", "Infinity");
test(2, Float::NEGATIVE_INFINITY, "0.0", "0x0.0");
test(2, Float::ZERO, "1.0", "0x1.0#1");
test(2, Float::NEGATIVE_ZERO, "1.0", "0x1.0#1");
}
#[allow(clippy::needless_pass_by_value)]
fn unsigned_pow_prec_round_properties_helper(
y: Float,
x: u64,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = Float::unsigned_pow_prec_round_ref(x, &y, prec, Nearest);
if o == Equal {
let (pe, oe) = Float::unsigned_pow_prec_round_ref(x, &y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(Float::unsigned_pow_prec_round_ref(x, &y, prec, Exact));
}
return;
}
let (p, o) = Float::unsigned_pow_prec_round(x, y.clone(), prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::unsigned_pow_prec_round_ref(x, &y, prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let kf = u64_as_float(x);
let (pp, op) = kf.pow_prec_round_ref_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&pp), ComparableFloatRef(&p));
assert_eq!(op, o);
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_p, rug_o) = rug_pow_prec_round(
&rug::Float::exact_from(&kf),
&rug::Float::exact_from(&y),
prec,
rug_rm,
);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_p)),
ComparableFloatRef(&p)
);
assert_eq!(rug_o, o);
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn unsigned_pow_prec_round_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_11().test_properties(
|(y, x, prec, rm)| {
unsigned_pow_prec_round_properties_helper(y, x, prec, rm, false);
},
);
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_12().test_properties(
|(y, x, prec, rm)| {
unsigned_pow_prec_round_properties_helper(y, x, prec, rm, true);
},
);
}
#[test]
fn unsigned_pow_prec_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_11().test_properties(
|(y, x, prec, _)| {
let (p, o) = Float::unsigned_pow_prec(x, y.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::unsigned_pow_prec_ref(x, &y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::unsigned_pow_prec_round_ref(x, &y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
},
);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_unsigned_pow() {
fn test<T: PrimitiveFloat>(x: u64, y: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_unsigned_pow(x, y)),
NiceFloat(out)
);
}
test::<f32>(0, f32::NAN, f32::NAN);
test::<f32>(0, f32::INFINITY, 0.0);
test::<f32>(0, f32::NEGATIVE_INFINITY, f32::INFINITY);
test::<f32>(0, 0.0, 1.0);
test::<f32>(0, -0.0, 1.0);
test::<f32>(0, 0.5, 0.0);
test::<f32>(0, -1.0, f32::INFINITY);
test::<f32>(0, 2.0, 0.0);
test::<f32>(1, f32::NAN, 1.0);
test::<f32>(1, f32::INFINITY, 1.0);
test::<f32>(1, f32::NEGATIVE_INFINITY, 1.0);
test::<f32>(1, 0.0, 1.0);
test::<f32>(1, -0.0, 1.0);
test::<f32>(1, 0.5, 1.0);
test::<f32>(1, -1.0, 1.0);
test::<f32>(1, 2.0, 1.0);
test::<f32>(2, f32::NAN, f32::NAN);
test::<f32>(2, f32::INFINITY, f32::INFINITY);
test::<f32>(2, f32::NEGATIVE_INFINITY, 0.0);
test::<f32>(2, 0.0, 1.0);
test::<f32>(2, -0.0, 1.0);
test::<f32>(2, 0.5, std::f32::consts::SQRT_2);
test::<f32>(2, -1.0, 0.5);
test::<f32>(2, 2.0, 4.0);
test::<f32>(3, 2.5, 15.588457);
test::<f32>(10, -0.5, 0.31622776);
test::<f32>(2, 200.0, f32::INFINITY);
test::<f32>(2, -200.0, 0.0);
test::<f32>(2, -140.0, 7.17e-43);
test::<f32>(3, -80.0, 6.765496e-39);
test::<f32>(3, -80.5, 3.90606e-39);
test::<f64>(2, -1060.0, 8.095e-320);
test::<f64>(3, -660.5, 7.26793875e-316);
test::<f64>(2, 0.5, std::f64::consts::SQRT_2);
test::<f64>(3, 2.5, 15.588457268119896);
test::<f64>(2, -1.0, 0.5);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_unsigned_pow_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_1::<T, u64>().test_properties(|(y, x)| {
primitive_float_unsigned_pow::<T>(x, y);
});
primitive_float_unsigned_pair_gen_var_4::<T, u64>().test_properties(|(y, x)| {
primitive_float_unsigned_pow::<T>(x, y);
});
}
#[test]
fn primitive_float_unsigned_pow_properties() {
apply_fn_to_primitive_floats!(primitive_float_unsigned_pow_properties_helper);
}
#[test]
fn test_unsigned_pow_rational() {
let test = |x: u64, s: &str, prec: u64, rm, out: &str, out_hex: &str, o_out| {
let q = Rational::from_str(s).unwrap();
let (p, o) = Float::unsigned_pow_rational_prec_round(x, q, 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);
};
test(8, "1/3", 20, Nearest, "2.0000000", "0x2.00000#20", Equal);
test(27, "1/3", 20, Floor, "3.0000000", "0x3.00000#20", Equal);
test(9, "1/2", 20, Nearest, "3.0000000", "0x3.00000#20", Equal);
test(16, "3/4", 20, Nearest, "8.0000000", "0x8.0000#20", Equal);
test(4, "-1/2", 20, Nearest, "0.50000000", "0x0.80000#20", Equal);
test(
1000000,
"1/3",
20,
Nearest,
"100.00000",
"0x64.0000#20",
Equal,
);
test(
64,
"5/6",
30,
Nearest,
"32.000000000",
"0x20.000000#30",
Equal,
);
test(
2,
"1/2",
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(8, "2/3", 20, Nearest, "4.0000000", "0x4.00000#20", Equal);
test(2, "-1", 10, Nearest, "0.50000", "0x0.800#10", Equal);
test(4, "1/3", 30, Floor, "1.5874010511", "0x1.965fea50#30", Less);
test(
3,
"1/2",
53,
Nearest,
"1.7320508075688772",
"0x1.bb67ae8584caa#53",
Less,
);
test(
5,
"2/3",
53,
Nearest,
"2.9240177382128660",
"0x2.ec8c6d2e8c538#53",
Less,
);
test(
7,
"-3/5",
30,
Nearest,
"0.31112948898",
"0x0.4fa62ea4#30",
Less,
);
test(3, "1/2", 2, Floor, "1.5", "0x1.8#2", Less);
test(3, "1/2", 2, Ceiling, "2.0", "0x2.0#2", Greater);
test(5, "3", 20, Nearest, "125.00000", "0x7d.0000#20", Equal);
test(2, "10", 20, Nearest, "1024.0000", "0x400.000#20", Equal);
test(
2,
"1000000000000",
10,
Nearest,
"Infinity",
"Infinity",
Greater,
);
test(2, "-1000000000000", 10, Nearest, "0.0", "0x0.0", Less);
test(
3,
"5000000000/7",
5,
Down,
"2.03e323228496",
"0x7.cE+268435455#5",
Less,
);
test(8, "1/3", 20, Exact, "2.0000000", "0x2.00000#20", Equal);
test(
27,
"1/3",
30,
Exact,
"3.0000000000",
"0x3.0000000#30",
Equal,
);
test(
3,
"1/18446744073709551617",
20,
Nearest,
"1.0000000",
"0x1.00000#20",
Less,
);
test(
3,
"-1/18446744073709551617",
20,
Nearest,
"1.0000000",
"0x1.00000#20",
Greater,
);
test(
10,
"3/36028797018963968",
53,
Floor,
"1.0000000000000000",
"0x1.0000000000000#53",
Less,
);
test(
10,
"3/36028797018963968",
53,
Ceiling,
"1.0000000000000002",
"0x1.0000000000001#53",
Greater,
);
test(
10,
"3/36028797018963968",
53,
Nearest,
"1.0000000000000002",
"0x1.0000000000001#53",
Greater,
);
test(
10,
"-3/36028797018963968",
53,
Nearest,
"0.99999999999999978",
"0x0.fffffffffffff0#53",
Less,
);
test(
7,
"-3/73786976294838206464",
64,
Nearest,
"0.999999999999999999946",
"0x0.ffffffffffffffff#64",
Greater,
);
test(
1000000,
"3/4503599627370496",
50,
Nearest,
"1.0000000000000089",
"0x1.0000000000028#50",
Less,
);
let q = Rational::ONE + (Rational::ONE >> 300u32);
let (p, o) = Float::unsigned_pow_rational_prec_round(6, q.clone(), 53, Floor);
assert_eq!(p.to_string(), "6.0000000000000000");
assert_eq!(to_hex_string(&p), "0x6.0000000000000#53");
assert_eq!(o, Less);
let (p, o) = Float::unsigned_pow_rational_prec_round(6, q, 53, Ceiling);
assert_eq!(p.to_string(), "6.0000000000000009");
assert_eq!(to_hex_string(&p), "0x6.0000000000004#53");
assert_eq!(o, Greater);
}
#[test]
fn test_unsigned_pow_rational_special_values() {
let test = |x: u64, s: &str, out: &str, out_hex: &str| {
let q = Rational::from_str(s).unwrap();
let (p, o) = Float::unsigned_pow_rational_prec_round(x, q, 1, Nearest);
assert!(p.is_valid());
assert_eq!(p.to_string(), out);
assert_eq!(to_hex_string(&p), out_hex);
assert_eq!(o, Equal);
};
test(0, "0", "1.0", "0x1.0#1");
test(0, "1", "0.0", "0x0.0");
test(0, "-1", "Infinity", "Infinity");
test(0, "1/2", "0.0", "0x0.0");
test(0, "-2", "Infinity", "Infinity");
test(1, "0", "1.0", "0x1.0#1");
test(1, "1", "1.0", "0x1.0#1");
test(1, "-1", "1.0", "0x1.0#1");
test(1, "1/2", "1.0", "0x1.0#1");
test(1, "-2", "1.0", "0x1.0#1");
test(2, "0", "1.0", "0x1.0#1");
test(2, "1", "2.0", "0x2.0#1");
test(2, "-1", "0.50", "0x0.8#1");
test(2, "-2", "0.25", "0x0.4#1");
}
#[allow(clippy::needless_pass_by_value)]
fn unsigned_pow_rational_prec_round_properties_helper(
q: Rational,
k: u64,
prec: u64,
rm: RoundingMode,
extreme: bool,
) {
if rm == Exact {
let (p, o) = Float::unsigned_pow_rational_prec_round_ref(k, &q, prec, Nearest);
if o == Equal {
let (pe, oe) = Float::unsigned_pow_rational_prec_round_ref(k, &q, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(Float::unsigned_pow_rational_prec_round_ref(
k, &q, prec, Exact
));
}
return;
}
let (p, o) = Float::unsigned_pow_rational_prec_round_ref(k, &q, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::unsigned_pow_rational_prec_round(k, q.clone(), prec, rm);
assert!(p_alt.is_valid());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if q.denominator_ref().is_power_of_2()
&& q.numerator_ref().significant_bits() < 4096
&& q.denominator_ref().significant_bits() < 4096
{
let yf = Float::exact_from(&q);
let (pr, or) = Float::rational_pow_prec_round_ref_val(&Rational::from(k), yf, prec, rm);
assert_eq!(ComparableFloatRef(&pr), ComparableFloatRef(&p));
assert_eq!(or, o);
}
let k_perfect_power = u64::try_from(q.denominator_ref())
.ok()
.and_then(|b| k.checked_root(b))
.is_some();
if k >= 2
&& !k_perfect_power
&& let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
{
let (rp, ro) = rug_unsigned_pow_rational_prec_round(k, &q, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rp)),
ComparableFloatRef(&p)
);
assert_eq!(ro, o);
}
if p.is_normal() && !extreme {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn unsigned_pow_rational_prec_round_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_2().test_properties(
|(q, k, prec, rm)| {
unsigned_pow_rational_prec_round_properties_helper(q, k, prec, rm, false);
},
);
}
#[test]
fn unsigned_pow_rational_prec_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_2().test_properties(
|(q, k, prec, _)| {
let (p, o) = Float::unsigned_pow_rational_prec(k, q.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::unsigned_pow_rational_prec_ref(k, &q, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::unsigned_pow_rational_prec_round_ref(k, &q, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
},
);
}
#[test]
fn test_pow_integer_overflow_window_regression() {
let z = (1u64 << 30) + 1;
let t = (Rational::from(Float::MAX_EXPONENT) + (Rational::ONE >> 40u32)) / Rational::from(z);
let x = Float::power_of_2_rational_prec_round(t, 200, Ceiling).0;
let (v, o) = x.pow_integer_prec_round_ref_val(Integer::from(z), 53, Nearest);
assert!(v.is_infinite());
assert_eq!(o, Greater);
let (v, o) = x.pow_integer_prec_round_ref_val(Integer::from(z), 53, Floor);
assert!(!v.is_infinite());
assert_eq!(v.get_exponent(), Some(Float::MAX_EXPONENT));
assert_eq!(o, Less);
}
#[test]
fn test_pow_general_tiny_product_regression() {
let min_exp = i64::from(Float::MIN_EXPONENT);
let xk = u64::exact_from(-(min_exp + 300));
let x = Float::from_rational_prec(Rational::ONE - (Rational::ONE >> xk), xk).0;
let y = Float::power_of_2(-302i64);
let (v, o) = Float::pow_prec_round_ref_ref(&x, &y, 301, Nearest);
assert_eq!(v, 1u32);
assert_eq!(o, Greater);
let (v, o) = Float::pow_prec_round_ref_ref(&x, &y, 301, Floor);
assert!(v < 1u32);
assert_eq!(o, Less);
let s29 = 1u64 << 29;
let x = Float::from_rational_prec(Rational::ONE + (Rational::ONE >> s29), s29 + 1).0;
let y = Float::power_of_2(-(1i64 << 29) - 2);
let (v, o) = Float::pow_prec_round_ref_ref(&x, &y, 1u64 << 30, Nearest);
assert_eq!(v, 1u32);
assert_eq!(o, Less);
}
#[test]
fn test_pow_near_one_fast_path() {
let xp = Float::one_prec(2)
.add_prec(Float::power_of_2(-100i64), 101)
.0;
let xm = Float::one_prec(2)
.add_prec(-Float::power_of_2(-100i64), 101)
.0;
let test = |v: (Float, Ordering), out: &str, out_hex: &str, o_out| {
assert!(v.0.is_valid());
assert_eq!(v.0.to_string(), out);
assert_eq!(to_hex_string(&v.0), out_hex);
assert_eq!(v.1, o_out);
};
test(
xp.pow_u_prec_round_ref(3, 53, Floor),
"1.0000000000000000",
"0x1.0000000000000#53",
Less,
);
test(
xp.pow_u_prec_round_ref(3, 53, Ceiling),
"1.0000000000000002",
"0x1.0000000000001#53",
Greater,
);
test(
xp.pow_u_prec_round_ref(3, 53, Nearest),
"1.0000000000000000",
"0x1.0000000000000#53",
Less,
);
test(
xm.pow_u_prec_round_ref(65535, 53, Floor),
"0.99999999999999989",
"0x0.fffffffffffff8#53",
Less,
);
test(
xm.pow_u_prec_round_ref(65535, 53, Nearest),
"1.0000000000000000",
"0x1.0000000000000#53",
Greater,
);
test(
xp.pow_integer_prec_round_ref_ref(&-Integer::from(1000), 53, Floor),
"0.99999999999999989",
"0x0.fffffffffffff8#53",
Less,
);
test(
xp.pow_integer_prec_round_ref_ref(&-Integer::from(1000), 53, Nearest),
"1.0000000000000000",
"0x1.0000000000000#53",
Greater,
);
test(
(-xp.clone()).pow_u_prec_round_ref(3, 53, Floor),
"-1.0000000000000002",
"-0x1.0000000000001#53",
Less,
);
test(
(-xp.clone()).pow_u_prec_round_ref(3, 53, Nearest),
"-1.0000000000000000",
"-0x1.0000000000000#53",
Greater,
);
test(
(-xm.clone()).pow_integer_prec_round_ref_ref(&-Integer::from(999), 53, Nearest),
"-1.0000000000000000",
"-0x1.0000000000000#53",
Greater,
);
test(
xp.pow_u_prec_round_ref(3, 150, Nearest),
"1.0000000000000000000000000000023665827156630354",
"0x1.00000000000000000000000030000000000000#150",
Less,
);
test(
xp.pow_integer_prec_round_ref_ref(&-Integer::from(3), 150, Nearest),
"0.99999999999999999999999999999763341728433696458",
"0x0.ffffffffffffffffffffffffd0000000000000#150",
Less,
);
}
#[test]
fn test_pow_rational_prec_round() {
let test = |x_hex: &str,
a: i64,
b: u64,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out| {
let x = parse_hex_string(x_hex);
let y = Rational::from(a) / Rational::from(b);
let (p, o) = x.clone().pow_rational_prec_round(y.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) = x.clone().pow_rational_prec_round_val_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x
.clone()
.pow_rational_prec_round_ref_val(y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_prec_round_ref_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut p_assign = x.clone();
let o_assign = p_assign.pow_rational_prec_round_assign(y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
assert_eq!(o_assign, o);
let mut p_assign = x.clone();
let o_assign = p_assign.pow_rational_prec_round_assign_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
assert_eq!(o_assign, o);
};
test(
"0x2.0#2",
3,
2,
20,
Floor,
"2.8284264",
"0x2.d413c#20",
Less,
);
test(
"0x2.0#2",
3,
2,
20,
Ceiling,
"2.8284302",
"0x2.d4140#20",
Greater,
);
test(
"0x2.0#2",
3,
2,
20,
Nearest,
"2.8284264",
"0x2.d413c#20",
Less,
);
test("0x3.0#2", 5, 2, 10, Nearest, "15.594", "0xf.98#10", Greater);
test(
"0x2.0#2",
1,
2,
53,
Nearest,
"1.4142135623730951",
"0x1.6a09e667f3bcd#53",
Greater,
);
test(
"0xa.0#4",
-1,
2,
20,
Floor,
"0.31622744",
"0x0.50f448#20",
Less,
);
test(
"0xa.0#4",
-1,
2,
20,
Ceiling,
"0.31622791",
"0x0.50f450#20",
Greater,
);
test(
"0x1.8#2",
1,
2,
20,
Nearest,
"1.2247448",
"0x1.3988e#20",
Less,
);
test(
"0x8.0#4",
1,
3,
20,
Floor,
"2.0000000",
"0x2.00000#20",
Equal,
);
test(
"0x9.0#4",
1,
2,
20,
Nearest,
"3.0000000",
"0x3.00000#20",
Equal,
);
test(
"0x1b.0#5",
2,
3,
20,
Nearest,
"9.0000000",
"0x9.0000#20",
Equal,
);
test("0x4.0#3", 1, 2, 10, Nearest, "2.0000", "0x2.00#10", Equal);
test(
"0x8.0#4",
1,
3,
20,
Exact,
"2.0000000",
"0x2.00000#20",
Equal,
);
test(
"0x0.4#1",
1,
2,
30,
Nearest,
"0.50000000000",
"0x0.80000000#30",
Equal,
);
test(
"-0x2.0#2",
3,
1,
10,
Nearest,
"-8.0000",
"-0x8.00#10",
Equal,
);
test("-0x8.0#4", 1, 3, 10, Nearest, "NaN", "NaN", Equal);
}
#[test]
fn test_pow_rational_special_values() {
let test = |x: Float, a: i64, b: u64, out: &str, o_out| {
let y = Rational::from(a) / Rational::from(b);
let (p, o) = x.pow_rational_prec_round_ref_ref(&y, 10, Nearest);
assert!(p.is_valid());
assert_eq!(to_hex_string(&p), out);
assert_eq!(o, o_out);
};
for x in [Float::NAN, Float::INFINITY, Float::from(3), Float::ZERO, Float::from(-5)] {
let (p, o) = x.pow_rational_prec_round_ref_ref(&Rational::ZERO, 10, Nearest);
assert_eq!(to_hex_string(&p), "0x1.000#10");
assert_eq!(o, Equal);
}
test(Float::NAN, 1, 2, "NaN", Equal);
test(Float::INFINITY, 1, 2, "Infinity", Equal);
test(Float::INFINITY, -1, 2, "0x0.0", Equal);
test(Float::NEGATIVE_INFINITY, 1, 2, "Infinity", Equal); test(Float::NEGATIVE_INFINITY, 3, 1, "-Infinity", Equal); test(Float::NEGATIVE_INFINITY, 2, 1, "Infinity", Equal); test(Float::NEGATIVE_INFINITY, -3, 1, "-0x0.0", Equal); test(Float::ZERO, 1, 2, "0x0.0", Equal);
test(Float::ZERO, -1, 2, "Infinity", Equal);
test(Float::NEGATIVE_ZERO, 3, 1, "-0x0.0", Equal); test(Float::NEGATIVE_ZERO, -3, 1, "-Infinity", Equal);
test(Float::NEGATIVE_ZERO, 1, 2, "0x0.0", Equal); test(Float::ONE, 1, 2, "0x1.000#10", Equal);
test(Float::NEGATIVE_ONE, 3, 1, "-0x1.000#10", Equal);
test(Float::NEGATIVE_ONE, 2, 1, "0x1.000#10", Equal);
test(Float::NEGATIVE_ONE, 1, 2, "NaN", Equal); }
#[test]
fn test_pow_rational_tiny() {
let tiny = Rational::power_of_2(-100i64);
let (p, o) = Float::from(3).pow_rational_prec_round_ref_ref(&tiny, 10, Nearest);
assert_eq!(to_hex_string(&p), "0x1.000#10");
assert_eq!(o, Less);
let x = parse_hex_string("0x1.8#2"); let (p, o) = x.pow_rational_prec_round_ref_ref(&tiny, 10, Nearest);
assert_eq!(to_hex_string(&p), "0x1.000#10");
assert_eq!(o, Less);
let (p, o) = parse_hex_string("0x1.8#2").pow_rational_prec_round_ref_ref(&tiny, 10, Ceiling);
assert_eq!(to_hex_string(&p), "0x1.008#10");
assert_eq!(o, Greater);
}
#[test]
#[should_panic]
fn pow_rational_prec_round_fail_1() {
Float::from(3).pow_rational_prec_round(Rational::from_signeds(1, 2), 0, Floor);
}
#[test]
#[should_panic]
fn pow_rational_prec_round_fail_2() {
Float::from(2).pow_rational_prec_round(Rational::from_signeds(1, 2), 10, Exact);
}
#[allow(clippy::needless_pass_by_value)]
fn pow_rational_prec_round_properties_helper(x: Float, y: Rational, prec: u64, rm: RoundingMode) {
if rm == Exact {
let (p, o) = x.pow_rational_prec_round_ref_ref(&y, prec, Nearest);
if o == Equal {
let (pe, oe) = x.pow_rational_prec_round_ref_ref(&y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(x.pow_rational_prec_round_ref_ref(&y, prec, Exact));
}
return;
}
let (p, o) = x.pow_rational_prec_round_ref_ref(&y, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_rational_prec_round(y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.clone().pow_rational_prec_round_val_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_prec_round_ref_val(y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let mut p_assign = x.clone();
let o_assign = p_assign.pow_rational_prec_round_assign(y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
assert_eq!(o_assign, o);
let mut p_assign = x.clone();
let o_assign = p_assign.pow_rational_prec_round_assign_ref(&y, prec, rm);
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
assert_eq!(o_assign, o);
if y.denominator_ref().is_power_of_2() && y.significant_bits() < 1000 {
let yf = Float::exact_from(&y);
let (p_alt, o_alt) = x.pow_prec_round_ref_val(yf, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if x.is_normal()
&& x > 0u32
&& (&x).is_integer()
&& let Ok(k) = u64::try_from(&Integer::rounding_from(&x, Nearest).0)
{
let (p_alt, o_alt) = Float::unsigned_pow_rational_prec_round(k, y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if o == Equal && p.is_normal() {
for rm2 in [Floor, Ceiling, Down, Up, Nearest] {
let (p_alt, o_alt) = x.pow_rational_prec_round_ref_ref(&y, prec, rm2);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, Equal);
}
}
if x < 0u32 && x.is_normal() && !y.is_integer() {
assert!(p.is_nan());
}
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn pow_rational_prec_round_properties() {
float_rational_unsigned_rounding_mode_quadruple_gen_var_15().test_properties(
|(x, y, prec, rm)| {
pow_rational_prec_round_properties_helper(x, y, prec, rm);
},
);
}
#[test]
fn pow_rational_prec_round_properties_extreme() {
float_rational_unsigned_rounding_mode_quadruple_gen_var_16().test_properties_with_limit(
20,
|(x, y, prec, rm)| {
pow_rational_prec_round_properties_helper(x, y, prec, rm);
},
);
}
#[test]
fn pow_rational_prec_properties() {
float_rational_unsigned_triple_gen_var_1::<u64>().test_properties(|(x, y, prec)| {
let (p, o) = x.clone().pow_rational_prec(y.clone(), prec);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_rational_prec_val_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.clone().pow_rational_prec_ref_val(y.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_prec_ref_ref(&y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_prec_round_ref_ref(&y, prec, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
});
}
#[test]
fn pow_rational_round_properties() {
float_rational_pair_gen_var_1().test_properties(|(x, y)| {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let (p, o) = x.clone().pow_rational_round(y.clone(), rm);
assert!(p.is_valid());
let (p_alt, o_alt) = x.clone().pow_rational_round_val_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_round_ref_val(y.clone(), rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = x.pow_rational_round_ref_ref(&y, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if p.is_normal() {
assert_eq!(p.get_prec(), Some(x.significant_bits()));
}
}
});
}
#[test]
fn pow_rational_properties() {
float_rational_pair_gen_var_1().test_properties(|(x, y)| {
let p = (&x).pow(&y);
assert!(p.is_valid());
let p_alt = (&x).pow(y.clone());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = x.clone().pow(&y);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let p_alt = x.clone().pow(y.clone());
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
let mut p_assign = x.clone();
p_assign.pow_assign(y.clone());
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
let mut p_assign = x.clone();
p_assign.pow_assign(&y);
assert_eq!(ComparableFloatRef(&p_assign), ComparableFloatRef(&p));
let (p_alt, _) = x.pow_rational_round_ref_ref(&y, Nearest);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
#[allow(clippy::approx_constant)]
fn test_primitive_float_pow_rational() {
fn test<T: PrimitiveFloat>(x: T, s: &str, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
let y = Rational::from_str(s).unwrap();
assert_eq!(
NiceFloat(primitive_float_pow_rational(x, &y)),
NiceFloat(out)
);
}
test::<f32>(f32::NAN, "0", 1.0);
test::<f32>(f32::NAN, "1/2", f32::NAN);
test::<f32>(f32::NAN, "-1/2", f32::NAN);
test::<f32>(f32::NAN, "2", f32::NAN);
test::<f32>(f32::NAN, "-3", f32::NAN);
test::<f32>(f32::NAN, "1/3", f32::NAN);
test::<f32>(f32::NAN, "-1/3", f32::NAN);
test::<f32>(f32::INFINITY, "0", 1.0);
test::<f32>(f32::INFINITY, "1/2", f32::INFINITY);
test::<f32>(f32::INFINITY, "-1/2", 0.0);
test::<f32>(f32::INFINITY, "2", f32::INFINITY);
test::<f32>(f32::INFINITY, "-3", 0.0);
test::<f32>(f32::INFINITY, "1/3", f32::INFINITY);
test::<f32>(f32::INFINITY, "-1/3", 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, "0", 1.0);
test::<f32>(f32::NEGATIVE_INFINITY, "1/2", f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, "-1/2", 0.0);
test::<f32>(f32::NEGATIVE_INFINITY, "2", f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, "-3", -0.0);
test::<f32>(f32::NEGATIVE_INFINITY, "1/3", f32::INFINITY);
test::<f32>(f32::NEGATIVE_INFINITY, "-1/3", 0.0);
test::<f32>(0.0, "0", 1.0);
test::<f32>(0.0, "1/2", 0.0);
test::<f32>(0.0, "-1/2", f32::INFINITY);
test::<f32>(0.0, "2", 0.0);
test::<f32>(0.0, "-3", f32::INFINITY);
test::<f32>(0.0, "1/3", 0.0);
test::<f32>(0.0, "-1/3", f32::INFINITY);
test::<f32>(-0.0, "0", 1.0);
test::<f32>(-0.0, "1/2", 0.0);
test::<f32>(-0.0, "-1/2", f32::INFINITY);
test::<f32>(-0.0, "2", 0.0);
test::<f32>(-0.0, "-3", f32::NEGATIVE_INFINITY);
test::<f32>(-0.0, "1/3", 0.0);
test::<f32>(-0.0, "-1/3", f32::INFINITY);
test::<f32>(1.0, "0", 1.0);
test::<f32>(1.0, "1/2", 1.0);
test::<f32>(1.0, "-1/2", 1.0);
test::<f32>(1.0, "2", 1.0);
test::<f32>(1.0, "-3", 1.0);
test::<f32>(1.0, "1/3", 1.0);
test::<f32>(1.0, "-1/3", 1.0);
test::<f32>(-1.0, "0", 1.0);
test::<f32>(-1.0, "1/2", f32::NAN);
test::<f32>(-1.0, "-1/2", f32::NAN);
test::<f32>(-1.0, "2", 1.0);
test::<f32>(-1.0, "-3", -1.0);
test::<f32>(-1.0, "1/3", f32::NAN);
test::<f32>(-1.0, "-1/3", f32::NAN);
test::<f32>(2.0, "0", 1.0);
test::<f32>(2.0, "1/2", 1.4142135);
test::<f32>(2.0, "-1/2", 0.70710677);
test::<f32>(2.0, "2", 4.0);
test::<f32>(2.0, "-3", 0.125);
test::<f32>(2.0, "1/3", 1.2599211);
test::<f32>(2.0, "-1/3", 0.7937005);
test::<f32>(-8.0, "0", 1.0);
test::<f32>(-8.0, "1/2", f32::NAN);
test::<f32>(-8.0, "-1/2", f32::NAN);
test::<f32>(-8.0, "2", 64.0);
test::<f32>(-8.0, "-3", -0.001953125);
test::<f32>(-8.0, "1/3", f32::NAN);
test::<f32>(-8.0, "-1/3", f32::NAN);
test::<f64>(4.0, "1/2", 2.0);
test::<f64>(8.0, "1/3", 2.0);
test::<f64>(2.0, "3/2", 2.8284271247461903);
test::<f64>(4.0, "-1/2", 0.5);
test::<f64>(9.0, "1/2", 3.0);
test::<f64>(27.0, "2/3", 9.0);
test::<f64>(-8.0, "3", -512.0);
test::<f64>(3.0, "1000", f64::INFINITY);
test::<f64>(3.0, "-1000", 0.0);
test::<f32>(2.0, "3/2", 2.828427);
test::<f32>(2.0, "200", f32::INFINITY);
test::<f32>(0.5, "200", 0.0);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_pow_rational_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_primitive_float_pair_gen::<T>().test_properties(|(y, x)| {
primitive_float_pow_rational::<T>(x, &y);
});
}
#[test]
fn primitive_float_pow_rational_properties() {
apply_fn_to_primitive_floats!(primitive_float_pow_rational_properties_helper);
}
#[test]
fn test_rational_pow_rational() {
let test =
|xs: &str, ys: &str, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, o_out| {
let x = Rational::from_str(xs).unwrap();
let y = Rational::from_str(ys).unwrap();
let (p, o) = Float::rational_pow_rational_prec_round_ref(&x, &y, 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::rational_pow_rational_prec_round(x.clone(), y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if rm == Nearest {
let (p_alt, o_alt) = Float::rational_pow_rational_prec_ref(&x, &y, prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
let (p_alt, o_alt) = Float::rational_pow_rational_prec(x.clone(), y.clone(), prec);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
};
test("3/2", "0", 10, Nearest, "1.0000", "0x1.000#10", Equal);
test("0", "1/2", 10, Nearest, "0.0", "0x0.0", Equal);
test("0", "-1/2", 10, Nearest, "Infinity", "Infinity", Equal);
test("-4", "1/2", 10, Nearest, "NaN", "NaN", Equal);
test("-2", "3", 10, Nearest, "-8.0000", "-0x8.00#10", Equal);
test("-2", "2", 10, Nearest, "4.0000", "0x4.00#10", Equal);
test("1", "1/2", 10, Nearest, "1.0000", "0x1.000#10", Equal);
test("4", "1/3", 20, Floor, "1.5874004", "0x1.965fe#20", Less);
test(
"4",
"1/3",
20,
Ceiling,
"1.5874023",
"0x1.96600#20",
Greater,
);
test(
"1/2",
"1/2",
20,
Nearest,
"0.70710659",
"0x0.b504f#20",
Less,
);
test("5", "3", 10, Nearest, "125.00", "0x7d.0#10", Equal);
test("3/2", "4", 20, Nearest, "5.0625000", "0x5.10000#20", Equal);
test("3/4", "1/2", 20, Floor, "0.86602497", "0x0.ddb3d#20", Less);
test(
"3/4",
"1/2",
20,
Ceiling,
"0.86602592",
"0x0.ddb3e#20",
Greater,
);
test(
"1/9",
"-1/2",
20,
Nearest,
"3.0000000",
"0x3.00000#20",
Equal,
);
test("6/5", "1/2", 20, Floor, "1.0954437", "0x1.186f0#20", Less);
test(
"6/5",
"1/2",
20,
Ceiling,
"1.0954456",
"0x1.186f2#20",
Greater,
);
test(
"3/5",
"1/2",
20,
Nearest,
"0.77459621",
"0x0.c64bf#20",
Less,
);
test("9/5", "1/2", 20, Nearest, "1.3416405", "0x1.5775c#20", Less);
test("9/25", "1/2", 20, Floor, "0.59999943", "0x0.99999#20", Less);
test(
"9/25",
"1/2",
20,
Ceiling,
"0.60000038",
"0x0.9999a#20",
Greater,
);
test(
"9/25",
"-1/2",
20,
Nearest,
"1.6666660",
"0x1.aaaaa#20",
Less,
);
test(
"3",
"1/2",
53,
Nearest,
"1.7320508075688772",
"0x1.bb67ae8584caa#53",
Less,
);
test(
"2/3",
"1/3",
20,
Nearest,
"0.87358093",
"0x0.dfa30#20",
Greater,
);
test("9/4", "1/2", 10, Exact, "1.5000", "0x1.800#10", Equal);
test(
"3/5",
"1/1180591620717411303425",
20,
Nearest,
"1.0000000",
"0x1.00000#20",
Greater,
);
}
#[test]
#[should_panic]
fn rational_pow_rational_prec_round_fail_1() {
Float::rational_pow_rational_prec_round(
Rational::from(3),
Rational::from_signeds(1, 2),
0,
Floor,
);
}
#[test]
#[should_panic]
fn rational_pow_rational_prec_round_fail_2() {
Float::rational_pow_rational_prec_round(
Rational::from(2),
Rational::from_signeds(1, 2),
10,
Exact,
);
}
#[test]
fn test_rational_pow_rational_extreme() {
let k = 1i64 << 30;
let x = Rational::from(9) * Rational::power_of_2(k);
let (p, o) =
Float::rational_pow_rational_prec_round_ref(&x, &Rational::from_signeds(1, 2), 20, Nearest);
assert!(p.is_valid());
assert_eq!(o, Equal);
assert_eq!(p.get_prec(), Some(20));
let expected = Float::from(3) << (1i64 << 29);
assert_eq!(p, expected);
}
fn rational_pow_rational_prec_round_properties_helper(
x: &Rational,
y: &Rational,
prec: u64,
rm: RoundingMode,
) {
if rm == Exact {
let (p, o) = Float::rational_pow_rational_prec_round_ref(x, y, prec, Nearest);
if o == Equal {
let (pe, oe) = Float::rational_pow_rational_prec_round_ref(x, y, prec, Exact);
assert_eq!(ComparableFloatRef(&pe), ComparableFloatRef(&p));
assert_eq!(oe, Equal);
} else {
assert_panic!(Float::rational_pow_rational_prec_round_ref(
x, y, prec, Exact
));
}
return;
}
let (p, o) = Float::rational_pow_rational_prec_round_ref(x, y, prec, rm);
assert!(p.is_valid());
let (p_alt, o_alt) = Float::rational_pow_rational_prec_round(x.clone(), y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
if y.denominator_ref().is_power_of_2() && y.significant_bits() < 1000 {
let yf = Float::exact_from(y);
let (p_alt, o_alt) = Float::rational_pow_prec_round_ref_ref(x, &yf, prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if *x > 0u32
&& x.denominator_ref() == &1u32
&& let Ok(k) = u64::try_from(x.numerator_ref())
{
let (p_alt, o_alt) = Float::unsigned_pow_rational_prec_round(k, y.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, o);
}
if o == Equal && p.is_normal() {
for rm2 in [Floor, Ceiling, Down, Up, Nearest] {
let (p_alt, o_alt) = Float::rational_pow_rational_prec_round_ref(x, y, prec, rm2);
assert_eq!(ComparableFloatRef(&p_alt), ComparableFloatRef(&p));
assert_eq!(o_alt, Equal);
}
}
if *x < 0u32 && y.denominator_ref() != &1u32 {
assert!(p.is_nan());
}
if p.is_normal() {
assert_eq!(p.get_prec(), Some(prec));
}
}
#[test]
fn rational_pow_rational_prec_round_properties() {
rational_rational_unsigned_rounding_mode_quadruple_gen_var_3().test_properties_with_limit(
20,
|(x, y, prec, rm)| {
rational_pow_rational_prec_round_properties_helper(&x, &y, prec, rm);
},
);
}