use core::cmp::max;
use malachite_base::num::arithmetic::traits::{Average, AverageAssign, PowerOf2};
use malachite_base::num::basic::traits::{
Infinity, NaN, NegativeInfinity, NegativeZero, One, Two, Zero,
};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::num::logic::traits::SignificantBits;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_float::test_util::generators::float_float_unsigned_rounding_mode_quadruple_gen_var_15;
use malachite_float::{ComparableFloatRef, Float};
use malachite_q::Rational;
use std::cmp::Ordering::{self, *};
const MAX_POW: i64 = (1 << 30) - 2;
const MIN_POW: i64 = -(1 << 30);
fn expect(x: Float, y: Float, prec: u64, rm: RoundingMode, out: Float, o: Ordering) {
let (out, out_o) = Float::from_float_prec(out, prec);
assert_eq!(out_o, Equal);
let (a, ao) = x.clone().average_prec_round(y.clone(), prec, rm);
assert_eq!(
(ComparableFloatRef(&a), ao),
(ComparableFloatRef(&out), o),
"average({x}, {y}, {prec}, {rm})"
);
let (b, bo) = y.average_prec_round(x, prec, rm);
assert_eq!((ComparableFloatRef(&b), bo), (ComparableFloatRef(&out), o));
}
#[test]
fn test_average_extremes() {
let max_pow = Float::power_of_2(MAX_POW);
let min_pow = Float::power_of_2(MIN_POW);
for rm in [Floor, Ceiling, Down, Up, Nearest, Exact] {
expect(
max_pow.clone(),
max_pow.clone(),
10,
rm,
Float::power_of_2(MAX_POW),
Equal,
);
expect(
-max_pow.clone(),
-max_pow.clone(),
10,
rm,
-Float::power_of_2(MAX_POW),
Equal,
);
expect(
min_pow.clone(),
min_pow.clone(),
10,
rm,
Float::power_of_2(MIN_POW),
Equal,
);
expect(
max_pow.clone(),
Float::power_of_2(MAX_POW - 1),
2,
rm,
Float::power_of_2(MAX_POW - 1) * Float::from(1.5),
Equal,
);
expect(
min_pow.clone(),
Float::power_of_2(MIN_POW + 1),
2,
rm,
Float::power_of_2(MIN_POW) * Float::from(1.5),
Equal,
);
}
for rm in [Ceiling, Down, Up, Nearest] {
expect(
min_pow.clone(),
-min_pow.clone(),
10,
rm,
Float::ZERO,
Equal,
);
expect(
max_pow.clone(),
-max_pow.clone(),
10,
rm,
Float::ZERO,
Equal,
);
}
expect(
min_pow.clone(),
-min_pow.clone(),
10,
Floor,
Float::NEGATIVE_ZERO,
Equal,
);
expect(min_pow.clone(), Float::ZERO, 10, Floor, Float::ZERO, Less);
expect(min_pow.clone(), Float::ZERO, 10, Down, Float::ZERO, Less);
expect(min_pow.clone(), Float::ZERO, 10, Nearest, Float::ZERO, Less);
expect(
min_pow.clone(),
Float::ZERO,
10,
Ceiling,
Float::power_of_2(MIN_POW),
Greater,
);
expect(
min_pow.clone(),
Float::ZERO,
10,
Up,
Float::power_of_2(MIN_POW),
Greater,
);
expect(
max_pow.clone(),
min_pow.clone(),
10,
Floor,
Float::power_of_2(MAX_POW - 1),
Less,
);
expect(
max_pow.clone(),
min_pow.clone(),
10,
Nearest,
Float::power_of_2(MAX_POW - 1),
Less,
);
expect(
max_pow.clone(),
min_pow.clone(),
10,
Ceiling,
Float::power_of_2(MAX_POW - 1)
.add_prec(Float::power_of_2(MAX_POW - 10), 10)
.0,
Greater,
);
}
#[test]
fn test_average_specials() {
for rm in [Floor, Ceiling, Down, Up, Nearest] {
let f = |x: Float, y: Float| {
let (a, o) = x.clone().average_prec_round(y.clone(), 10, rm);
let (s, so) = x.add_prec_round(y, 10, rm);
assert_eq!((ComparableFloatRef(&a), o), (ComparableFloatRef(&s), so));
};
f(Float::NAN, Float::ONE);
f(Float::NAN, Float::NAN);
f(Float::INFINITY, Float::ONE);
f(Float::NEGATIVE_INFINITY, Float::ONE);
f(Float::INFINITY, Float::NEGATIVE_INFINITY);
f(Float::INFINITY, Float::INFINITY);
f(Float::ZERO, Float::ZERO);
f(Float::NEGATIVE_ZERO, Float::NEGATIVE_ZERO);
f(Float::ZERO, Float::NEGATIVE_ZERO);
}
for rm in [Floor, Ceiling, Down, Up, Nearest] {
expect(Float::ZERO, Float::TWO, 10, rm, Float::ONE, Equal);
expect(Float::NEGATIVE_ZERO, Float::TWO, 10, rm, Float::ONE, Equal);
expect(Float::ZERO, -Float::TWO, 10, rm, -Float::ONE, Equal);
}
}
#[test]
fn average_prec_round_properties() {
float_float_unsigned_rounding_mode_quadruple_gen_var_15().test_properties(
|(x, y, prec, rm)| {
let (avg, o) = x.clone().average_prec_round(y.clone(), prec, rm);
assert!(avg.is_valid());
for (a, ao) in [
x.clone().average_prec_round_val_ref(&y, prec, rm),
x.average_prec_round_ref_val(y.clone(), prec, rm),
x.average_prec_round_ref_ref(&y, prec, rm),
] {
assert_eq!(ComparableFloatRef(&a), ComparableFloatRef(&avg));
assert_eq!(ao, o);
}
let mut m = x.clone();
assert_eq!(m.average_prec_round_assign(y.clone(), prec, rm), o);
assert_eq!(ComparableFloatRef(&m), ComparableFloatRef(&avg));
let mut m = x.clone();
assert_eq!(m.average_prec_round_assign_ref(&y, prec, rm), o);
assert_eq!(ComparableFloatRef(&m), ComparableFloatRef(&avg));
if rm == Nearest {
let (a, ao) = x.clone().average_prec(y.clone(), prec);
assert_eq!(ComparableFloatRef(&a), ComparableFloatRef(&avg));
assert_eq!(ao, o);
let mut m = x.clone();
assert_eq!(m.average_prec_assign(y.clone(), prec), o);
assert_eq!(ComparableFloatRef(&m), ComparableFloatRef(&avg));
}
if prec == max(x.significant_bits(), y.significant_bits()) {
let (a, ao) = x.clone().average_round(y.clone(), rm);
assert_eq!(ComparableFloatRef(&a), ComparableFloatRef(&avg));
assert_eq!(ao, o);
let mut m = x.clone();
assert_eq!(m.average_round_assign(y.clone(), rm), o);
assert_eq!(ComparableFloatRef(&m), ComparableFloatRef(&avg));
if rm == Nearest {
assert_eq!(
ComparableFloatRef(&x.clone().average(y.clone())),
ComparableFloatRef(&avg)
);
assert_eq!(
ComparableFloatRef(&(&x).average(&y)),
ComparableFloatRef(&avg)
);
let mut m = x.clone();
m.average_assign(y.clone());
assert_eq!(ComparableFloatRef(&m), ComparableFloatRef(&avg));
}
}
let (avg_alt, o_alt) = y.clone().average_prec_round(x.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&avg_alt), ComparableFloatRef(&avg));
assert_eq!(o_alt, o);
if avg.is_finite() && avg != 0u32 {
assert_eq!(avg.get_prec(), Some(prec));
}
if x.is_nan() || y.is_nan() {
assert!(avg.is_nan());
return;
}
let moderate = |f: &Float| f.get_exponent().is_none_or(|e| e.unsigned_abs() < 1000);
if x.is_finite() && y.is_finite() && moderate(&x) && moderate(&y) {
let q = (Rational::exact_from(&x) + Rational::exact_from(&y)) >> 1u64;
if q == 0u32 {
assert_eq!(avg, 0u32);
assert_eq!(o, Equal);
} else {
let (e, eo) = Float::from_rational_prec_round(q.clone(), prec, rm);
assert_eq!(ComparableFloatRef(&avg), ComparableFloatRef(&e));
assert_eq!(o, eo);
assert_eq!(Rational::exact_from(&avg).cmp(&q), o);
}
let (lo, hi) = if x <= y { (&x, &y) } else { (&y, &x) };
assert!(q >= Rational::exact_from(lo));
assert!(q <= Rational::exact_from(hi));
}
if o == Equal && avg != 0u32 {
for rm_alt in [Floor, Ceiling, Down, Up, Nearest, Exact] {
let (avg_alt, o_alt) = x.clone().average_prec_round(y.clone(), prec, rm_alt);
assert_eq!(ComparableFloatRef(&avg_alt), ComparableFloatRef(&avg));
assert_eq!(o_alt, Equal);
}
}
if avg != 0u32 {
let (neg, neg_o) = (-x).average_prec_round(-y, prec, -rm);
assert_eq!(ComparableFloatRef(&neg), ComparableFloatRef(&-avg));
assert_eq!(neg_o, o.reverse());
}
},
);
}