use core::cmp::Ordering::{self, *};
use malachite_base::num::arithmetic::traits::{Asec, AsecAssign, IsPowerOf2, PowerOf2, Reciprocal};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::traits::{
Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, OneHalf, Two, Zero,
};
use malachite_base::num::comparison::traits::{EqAbs, PartialOrdAbs};
use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
use malachite_base::num::float::NiceFloat;
use malachite_base::num::logic::traits::SignificantBits;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_base::rounding_modes::exhaustive::exhaustive_rounding_modes;
use malachite_base::test_util::generators::{
primitive_float_gen, primitive_float_gen_var_1, primitive_float_unsigned_pair_gen_var_1,
unsigned_rounding_mode_pair_gen_var_3,
};
use malachite_float::float::arithmetic::asec::{
primitive_float_asec, primitive_float_asec_pi, primitive_float_asec_pi_rational,
primitive_float_asec_rational, primitive_float_asec_with_period,
primitive_float_asec_with_period_rational,
};
use malachite_float::test_util::common::{
assert_rounding_ordering_consistent, parse_hex_string, rug_round_try_from_rounding_mode,
to_hex_string,
};
use malachite_float::test_util::float::arithmetic::asec::{
rug_asec, rug_asec_prec_round, rug_asec_rational_prec_round, rug_asec_with_period_prec_round,
rug_asec_with_period_rational_prec_round,
};
use malachite_float::test_util::generators::{
float_gen, float_rounding_mode_pair_gen_var_50, float_unsigned_pair_gen_var_1,
float_unsigned_pair_gen_var_2, float_unsigned_rounding_mode_triple_gen_var_45,
float_unsigned_rounding_mode_triple_gen_var_46, float_unsigned_rounding_mode_triple_gen_var_47,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_25,
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_26,
float_unsigned_unsigned_triple_gen_var_1, rational_unsigned_rounding_mode_triple_gen_var_12,
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_9,
};
use malachite_float::{ComparableFloat, ComparableFloatRef, Float};
use malachite_q::Rational;
use malachite_q::test_util::generators::{
rational_gen, rational_unsigned_pair_gen_var_1, rational_unsigned_pair_gen_var_3,
};
use std::panic::catch_unwind;
use std::str::FromStr;
fn acos_of_reciprocal(x: &Float, prec: u64, rm: RoundingMode) -> Option<(Float, Ordering)> {
if !x.is_finite() || *x == 0u32 || x.get_exponent().unwrap().unsigned_abs() > 1000 {
return None;
}
Some(Float::acos_rational_prec_round(
Rational::exact_from(x).reciprocal(),
prec,
rm,
))
}
#[test]
fn test_asec_prec_round() {
let test = |s: &str,
s_hex: &str,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out: Ordering| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (c, o) = x.clone().asec_prec_round(prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = x.asec_prec_round_ref(prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_prec_round_assign(prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = x.asec_prec_ref(prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Some((c_alt, o_alt)) = acos_of_reciprocal(&x, prec, rm) {
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) = rug_asec_prec_round(&rug::Float::exact_from(&x), prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("NaN", "NaN", 10, Nearest, "NaN", "NaN", Equal);
test(
"Infinity", "Infinity", 1, Nearest, "2.0", "0x2.0#1", Greater,
);
test(
"Infinity",
"Infinity",
10,
Floor,
"1.5703",
"0x1.920#10",
Less,
);
test(
"Infinity",
"Infinity",
10,
Ceiling,
"1.5723",
"0x1.928#10",
Greater,
);
test(
"-Infinity",
"-Infinity",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test("0.0", "0x0.0", 10, Exact, "NaN", "NaN", Equal);
test("-0.0", "-0x0.0", 10, Exact, "NaN", "NaN", Equal);
test("0.50", "0x0.8#1", 10, Exact, "NaN", "NaN", Equal);
test("-0.50", "-0x0.8#1", 10, Nearest, "NaN", "NaN", Equal);
test("0.99902", "0x0.ffc#10", 10, Nearest, "NaN", "NaN", Equal);
test("1.0", "0x1.0#1", 10, Exact, "0.0", "0x0.0", Equal);
test("1.0", "0x1.0#1", 1, Exact, "0.0", "0x0.0", Equal);
test("-1.0", "-0x1.0#1", 10, Floor, "3.1406", "0x3.24#10", Less);
test(
"-1.0",
"-0x1.0#1",
10,
Ceiling,
"3.1445",
"0x3.25#10",
Greater,
);
test(
"-1.0",
"-0x1.0#1",
53,
Nearest,
"3.1415926535897931",
"0x3.243f6a8885a30#53",
Less,
);
test("2.0", "0x2.0#1", 10, Floor, "1.0469", "0x1.0c0#10", Less);
test(
"2.0",
"0x2.0#1",
10,
Ceiling,
"1.0488",
"0x1.0c8#10",
Greater,
);
test("2.0", "0x2.0#1", 10, Nearest, "1.0469", "0x1.0c0#10", Less);
test(
"2.0",
"0x2.0#1",
53,
Nearest,
"1.0471975511965979",
"0x1.0c152382d7366#53",
Greater,
);
test(
"-2.0",
"-0x2.0#1",
53,
Nearest,
"2.0943951023931957",
"0x2.182a4705ae6cc#53",
Greater,
);
test(
"1.5",
"0x1.8#2",
20,
Nearest,
"0.84106827",
"0x0.d7504#20",
Less,
);
test(
"-1.5",
"-0x1.8#2",
20,
Nearest,
"2.3005257",
"0x2.4cef4#20",
Greater,
);
test(
"1.0010",
"0x1.004#11",
20,
Nearest,
"0.044176221",
"0x0.0b4f22#20",
Greater,
);
test(
"1.0010",
"0x1.004#11",
100,
Nearest,
"0.044176202487635610232666265452557",
"0x0.0b4f21b0f2247500b4ff3d6475#100",
Greater,
);
test(
"-1.0010",
"-0x1.004#11",
20,
Nearest,
"3.0974159",
"0x3.18f04#20",
Less,
);
test(
"1.60000000000000000002",
"0x1.999999999999999a#64",
64,
Nearest,
"0.895664793857864972024",
"0x0.e54a49b5cc510cd7#64",
Less,
);
test(
"1.3e30",
"0x1.0E+25#1",
20,
Nearest,
"1.5707970",
"0x1.921fc#20",
Greater,
);
test(
"-1.3e30",
"-0x1.0E+25#1",
20,
Nearest,
"1.5707970",
"0x1.921fc#20",
Greater,
);
test(
"2.6e323228495",
"0x1.0E+268435455#1",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test("-1.2", "-0x1.4#3", 2, Nearest, "2.0", "0x2.0#2", Less);
test("-1.2", "-0x1.4#3", 3, Down, "2.0", "0x2.0#3", Less);
test("-1.2", "-0x1.4#3", 3, Nearest, "2.5", "0x2.8#3", Greater);
test(
"-2.570",
"-0x2.92#9",
24,
Nearest,
"1.97040486",
"0x1.f86c74#24",
Greater,
);
}
#[test]
#[should_panic]
fn asec_prec_round_fail_1() {
Float::ONE.asec_prec_round(0, Floor);
}
#[test]
#[should_panic]
fn asec_prec_round_fail_2() {
Float::TWO.asec_prec_round(10, Exact);
}
#[test]
#[should_panic]
fn asec_prec_round_fail_3() {
Float::NEGATIVE_ONE.asec_prec_round(10, Exact);
}
#[test]
#[should_panic]
fn asec_prec_round_fail_4() {
Float::INFINITY.asec_prec_round(10, Exact);
}
#[test]
#[should_panic]
fn asec_prec_round_ref_fail() {
Float::ONE.asec_prec_round_ref(0, Floor);
}
#[test]
#[should_panic]
fn asec_prec_fail() {
Float::ONE.asec_prec(0);
}
#[test]
#[should_panic]
fn asec_round_fail() {
Float::TWO.asec_round(Exact);
}
fn asec_exact(x: &Float) -> bool {
x.is_nan() || x.lt_abs(&1u32) || *x == 1u32
}
#[allow(clippy::needless_pass_by_value)]
fn asec_prec_round_properties_helper(x: Float, prec: u64, rm: RoundingMode) {
if rm == Exact && !asec_exact(&x) {
assert_panic!(x.asec_prec_round_ref(prec, Exact));
return;
}
let (c, o) = x.clone().asec_prec_round(prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_prec_round_ref(prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_prec_round_assign(prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if let Some((c_alt, o_alt)) = acos_of_reciprocal(&x, prec, rm) {
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o, "x = {x} prec = {prec} rm = {rm:?}");
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) = rug_asec_prec_round(&rug::Float::exact_from(&x), prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
assert_eq!(c.is_nan(), x.is_nan() || x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= 0u32);
assert!(c <= Float::pi_prec_round(prec, Ceiling).0);
assert_eq!(c == 0u32, x == 1u32);
if c.is_normal() {
assert_eq!(c.get_prec(), Some(prec));
}
let w = prec + 64;
let sum = (-&x).asec_prec_ref(w).0.add_prec(x.asec_prec_ref(w).0, w).0;
let diff = sum.sub_prec(Float::pi_prec(w).0, w).0;
assert!(
diff == 0u32 || i64::from(diff.get_exponent().unwrap()) < 10 - i64::exact_from(w),
"asec(-x) + asec(x) is not pi for {x}"
);
}
if o == Equal {
assert!(asec_exact(&x));
for rm in exhaustive_rounding_modes() {
let (c2, oo) = x.asec_prec_round_ref(prec, rm);
assert_eq!(ComparableFloatRef(&c2), ComparableFloatRef(&c));
assert_eq!(oo, Equal);
}
} else {
assert_panic!(x.asec_prec_round_ref(prec, Exact));
}
}
#[test]
fn asec_prec_round_properties() {
float_unsigned_rounding_mode_triple_gen_var_45().test_properties(|(x, prec, rm)| {
asec_prec_round_properties_helper(x, prec, rm);
});
float_unsigned_rounding_mode_triple_gen_var_46().test_properties(|(x, prec, rm)| {
asec_prec_round_properties_helper(x, prec, rm);
});
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
for x in [Float::NAN, Float::ZERO, Float::NEGATIVE_ZERO, Float::ONE_HALF, -Float::ONE_HALF]
{
let (c, o) = x.asec_prec_round(prec, rm);
assert!(c.is_nan());
assert_eq!(o, Equal);
}
let (c, o) = Float::ONE.asec_prec_round(prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
if rm == Exact {
assert_panic!(Float::NEGATIVE_ONE.asec_prec_round(prec, Exact));
assert_panic!(Float::INFINITY.asec_prec_round(prec, Exact));
assert_panic!(Float::NEGATIVE_INFINITY.asec_prec_round(prec, Exact));
return;
}
let (pi, o_pi) = Float::pi_prec_round(prec, rm);
let (c, o) = Float::NEGATIVE_ONE.asec_prec_round(prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(pi.clone()));
assert_eq!(o, o_pi);
for x in [Float::INFINITY, Float::NEGATIVE_INFINITY] {
let (c, o) = x.asec_prec_round(prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(pi.clone() >> 1u32));
assert_eq!(o, o_pi);
}
});
}
#[test]
fn asec_prec_properties() {
float_unsigned_pair_gen_var_1().test_properties(|(x, prec)| {
let (c, o) = x.clone().asec_prec(prec);
assert!(c.is_valid());
let (c_alt, o_alt) = x.asec_prec_ref(prec);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_prec_round_ref(prec, Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_prec_assign(prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
}
#[test]
fn asec_round_properties() {
float_rounding_mode_pair_gen_var_50().test_properties(|(x, rm)| {
let (c, o) = x.clone().asec_round(rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_round_ref(rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_prec_round_ref(x.significant_bits(), rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_round_assign(rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
}
#[test]
fn asec_properties() {
float_gen().test_properties(|x| {
let c = x.clone().asec();
assert!(c.is_valid());
let c_alt = (&x).asec();
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let mut c_alt = x.clone();
c_alt.asec_assign();
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let (c_alt, _) = x.asec_prec_round_ref(x.significant_bits(), Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let rug_c = rug_asec(&rug::Float::exact_from(&x));
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
});
}
#[test]
#[allow(clippy::approx_constant, clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec() {
fn test<T: PrimitiveFloat>(x: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_asec(x)), NiceFloat(out));
}
test::<f32>(f32::NAN, f32::NAN);
test::<f32>(f32::INFINITY, 1.5707964);
test::<f32>(f32::NEGATIVE_INFINITY, 1.5707964);
test::<f32>(0.0, f32::NAN);
test::<f32>(-0.0, f32::NAN);
test::<f32>(0.5, f32::NAN);
test::<f32>(-0.5, f32::NAN);
test::<f32>(1.0, 0.0);
test::<f32>(-1.0, 3.1415927);
test::<f32>(1.5, 0.8410687);
test::<f32>(-1.5, 2.300524);
test::<f32>(2.0, 1.0471976);
test::<f32>(-2.0, 2.0943952);
test::<f32>(100.0, 1.5607961);
test::<f32>(1.0009766, 0.044176202);
test::<f32>(1.0e30, 1.5707964);
test::<f64>(f64::NAN, f64::NAN);
test::<f64>(f64::INFINITY, 1.5707963267948966);
test::<f64>(f64::NEGATIVE_INFINITY, 1.5707963267948966);
test::<f64>(0.0, f64::NAN);
test::<f64>(-0.0, f64::NAN);
test::<f64>(0.5, f64::NAN);
test::<f64>(-0.5, f64::NAN);
test::<f64>(1.0, 0.0);
test::<f64>(-1.0, 3.141592653589793);
test::<f64>(1.5, 0.8410686705679302);
test::<f64>(-1.5, 2.300523983021863);
test::<f64>(2.0, 1.0471975511965979);
test::<f64>(-2.0, 2.0943951023931957);
test::<f64>(100.0, 1.5607961601207294);
test::<f64>(1.0009765625, 0.04417620248763561);
test::<f64>(1.0e300, 1.5707963267948966);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_asec_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_gen::<T>().test_properties(|x| {
let c = primitive_float_asec(x);
assert_eq!(c.is_nan(), x.is_nan() || x.abs() < T::ONE);
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= T::ZERO);
let (c_float, _) = Float::asec_prec(Float::from(x), T::MANTISSA_WIDTH + 64);
assert_eq!(
NiceFloat(T::rounding_from(&c_float, Nearest).0),
NiceFloat(c)
);
}
});
}
#[test]
fn primitive_float_asec_properties() {
apply_fn_to_primitive_floats!(primitive_float_asec_properties_helper);
}
#[test]
fn test_asec_rational_prec_round() {
let test = |s: &str, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, o_out: Ordering| {
let x = Rational::from_str(s).unwrap();
let (c, o) = Float::asec_rational_prec_round(x.clone(), prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = Float::asec_rational_prec_round_ref(&x, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = Float::asec_rational_prec(x.clone(), prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_rational_prec_ref(&x, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if x != 0u32 {
let (c_alt, o_alt) = Float::acos_rational_prec_round(x.clone().reciprocal(), prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) = rug_asec_rational_prec_round(&x, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("0", 10, Exact, "NaN", "NaN", Equal);
test("1/2", 10, Exact, "NaN", "NaN", Equal);
test("-1/2", 10, Nearest, "NaN", "NaN", Equal);
test("999999/1000000", 10, Nearest, "NaN", "NaN", Equal);
test("1", 10, Exact, "0.0", "0x0.0", Equal);
test("1", 1, Exact, "0.0", "0x0.0", Equal);
test("-1", 10, Floor, "3.1406", "0x3.24#10", Less);
test("-1", 10, Ceiling, "3.1445", "0x3.25#10", Greater);
test(
"-1",
53,
Nearest,
"3.1415926535897931",
"0x3.243f6a8885a30#53",
Less,
);
test("2", 10, Floor, "1.0469", "0x1.0c0#10", Less);
test("2", 10, Ceiling, "1.0488", "0x1.0c8#10", Greater);
test("2", 10, Nearest, "1.0469", "0x1.0c0#10", Less);
test(
"2",
53,
Nearest,
"1.0471975511965979",
"0x1.0c152382d7366#53",
Greater,
);
test(
"-2",
53,
Nearest,
"2.0943951023931957",
"0x2.182a4705ae6cc#53",
Greater,
);
test("5/3", 10, Floor, "0.92676", "0x0.ed4#10", Less);
test("5/3", 10, Ceiling, "0.92773", "0x0.ed8#10", Greater);
test(
"5/3",
53,
Nearest,
"0.92729521800161219",
"0x0.ed63382b0dda78#53",
Less,
);
test(
"-5/3",
53,
Nearest,
"2.2142974355881808",
"0x2.36dc325d77c88#53",
Less,
);
test(
"1000001/1000000",
20,
Nearest,
"0.0014142133",
"0x0.005cae90#20",
Greater,
);
test(
"1000001/1000000",
100,
Nearest,
"0.0014142129731178241296276027330038",
"0x0.005cae8e78183f43b1be300096a0#100",
Less,
);
test(
"-1000001/1000000",
20,
Nearest,
"3.1401787",
"0x3.23e2c#20",
Greater,
);
test("1000000", 20, Nearest, "1.5707951", "0x1.921fa#20", Less);
test(
"-1000000",
53,
Nearest,
"1.5707973267948967",
"0x1.921fc60b3a724#53",
Greater,
);
test(
"1000000000000000000000000000001/1000000000000000000000000000000",
53,
Nearest,
"1.4142135623730951e-15",
"0x6.5e7a2ba008448E-13#53",
Greater,
);
test(
"340282366920938463463374607431768211456",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test(
"115792089237316195423570985008687907853269984665640564039457584007913129639936",
20,
Nearest,
"1.5707970",
"0x1.921fc#20",
Greater,
);
}
#[test]
#[should_panic]
fn asec_rational_prec_round_fail_1() {
Float::asec_rational_prec_round(Rational::TWO, 0, Floor);
}
#[test]
#[should_panic]
fn asec_rational_prec_round_fail_2() {
Float::asec_rational_prec_round(Rational::TWO, 10, Exact);
}
#[test]
#[should_panic]
fn asec_rational_prec_round_fail_3() {
Float::asec_rational_prec_round(Rational::NEGATIVE_ONE, 10, Exact);
}
#[test]
#[should_panic]
fn asec_rational_prec_round_ref_fail() {
Float::asec_rational_prec_round_ref(&Rational::TWO, 0, Floor);
}
#[test]
#[should_panic]
fn asec_rational_prec_fail() {
Float::asec_rational_prec(Rational::TWO, 0);
}
#[test]
fn test_asec_rational_underflow() {
let min_positive = Float::min_positive_value_prec(53);
let x = Rational::ONE + Rational::power_of_2(-((1i64 << 31) + 4));
for (rm, expected, o_out) in
[(Nearest, Float::ZERO, Less), (Ceiling, min_positive.clone(), Greater)]
{
let (c, o) = Float::asec_rational_prec_round_ref(&x, 53, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(expected), "rm = {rm:?}");
assert_eq!(o, o_out, "rm = {rm:?}");
}
let x = Rational::ONE + Rational::power_of_2(-(1i64 << 31));
let (c, o) = Float::asec_rational_prec_round_ref(&x, 53, Nearest);
assert!(c > min_positive);
assert_eq!(o, Greater);
}
fn asec_rational_exact(x: &Rational) -> bool {
x.lt_abs(&1u32) || *x == 1u32
}
#[allow(clippy::needless_pass_by_value)]
fn asec_rational_prec_round_properties_helper(x: Rational, prec: u64, rm: RoundingMode) {
if rm == Exact && !asec_rational_exact(&x) {
assert_panic!(Float::asec_rational_prec_round_ref(&x, prec, Exact));
return;
}
let (c, o) = Float::asec_rational_prec_round(x.clone(), prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = Float::asec_rational_prec_round_ref(&x, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if x != 0u32 {
let (c_alt, o_alt) = Float::acos_rational_prec_round(x.clone().reciprocal(), prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o, "x = {x} prec = {prec} rm = {rm:?}");
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) = rug_asec_rational_prec_round(&x, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
assert_eq!(c.is_nan(), x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= 0u32);
assert!(c <= Float::pi_prec_round(prec, Ceiling).0);
assert_eq!(c == 0u32, x == 1u32);
if c.is_normal() {
assert_eq!(c.get_prec(), Some(prec));
}
}
if let Ok(f) = Float::try_from(&x) {
let (c_alt, o_alt) = f.asec_prec_round(prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if o == Equal {
assert!(asec_rational_exact(&x));
for rm in exhaustive_rounding_modes() {
let (c2, oo) = Float::asec_rational_prec_round_ref(&x, prec, rm);
assert_eq!(ComparableFloatRef(&c2), ComparableFloatRef(&c));
assert_eq!(oo, Equal);
}
} else {
assert_panic!(Float::asec_rational_prec_round_ref(&x, prec, Exact));
}
}
#[test]
fn asec_rational_prec_round_properties() {
rational_unsigned_rounding_mode_triple_gen_var_12().test_properties(|(x, prec, rm)| {
asec_rational_prec_round_properties_helper(x, prec, rm);
});
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
for x in [Rational::ZERO, Rational::ONE_HALF, -Rational::ONE_HALF] {
let (c, o) = Float::asec_rational_prec_round(x, prec, rm);
assert!(c.is_nan());
assert_eq!(o, Equal);
}
let (c, o) = Float::asec_rational_prec_round(Rational::ONE, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
if rm == Exact {
assert_panic!(Float::asec_rational_prec_round(
Rational::NEGATIVE_ONE,
prec,
Exact
));
return;
}
let (pi, o_pi) = Float::pi_prec_round(prec, rm);
let (c, o) = Float::asec_rational_prec_round(Rational::NEGATIVE_ONE, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(pi));
assert_eq!(o, o_pi);
});
}
#[test]
fn asec_rational_prec_properties() {
rational_unsigned_pair_gen_var_3().test_properties(|(x, prec)| {
let (c, o) = Float::asec_rational_prec(x.clone(), prec);
assert!(c.is_valid());
let (c_alt, o_alt) = Float::asec_rational_prec_ref(&x, prec);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_rational_prec_round_ref(&x, prec, Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
}
#[test]
#[allow(clippy::approx_constant, clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec_rational() {
fn test<T: PrimitiveFloat>(s: &str, out: T)
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_asec_rational::<T>(
&Rational::from_str(s).unwrap()
)),
NiceFloat(out)
);
}
test::<f32>("0", f32::NAN);
test::<f32>("1/2", f32::NAN);
test::<f32>("-1/2", f32::NAN);
test::<f32>("1", 0.0);
test::<f32>("-1", 3.1415927);
test::<f32>("2", 1.0471976);
test::<f32>("-2", 2.0943952);
test::<f32>("5/3", 0.9272952);
test::<f32>("-5/3", 2.2142975);
test::<f32>("1000001/1000000", 0.001414213);
test::<f32>("1000000", 1.5707953);
test::<f32>("-1000000", 1.5707973);
test::<f32>(
"1000000000000000000000000000001/1000000000000000000000000000000",
1.4142135e-15,
);
test::<f64>("0", f64::NAN);
test::<f64>("1/2", f64::NAN);
test::<f64>("-1/2", f64::NAN);
test::<f64>("1", 0.0);
test::<f64>("-1", 3.141592653589793);
test::<f64>("2", 1.0471975511965979);
test::<f64>("-2", 2.0943951023931957);
test::<f64>("5/3", 0.9272952180016122);
test::<f64>("-5/3", 2.214297435588181);
test::<f64>("1000001/1000000", 0.0014142129731178241);
test::<f64>("1000000", 1.5707953267948966);
test::<f64>("-1000000", 1.5707973267948967);
test::<f64>(
"1000000000000000000000000000001/1000000000000000000000000000000",
1.414213562373095e-15,
);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_asec_rational_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
Rational: ExactFrom<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_gen().test_properties(|x| {
let c = primitive_float_asec_rational::<T>(&x);
assert_eq!(c.is_nan(), x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= T::ZERO);
let (c_float, _) = Float::asec_rational_prec_ref(&x, T::MANTISSA_WIDTH + 64);
assert_eq!(
NiceFloat(T::rounding_from(&c_float, Nearest).0),
NiceFloat(c)
);
}
});
primitive_float_gen_var_1::<T>().test_properties(|x| {
if x != T::ZERO {
assert_eq!(
NiceFloat(primitive_float_asec_rational::<T>(&Rational::exact_from(x))),
NiceFloat(primitive_float_asec(x))
);
}
});
}
#[test]
fn primitive_float_asec_rational_properties() {
apply_fn_to_primitive_floats!(primitive_float_asec_rational_properties_helper);
}
fn acosu_of_reciprocal(
x: &Float,
u: u64,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
if !x.is_finite() || *x == 0u32 || x.get_exponent().unwrap().unsigned_abs() > 1000 {
return None;
}
Some(Float::acos_with_period_rational_prec_round(
Rational::exact_from(x).reciprocal(),
u,
prec,
rm,
))
}
fn acos_of_reciprocal_huge(x: &Float, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if x.significand_ref().unwrap().is_power_of_2() {
let (r, o_r) = x.reciprocal_prec_round_ref(64, Exact);
assert_eq!(o_r, Equal);
r.acos_prec_round(prec, rm)
} else {
Float::acos_rational_prec_round(Rational::exact_from(x).reciprocal(), prec, rm)
}
}
fn acosu_of_reciprocal_huge(x: &Float, u: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if x.significand_ref().unwrap().is_power_of_2() {
let (r, o_r) = x.reciprocal_prec_round_ref(64, Exact);
assert_eq!(o_r, Equal);
r.acos_with_period_prec_round(u, prec, rm)
} else {
Float::acos_with_period_rational_prec_round(
Rational::exact_from(x).reciprocal(),
u,
prec,
rm,
)
}
}
#[test]
fn test_asec_huge() {
let test =
|s_hex: &str, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, o_out: Ordering| {
let x = parse_hex_string(s_hex);
let (c, o) = x.asec_prec_round_ref(prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = acos_of_reciprocal_huge(&x, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
};
test(
"0x1.0E+134217727#1",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test(
"0x1.0E+134217728#1",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test(
"0x1.0E+134217728#1",
53,
Floor,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test(
"0x1.0E+134217728#1",
53,
Ceiling,
"1.5707963267948968",
"0x1.921fb54442d19#53",
Greater,
);
test(
"0x4.0E+268435455#1",
20,
Nearest,
"1.5707970",
"0x1.921fc#20",
Greater,
);
test(
"0x3.0E+134217728#2",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
test(
"-0x4.0E+268435455#1",
20,
Nearest,
"1.5707970",
"0x1.921fc#20",
Greater,
);
test(
"-0x1.0E+134217728#1",
53,
Nearest,
"1.5707963267948966",
"0x1.921fb54442d18#53",
Less,
);
}
#[test]
fn test_asec_with_period_huge() {
let test = |s_hex: &str,
u: u64,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out: Ordering| {
let x = parse_hex_string(s_hex);
let (c, o) = x.asec_with_period_prec_round_ref(u, prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = acosu_of_reciprocal_huge(&x, u, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
};
test(
"0x1.0E+134217728#1",
360,
53,
Nearest,
"90.000000000000000",
"0x5a.000000000000#53",
Greater,
);
test(
"0x1.0E+134217728#1",
1,
53,
Nearest,
"0.25000000000000000",
"0x0.40000000000000#53",
Greater,
);
test(
"0x1.0E+134217728#1",
1,
53,
Ceiling,
"0.25000000000000000",
"0x0.40000000000000#53",
Greater,
);
test(
"0x1.0E+134217728#1",
1,
53,
Floor,
"0.24999999999999997",
"0x0.3ffffffffffffe#53",
Less,
);
test(
"0x4.0E+268435455#1",
1,
20,
Nearest,
"0.25000000",
"0x0.400000#20",
Greater,
);
test(
"0x3.0E+134217728#2",
360,
53,
Nearest,
"90.000000000000000",
"0x5a.000000000000#53",
Greater,
);
test(
"-0x4.0E+268435455#1",
1,
20,
Nearest,
"0.25000000",
"0x0.400000#20",
Less,
);
test(
"-0x1.0E+134217728#1",
360,
53,
Nearest,
"90.000000000000000",
"0x5a.000000000000#53",
Less,
);
}
#[test]
fn test_asec_with_period_prec_round() {
let test = |s: &str,
s_hex: &str,
u: u64,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out: Ordering| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (c, o) = x.clone().asec_with_period_prec_round(u, prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_with_period_prec_round_assign(u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = x.asec_with_period_prec_ref(u, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Some((c_alt, o_alt)) = acosu_of_reciprocal(&x, u, prec, rm) {
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
&& u <= u64::from(u32::MAX)
{
let (rug_c, rug_o) =
rug_asec_with_period_prec_round(&rug::Float::exact_from(&x), u, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("NaN", "NaN", 360, 10, Nearest, "NaN", "NaN", Equal);
test(
"Infinity",
"Infinity",
360,
10,
Exact,
"90.000",
"0x5a.0#10",
Equal,
);
test(
"-Infinity",
"-Infinity",
360,
10,
Exact,
"90.000",
"0x5a.0#10",
Equal,
);
test(
"Infinity",
"Infinity",
7,
10,
Nearest,
"1.7500",
"0x1.c00#10",
Equal,
);
test("Infinity", "Infinity", 0, 10, Exact, "0.0", "0x0.0", Equal);
test("0.0", "0x0.0", 360, 10, Exact, "NaN", "NaN", Equal);
test("-0.0", "-0x0.0", 360, 10, Exact, "NaN", "NaN", Equal);
test("0.50", "0x0.8#1", 360, 10, Exact, "NaN", "NaN", Equal);
test("0.50", "0x0.8#1", 0, 10, Exact, "NaN", "NaN", Equal);
test("1.0", "0x1.0#1", 360, 10, Exact, "0.0", "0x0.0", Equal);
test("1.0", "0x1.0#1", 0, 10, Exact, "0.0", "0x0.0", Equal);
test(
"-1.0",
"-0x1.0#1",
360,
10,
Exact,
"180.00",
"0xb4.0#10",
Equal,
);
test(
"-1.0",
"-0x1.0#1",
7,
10,
Exact,
"3.5000",
"0x3.80#10",
Equal,
);
test("-1.0", "-0x1.0#1", 7, 2, Floor, "3.0", "0x3.0#2", Less);
test(
"2.0",
"0x2.0#1",
360,
10,
Exact,
"60.000",
"0x3c.0#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
360,
10,
Exact,
"120.00",
"0x78.0#10",
Equal,
);
test(
"2.0",
"0x2.0#1",
12,
10,
Exact,
"2.0000",
"0x2.00#10",
Equal,
);
test(
"-2.0",
"-0x2.0#1",
12,
10,
Exact,
"4.0000",
"0x4.00#10",
Equal,
);
test("2.0", "0x2.0#1", 7, 10, Floor, "1.1660", "0x1.2a8#10", Less);
test(
"2.0",
"0x2.0#1",
7,
10,
Ceiling,
"1.1680",
"0x1.2b0#10",
Greater,
);
test(
"1.5",
"0x1.8#2",
360,
10,
Floor,
"48.188",
"0x30.3#10",
Less,
);
test(
"1.5",
"0x1.8#2",
360,
10,
Ceiling,
"48.250",
"0x30.4#10",
Greater,
);
test(
"1.5",
"0x1.8#2",
360,
53,
Nearest,
"48.189685104221404",
"0x30.308f33f72b56#53",
Greater,
);
test(
"-1.5",
"-0x1.8#2",
360,
53,
Nearest,
"131.81031489577859",
"0x83.cf70cc08d4a8#53",
Less,
);
test(
"1.0010",
"0x1.004#11",
360,
20,
Nearest,
"2.5311089",
"0x2.87f6c#20",
Less,
);
test(
"4.0",
"0x4.0#1",
360,
20,
Nearest,
"75.522461",
"0x4b.85c0#20",
Less,
);
test(
"-4.0",
"-0x4.0#1",
360,
20,
Nearest,
"104.47754",
"0x68.7a40#20",
Greater,
);
test(
"1.3e30",
"0x1.0E+25#1",
360,
20,
Nearest,
"90.000000",
"0x5a.0000#20",
Greater,
);
test(
"-1.3e30",
"-0x1.0E+25#1",
360,
20,
Nearest,
"90.000000",
"0x5a.0000#20",
Less,
);
test(
"1.3e30",
"0x1.0E+25#1",
1,
20,
Nearest,
"0.25000000",
"0x0.400000#20",
Greater,
);
test(
"2.6e323228495",
"0x1.0E+268435455#1",
360,
53,
Nearest,
"90.000000000000000",
"0x5a.000000000000#53",
Greater,
);
test(
"2.0",
"0x2.0#1",
18446744073709551615,
64,
Exact,
"3074457345618258602.50",
"0x2aaaaaaaaaaaaaaa.8#64",
Equal,
);
test(
"-1.0",
"-0x1.0#1",
18446744073709551615,
64,
Exact,
"9223372036854775807.50",
"0x7fffffffffffffff.8#64",
Equal,
);
test(
"Infinity",
"Infinity",
18446744073709551615,
64,
Exact,
"4611686018427387903.75",
"0x3fffffffffffffff.c#64",
Equal,
);
}
#[test]
#[should_panic]
fn asec_with_period_prec_round_fail_1() {
Float::TWO.asec_with_period_prec_round(7, 0, Floor);
}
#[test]
#[should_panic]
fn asec_with_period_prec_round_fail_2() {
Float::from(1.5).asec_with_period_prec_round(7, 10, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_prec_round_fail_3() {
Float::TWO.asec_with_period_prec_round(7, 10, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_prec_round_fail_4() {
Float::INFINITY.asec_with_period_prec_round(7, 2, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_prec_round_ref_fail() {
Float::TWO.asec_with_period_prec_round_ref(7, 0, Floor);
}
#[test]
#[should_panic]
fn asec_with_period_prec_fail() {
Float::TWO.asec_with_period_prec(7, 0);
}
#[test]
#[should_panic]
fn asec_with_period_round_fail() {
Float::from(1.5).asec_with_period_round(7, Exact);
}
fn asec_with_period_exact(x: &Float, u: u64, prec: u64) -> bool {
x.is_nan()
|| x.lt_abs(&1u32)
|| u == 0
|| *x == 1u32
|| ((!x.is_finite() || *x == -1i32) && Float::from_unsigned_prec(u, prec).1 == Equal)
|| (x.eq_abs(&Float::TWO)
&& u.is_multiple_of(3)
&& Float::from_unsigned_prec(u / 3, prec).1 == Equal)
}
#[allow(clippy::needless_pass_by_value)]
fn asec_with_period_prec_round_properties_helper(x: Float, u: u64, prec: u64, rm: RoundingMode) {
if rm == Exact && !asec_with_period_exact(&x, u, prec) {
assert_panic!(x.asec_with_period_prec_round_ref(u, prec, Exact));
return;
}
let (c, o) = x.clone().asec_with_period_prec_round(u, prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_with_period_prec_round_assign(u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if let Some((c_alt, o_alt)) = acosu_of_reciprocal(&x, u, prec, rm) {
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o, "x = {x} u = {u} prec = {prec} rm = {rm:?}");
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
&& u <= u64::from(u32::MAX)
{
let (rug_c, rug_o) =
rug_asec_with_period_prec_round(&rug::Float::exact_from(&x), u, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
assert_eq!(c.is_nan(), x.is_nan() || x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= 0u32);
assert!(c <= Float::from_unsigned_prec_round(u, prec, Ceiling).0 >> 1u32);
if c.is_normal() {
assert_eq!(c.get_prec(), Some(prec));
}
}
if o == Equal {
assert!(asec_with_period_exact(&x, u, prec));
for rm in exhaustive_rounding_modes() {
let (c2, oo) = x.asec_with_period_prec_round_ref(u, prec, rm);
assert_eq!(ComparableFloatRef(&c2), ComparableFloatRef(&c));
assert_eq!(oo, Equal);
}
} else {
assert_panic!(x.asec_with_period_prec_round_ref(u, prec, Exact));
}
}
#[test]
fn asec_with_period_prec_round_properties() {
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_25().test_properties(
|(x, u, prec, rm)| {
asec_with_period_prec_round_properties_helper(x, u, prec, rm);
},
);
float_unsigned_unsigned_rounding_mode_quadruple_gen_var_26().test_properties(
|(x, u, prec, rm)| {
asec_with_period_prec_round_properties_helper(x, u, prec, rm);
},
);
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
for x in [Float::NAN, Float::ZERO, Float::NEGATIVE_ZERO, Float::ONE_HALF] {
for u in [0, 4] {
let (c, o) = x.clone().asec_with_period_prec_round(u, prec, rm);
assert!(c.is_nan());
assert_eq!(o, Equal);
}
}
for x in [Float::ONE, Float::NEGATIVE_ONE, Float::TWO, Float::INFINITY] {
let (c, o) = x.asec_with_period_prec_round(0, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
}
let (c, o) = Float::ONE.asec_with_period_prec_round(8, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
let (q, o_q) = Float::from_unsigned_prec_round(8u32, prec, rm);
for (x, k) in
[(Float::INFINITY, 2u32), (Float::NEGATIVE_INFINITY, 2), (Float::NEGATIVE_ONE, 1)]
{
let (c, o) = x.asec_with_period_prec_round(8, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(q.clone() >> k));
assert_eq!(o, o_q);
}
let (q, o_q) = Float::from_unsigned_prec_round(4u32, prec, rm);
for (x, k) in [(Float::TWO, 1u32), (-Float::TWO, 0)] {
let (c, o) = x.asec_with_period_prec_round(12, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(q.clone() >> k));
assert_eq!(o, o_q);
}
});
}
#[test]
fn asec_with_period_prec_properties() {
float_unsigned_unsigned_triple_gen_var_1::<u64, u64>().test_properties(|(x, u, prec)| {
let (c, o) = x.clone().asec_with_period_prec(u, prec);
assert!(c.is_valid());
let (c_alt, o_alt) = x.asec_with_period_prec_ref(u, prec);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(u, prec, Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_with_period_prec_assign(u, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
}
#[test]
fn asec_with_period_round_properties() {
float_unsigned_rounding_mode_triple_gen_var_47().test_properties(|(x, u, rm)| {
if rm == Exact && !asec_with_period_exact(&x, u, x.significant_bits()) {
assert_panic!(x.asec_with_period_round_ref(u, Exact));
return;
}
let (c, o) = x.clone().asec_with_period_round(u, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_with_period_round_ref(u, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(u, x.significant_bits(), rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_with_period_round_assign(u, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
}
#[test]
fn asec_with_period_properties() {
float_unsigned_pair_gen_var_2::<u64>().test_properties(|(x, u)| {
let c = x.clone().asec_with_period(u);
assert!(c.is_valid());
let c_alt = x.asec_with_period_ref(u);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let mut c_alt = x.clone();
c_alt.asec_with_period_assign(u);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let (c_alt, _) = x.asec_with_period_prec_round_ref(u, x.significant_bits(), Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec_with_period() {
fn test<T: PrimitiveFloat>(x: T, u: u64, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_asec_with_period(x, u)),
NiceFloat(out)
);
}
test::<f32>(f32::NAN, 360, f32::NAN);
test::<f32>(f32::INFINITY, 360, 90.0);
test::<f32>(f32::NEGATIVE_INFINITY, 360, 90.0);
test::<f32>(0.0, 360, f32::NAN);
test::<f32>(0.5, 360, f32::NAN);
test::<f32>(0.5, 0, f32::NAN);
test::<f32>(1.0, 360, 0.0);
test::<f32>(1.0, 0, 0.0);
test::<f32>(-1.0, 360, 180.0);
test::<f32>(2.0, 360, 60.0);
test::<f32>(-2.0, 360, 120.0);
test::<f32>(2.0, 12, 2.0);
test::<f32>(-2.0, 12, 4.0);
test::<f32>(2.0, 7, 1.1666666);
test::<f32>(1.5, 360, 48.189686);
test::<f32>(-1.5, 360, 131.81032);
test::<f32>(100.0, 360, 89.42703);
test::<f32>(1.0e30, 360, 90.0);
test::<f32>(1.0e30, 1, 0.25);
test::<f32>(1.0, 18446744073709551615, 0.0);
test::<f64>(f64::NAN, 360, f64::NAN);
test::<f64>(f64::INFINITY, 360, 90.0);
test::<f64>(f64::NEGATIVE_INFINITY, 360, 90.0);
test::<f64>(0.0, 360, f64::NAN);
test::<f64>(0.5, 360, f64::NAN);
test::<f64>(0.5, 0, f64::NAN);
test::<f64>(1.0, 360, 0.0);
test::<f64>(1.0, 0, 0.0);
test::<f64>(-1.0, 360, 180.0);
test::<f64>(2.0, 360, 60.0);
test::<f64>(-2.0, 360, 120.0);
test::<f64>(2.0, 12, 2.0);
test::<f64>(-2.0, 12, 4.0);
test::<f64>(2.0, 7, 1.1666666666666667);
test::<f64>(1.5, 360, 48.189685104221404);
test::<f64>(-1.5, 360, 131.8103148957786);
test::<f64>(100.0, 360, 89.42703265514285);
test::<f64>(1.0e300, 360, 90.0);
test::<f64>(1.0e300, 1, 0.25);
test::<f64>(1.0, 18446744073709551615, 0.0);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_asec_with_period_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, u)| {
let c = primitive_float_asec_with_period(x, u);
assert_eq!(c.is_nan(), x.is_nan() || x.abs() < T::ONE);
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= T::ZERO);
let (c_float, _) =
Float::asec_with_period_prec(Float::from(x), u, T::MANTISSA_WIDTH + 64);
assert_eq!(
NiceFloat(T::rounding_from(&c_float, Nearest).0),
NiceFloat(c)
);
}
});
}
#[test]
fn primitive_float_asec_with_period_properties() {
apply_fn_to_primitive_floats!(primitive_float_asec_with_period_properties_helper);
}
#[test]
fn test_asec_with_period_rational_prec_round() {
let test = |s: &str,
u: u64,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out: Ordering| {
let x = Rational::from_str(s).unwrap();
let (c, o) = Float::asec_with_period_rational_prec_round(x.clone(), u, prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_round_ref(&x, u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = Float::asec_with_period_rational_prec(x.clone(), u, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_ref(&x, u, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if x != 0u32 {
let (c_alt, o_alt) =
Float::acos_with_period_rational_prec_round(x.clone().reciprocal(), u, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if !c.is_nan()
&& let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
&& u <= u64::from(u32::MAX)
{
let (rug_c, rug_o) = rug_asec_with_period_rational_prec_round(&x, u, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("0", 360, 10, Nearest, "NaN", "NaN", Equal);
test("1/2", 360, 10, Exact, "NaN", "NaN", Equal);
test("-1/2", 360, 10, Nearest, "NaN", "NaN", Equal);
test("0", 0, 10, Exact, "NaN", "NaN", Equal);
test("1/2", 0, 10, Exact, "NaN", "NaN", Equal);
test("1", 360, 10, Exact, "0.0", "0x0.0", Equal);
test("1", 0, 10, Exact, "0.0", "0x0.0", Equal);
test("1", 7, 10, Exact, "0.0", "0x0.0", Equal);
test("-1", 360, 10, Exact, "180.00", "0xb4.0#10", Equal);
test("-1", 12, 10, Exact, "6.0000", "0x6.00#10", Equal);
test("-1", 7, 10, Exact, "3.5000", "0x3.80#10", Equal);
test("-1", 7, 1, Floor, "2.0", "0x2.0#1", Less);
test("-1", 7, 1, Ceiling, "4.0", "0x4.0#1", Greater);
test("-1", 7, 1, Nearest, "4.0", "0x4.0#1", Greater);
test("2", 360, 10, Exact, "60.000", "0x3c.0#10", Equal);
test("-2", 360, 10, Exact, "120.00", "0x78.0#10", Equal);
test("2", 12, 10, Exact, "2.0000", "0x2.00#10", Equal);
test("-2", 12, 10, Exact, "4.0000", "0x4.00#10", Equal);
test("2", 3, 10, Exact, "0.50000", "0x0.800#10", Equal);
test("2", 7, 10, Nearest, "1.1660", "0x1.2a8#10", Less);
test("-2", 7, 10, Nearest, "2.3320", "0x2.55#10", Less);
test(
"3/2",
360,
20,
Nearest,
"48.189697",
"0x30.3090#20",
Greater,
);
test("-3/2", 360, 20, Nearest, "131.81030", "0x83.cf7#20", Less);
test("5/3", 360, 10, Floor, "53.125", "0x35.2#10", Less);
test("5/3", 360, 10, Ceiling, "53.188", "0x35.3#10", Greater);
test("5/3", 360, 10, Down, "53.125", "0x35.2#10", Less);
test("5/3", 360, 10, Up, "53.188", "0x35.3#10", Greater);
test("5/3", 360, 10, Nearest, "53.125", "0x35.2#10", Less);
test(
"5/3",
360,
100,
Nearest,
"53.130102354155978703144387440915",
"0x35.214e634c3b879fd3613647a0#100",
Greater,
);
test("-5/3", 360, 10, Nearest, "126.88", "0x7e.e#10", Greater);
test(
"100/99",
360,
20,
Nearest,
"8.1096191",
"0x8.1c10#20",
Greater,
);
test(
"-100/99",
360,
20,
Nearest,
"171.89038",
"0xab.e3f#20",
Less,
);
test(
"1000000/999999",
360,
100,
Nearest,
"0.081028475206513436722499131917693",
"0x0.14be483b0e855633616322e5e6#100",
Greater,
);
test("100", 360, 20, Nearest, "89.427002", "0x59.6d50#20", Less);
test(
"-100",
360,
20,
Nearest,
"90.572998",
"0x5a.92b0#20",
Greater,
);
test(
"100000000000000000000000000000000000000000",
360,
20,
Nearest,
"90.000000",
"0x5a.0000#20",
Greater,
);
test(
"100000000000000000000000000000000000000000",
1,
20,
Nearest,
"0.25000000",
"0x0.400000#20",
Greater,
);
test(
"-100000000000000000000000000000000000000000",
360,
20,
Nearest,
"90.000000",
"0x5a.0000#20",
Less,
);
test(
"100000000000000000000000000000000000000000",
360,
200,
Nearest,
"89.999999999999999999999999999999999999999427042204869176791248",
"0x59.ffffffffffffffffffffffffffffffffce169d3c4b77df1e8#200",
Greater,
);
test(
"-100000000000000000000000000000000000000000",
360,
200,
Nearest,
"90.000000000000000000000000000000000000000572957795130823208752",
"0x5a.0000000000000000000000000000000031e962c3b48820e18#200",
Less,
);
test(
"3/2",
1,
20,
Nearest,
"0.13386035",
"0x0.2244ac#20",
Greater,
);
test("1", 18446744073709551615, 64, Exact, "0.0", "0x0.0", Equal);
test(
"-1",
18446744073709551615,
64,
Exact,
"9223372036854775807.50",
"0x7fffffffffffffff.8#64",
Equal,
);
test(
"2",
18446744073709551615,
20,
Nearest,
"3.0744588e18",
"0x2.aaaacE+15#20",
Greater,
);
test(
"5/3",
18446744073709551615,
20,
Nearest,
"2.7224392e18",
"0x2.5c80cE+15#20",
Greater,
);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_round_fail_1() {
Float::asec_with_period_rational_prec_round(Rational::TWO, 7, 0, Floor);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_round_fail_2() {
Float::asec_with_period_rational_prec_round(Rational::from_unsigneds(3u8, 2), 7, 10, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_round_fail_3() {
Float::asec_with_period_rational_prec_round(Rational::TWO, 7, 10, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_round_fail_4() {
Float::asec_with_period_rational_prec_round(Rational::NEGATIVE_ONE, 7, 2, Exact);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_round_ref_fail() {
Float::asec_with_period_rational_prec_round_ref(&Rational::TWO, 7, 0, Floor);
}
#[test]
#[should_panic]
fn asec_with_period_rational_prec_fail() {
Float::asec_with_period_rational_prec(Rational::TWO, 7, 0);
}
#[test]
fn test_asec_with_period_rational_underflow() {
let x = Rational::ONE + Rational::power_of_2(-((1i64 << 31) + 4));
let (c, o) = Float::asec_with_period_rational_prec_round_ref(&x, 1, 53, Nearest);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Less);
let (c, o) = Float::asec_with_period_rational_prec_round_ref(&x, 1, 53, Ceiling);
assert_eq!(
ComparableFloat(c),
ComparableFloat(Float::min_positive_value_prec(53))
);
assert_eq!(o, Greater);
let (c, o) = Float::asec_with_period_rational_prec_round_ref(&x, 1 << 40, 53, Nearest);
assert!(c > Float::min_positive_value_prec(53));
assert_ne!(o, Equal);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_round_ref(&x, 1 << 41, 53, Nearest);
assert_eq!(ComparableFloat(c_alt), ComparableFloat(c << 1u32));
assert_eq!(o_alt, o);
}
fn asec_with_period_rational_exact(x: &Rational, u: u64, prec: u64) -> bool {
x.lt_abs(&1u32)
|| u == 0
|| *x == 1u32
|| (*x == -1i32 && Float::from_unsigned_prec(u, prec).1 == Equal)
|| (x.eq_abs(&Rational::TWO)
&& u.is_multiple_of(3)
&& Float::from_unsigned_prec(u / 3, prec).1 == Equal)
}
#[allow(clippy::needless_pass_by_value)]
fn asec_with_period_rational_prec_round_properties_helper(
x: Rational,
u: u64,
prec: u64,
rm: RoundingMode,
) {
if rm == Exact && !asec_with_period_rational_exact(&x, u, prec) {
assert_panic!(Float::asec_with_period_rational_prec_round_ref(
&x, u, prec, Exact
));
return;
}
let (c, o) = Float::asec_with_period_rational_prec_round(x.clone(), u, prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_round_ref(&x, u, prec, rm);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if x != 0u32 {
let (c_alt, o_alt) =
Float::acos_with_period_rational_prec_round(x.clone().reciprocal(), u, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o, "x = {x} u = {u} prec = {prec} rm = {rm:?}");
}
if !c.is_nan()
&& let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
&& u <= u64::from(u32::MAX)
{
let (rug_c, rug_o) = rug_asec_with_period_rational_prec_round(&x, u, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o, "x = {x} u = {u} prec = {prec} rm = {rm:?}");
}
assert_eq!(c.is_nan(), x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= 0u32);
assert!(c <= Float::from_unsigned_prec_round(u, prec, Ceiling).0 >> 1u32);
if c.is_normal() {
assert_eq!(c.get_prec(), Some(prec));
}
}
if let Ok(f) = Float::try_from(&x) {
let (c_alt, o_alt) = f.asec_with_period_prec_round(u, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if o == Equal {
assert!(asec_with_period_rational_exact(&x, u, prec));
for rm in exhaustive_rounding_modes() {
let (c2, oo) = Float::asec_with_period_rational_prec_round_ref(&x, u, prec, rm);
assert_eq!(ComparableFloatRef(&c2), ComparableFloatRef(&c));
assert_eq!(oo, Equal);
}
} else {
assert_panic!(Float::asec_with_period_rational_prec_round_ref(
&x, u, prec, Exact
));
}
}
#[test]
fn asec_with_period_rational_prec_round_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_9().test_properties(
|(x, u, prec, rm)| {
asec_with_period_rational_prec_round_properties_helper(x, u, prec, rm);
},
);
unsigned_rounding_mode_pair_gen_var_3().test_properties(|(prec, rm)| {
for x in [Rational::ZERO, Rational::ONE_HALF, -Rational::ONE_HALF] {
for u in [0, 4] {
let (c, o) = Float::asec_with_period_rational_prec_round(x.clone(), u, prec, rm);
assert!(c.is_nan());
assert_eq!(o, Equal);
}
}
for x in [Rational::ONE, Rational::NEGATIVE_ONE, Rational::TWO] {
let (c, o) = Float::asec_with_period_rational_prec_round(x, 0, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
}
let (c, o) = Float::asec_with_period_rational_prec_round(Rational::ONE, 8, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(Float::ZERO));
assert_eq!(o, Equal);
let (q, o_q) = Float::from_unsigned_prec_round(8u32, prec, rm);
let (c, o) =
Float::asec_with_period_rational_prec_round(Rational::NEGATIVE_ONE, 8, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(q >> 1u32));
assert_eq!(o, o_q);
let (q, o_q) = Float::from_unsigned_prec_round(4u32, prec, rm);
for (x, k) in [(Rational::TWO, 1u32), (-Rational::TWO, 0)] {
let (c, o) = Float::asec_with_period_rational_prec_round(x, 12, prec, rm);
assert_eq!(ComparableFloat(c), ComparableFloat(q.clone() >> k));
assert_eq!(o, o_q);
}
});
}
#[test]
fn asec_with_period_rational_prec_properties() {
rational_unsigned_unsigned_rounding_mode_quadruple_gen_var_9().test_properties(
|(x, u, prec, _)| {
let (c, o) = Float::asec_with_period_rational_prec(x.clone(), u, prec);
assert!(c.is_valid());
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_ref(&x, u, prec);
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) =
Float::asec_with_period_rational_prec_round_ref(&x, u, prec, Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
},
);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec_with_period_rational() {
fn test<T: PrimitiveFloat>(s: &str, u: u64, out: T)
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_asec_with_period_rational::<T>(
&Rational::from_str(s).unwrap(),
u
)),
NiceFloat(out)
);
}
test::<f32>("1/2", 360, f32::NAN);
test::<f32>("0", 360, f32::NAN);
test::<f32>("1", 360, 0.0);
test::<f32>("-1", 360, 180.0);
test::<f32>("2", 360, 60.0);
test::<f32>("-2", 360, 120.0);
test::<f32>("3/2", 360, 48.189686);
test::<f32>("-3/2", 360, 131.81032);
test::<f32>("5/3", 360, 53.130104);
test::<f32>("100", 360, 89.42703);
test::<f32>("1000000/999999", 360, 0.08102848);
test::<f32>("100000000000000000000000000000000000000000", 360, 90.0);
test::<f32>("2", 12, 2.0);
test::<f32>("-2", 12, 4.0);
test::<f32>("2", 7, 1.1666666);
test::<f32>("1/2", 0, f32::NAN);
test::<f32>("3/2", 0, 0.0);
test::<f32>("1", 18446744073709551615, 0.0);
test::<f32>("-1", 18446744073709551615, 9.223372e18);
test::<f64>("1/2", 360, f64::NAN);
test::<f64>("0", 360, f64::NAN);
test::<f64>("1", 360, 0.0);
test::<f64>("-1", 360, 180.0);
test::<f64>("2", 360, 60.0);
test::<f64>("-2", 360, 120.0);
test::<f64>("3/2", 360, 48.189685104221404);
test::<f64>("-3/2", 360, 131.8103148957786);
test::<f64>("5/3", 360, 53.13010235415598);
test::<f64>("100", 360, 89.42703265514285);
test::<f64>("1000000/999999", 360, 0.08102847520651343);
test::<f64>("100000000000000000000000000000000000000000", 360, 90.0);
test::<f64>("2", 12, 2.0);
test::<f64>("-2", 12, 4.0);
test::<f64>("2", 7, 1.1666666666666667);
test::<f64>("1/2", 0, f64::NAN);
test::<f64>("3/2", 0, 0.0);
test::<f64>("1", 18446744073709551615, 0.0);
test::<f64>("-1", 18446744073709551615, 9.223372036854776e18);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_asec_with_period_rational_properties_helper<T: PrimitiveFloat>()
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
rational_unsigned_pair_gen_var_1::<u64>().test_properties(|(x, u)| {
let c = primitive_float_asec_with_period_rational::<T>(&x, u);
assert_eq!(c.is_nan(), x.lt_abs(&1u32));
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= T::ZERO);
let (c_float, _) =
Float::asec_with_period_rational_prec_ref(&x, u, T::MANTISSA_WIDTH + 64);
assert_eq!(
NiceFloat(T::rounding_from(&c_float, Nearest).0),
NiceFloat(c)
);
}
});
}
#[test]
fn primitive_float_asec_with_period_rational_properties() {
apply_fn_to_primitive_floats!(primitive_float_asec_with_period_rational_properties_helper);
}
#[test]
fn test_asec_pi_prec_round() {
let test = |s: &str,
s_hex: &str,
prec: u64,
rm: RoundingMode,
out: &str,
out_hex: &str,
o_out: Ordering| {
let x = parse_hex_string(s_hex);
assert_eq!(x.to_string(), s);
let (c, o) = x.clone().asec_pi_prec_round(prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = x.asec_pi_prec_round_ref(prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_pi_prec_round_assign(prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = x.asec_pi_prec_ref(prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) =
rug_asec_with_period_prec_round(&rug::Float::exact_from(&x), 2, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("NaN", "NaN", 10, Nearest, "NaN", "NaN", Equal);
test(
"Infinity",
"Infinity",
10,
Exact,
"0.50000",
"0x0.800#10",
Equal,
);
test(
"-Infinity",
"-Infinity",
10,
Exact,
"0.50000",
"0x0.800#10",
Equal,
);
test("Infinity", "Infinity", 1, Exact, "0.50", "0x0.8#1", Equal);
test("0.0", "0x0.0", 10, Exact, "NaN", "NaN", Equal);
test("-0.0", "-0x0.0", 10, Exact, "NaN", "NaN", Equal);
test("0.50", "0x0.8#1", 10, Nearest, "NaN", "NaN", Equal);
test("1.0", "0x1.0#1", 10, Exact, "0.0", "0x0.0", Equal);
test("1.0", "0x1.0#1", 1, Exact, "0.0", "0x0.0", Equal);
test("-1.0", "-0x1.0#1", 10, Exact, "1.0000", "0x1.000#10", Equal);
test("-1.0", "-0x1.0#1", 1, Exact, "1.0", "0x1.0#1", Equal);
test("2.0", "0x2.0#1", 10, Floor, "0.33301", "0x0.554#10", Less);
test(
"2.0",
"0x2.0#1",
10,
Ceiling,
"0.33350",
"0x0.556#10",
Greater,
);
test(
"2.0",
"0x2.0#1",
10,
Nearest,
"0.33350",
"0x0.556#10",
Greater,
);
test(
"2.0",
"0x2.0#1",
53,
Nearest,
"0.33333333333333331",
"0x0.55555555555554#53",
Less,
);
test(
"-2.0",
"-0x2.0#1",
53,
Nearest,
"0.66666666666666663",
"0x0.aaaaaaaaaaaaa8#53",
Less,
);
test("2.5", "0x2.8#3", 10, Floor, "0.36865", "0x0.5e6#10", Less);
test(
"2.5",
"0x2.8#3",
10,
Ceiling,
"0.36914",
"0x0.5e8#10",
Greater,
);
test(
"2.5",
"0x2.8#3",
10,
Nearest,
"0.36914",
"0x0.5e8#10",
Greater,
);
test(
"2.5",
"0x2.8#3",
53,
Nearest,
"0.36901011956554536",
"0x0.5e77727b6d5444#53",
Less,
);
test(
"1.5",
"0x1.8#2",
20,
Nearest,
"0.26772070",
"0x0.448958#20",
Greater,
);
test(
"-1.5",
"-0x1.8#2",
20,
Nearest,
"0.73227978",
"0x0.bb76b#20",
Greater,
);
test(
"100.0",
"0x64.0#7",
20,
Nearest,
"0.49681664",
"0x0.7f2f60#20",
Less,
);
test(
"1.0000000000000002",
"0x1.0000000000001#53",
53,
Nearest,
"6.7078792762540724e-9",
"0x1.ccf6429be6620E-7#53",
Less,
);
}
#[test]
#[should_panic]
fn asec_pi_prec_round_fail_1() {
Float::ONE.asec_pi_prec_round(0, Floor);
}
#[test]
#[should_panic]
fn asec_pi_prec_round_fail_2() {
Float::TWO.asec_pi_prec_round(10, Exact);
}
#[test]
#[should_panic]
fn asec_pi_rational_prec_round_fail() {
Float::asec_pi_rational_prec_round(Rational::TWO, 10, Exact);
}
#[test]
fn test_asec_pi_rational_prec_round() {
let test = |s: &str, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, o_out: Ordering| {
let x = Rational::from_str(s).unwrap();
let (c, o) = Float::asec_pi_rational_prec_round(x.clone(), prec, rm);
assert!(c.is_valid());
assert_eq!(c.to_string(), out);
assert_eq!(to_hex_string(&c), out_hex);
assert_eq!(o, o_out);
let (c_alt, o_alt) = Float::asec_pi_rational_prec_round_ref(&x, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if rm == Nearest {
let (c_alt, o_alt) = Float::asec_pi_rational_prec(x.clone(), prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_pi_rational_prec_ref(&x, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if x != 0u32 {
let (c_alt, o_alt) =
Float::acos_pi_rational_prec_round(x.clone().reciprocal(), prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
}
if !c.is_nan()
&& let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
{
let (rug_c, rug_o) = rug_asec_with_period_rational_prec_round(&x, 2, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
};
test("0", 10, Nearest, "NaN", "NaN", Equal);
test("1/2", 10, Nearest, "NaN", "NaN", Equal);
test("-1/2", 10, Nearest, "NaN", "NaN", Equal);
test("1", 10, Exact, "0.0", "0x0.0", Equal);
test("1", 1, Exact, "0.0", "0x0.0", Equal);
test("-1", 10, Exact, "1.0000", "0x1.000#10", Equal);
test("-1", 1, Exact, "1.0", "0x1.0#1", Equal);
test("2", 10, Floor, "0.33301", "0x0.554#10", Less);
test("2", 10, Ceiling, "0.33350", "0x0.556#10", Greater);
test(
"2",
53,
Nearest,
"0.33333333333333331",
"0x0.55555555555554#53",
Less,
);
test(
"-2",
53,
Nearest,
"0.66666666666666663",
"0x0.aaaaaaaaaaaaa8#53",
Less,
);
test("5/3", 10, Floor, "0.29492", "0x0.4b8#10", Less);
test("5/3", 10, Ceiling, "0.29541", "0x0.4ba#10", Greater);
test("5/3", 10, Nearest, "0.29541", "0x0.4ba#10", Greater);
test(
"5/3",
53,
Nearest,
"0.29516723530086653",
"0x0.4b90147677cc20#53",
Less,
);
test(
"-5/3",
53,
Nearest,
"0.70483276469913347",
"0x0.b46feb898833e0#53",
Greater,
);
test(
"100/99",
20,
Nearest,
"0.045053422",
"0x0.0b889f#20",
Greater,
);
test("100", 20, Nearest, "0.49681664", "0x0.7f2f60#20", Less);
test(
"100000000000000000000000000000000000000000",
20,
Nearest,
"0.50000000",
"0x0.80000#20",
Greater,
);
}
#[test]
fn asec_pi_properties() {
let exact_ok = |x: &Float, prec: u64, rm: RoundingMode| {
rm != Exact || x.asec_with_period_prec_round_ref(2, prec, Nearest).1 == Equal
};
float_unsigned_rounding_mode_triple_gen_var_45().test_properties(|(x, prec, rm)| {
if !exact_ok(&x, prec, rm) {
assert_panic!(x.asec_pi_prec_round_ref(prec, Exact));
return;
}
let (c, o) = x.clone().asec_pi_prec_round(prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(2, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_pi_prec_round_ref(prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_pi_prec_round_assign(prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if !c.is_nan() {
assert!(c.is_finite());
assert!(c >= 0u32);
assert!(c <= 1u32);
}
if let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm) {
let (rug_c, rug_o) =
rug_asec_with_period_prec_round(&rug::Float::exact_from(&x), 2, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
});
float_unsigned_rounding_mode_triple_gen_var_46().test_properties(|(x, prec, rm)| {
if !exact_ok(&x, prec, rm) {
return;
}
let (c, o) = x.asec_pi_prec_round_ref(prec, rm);
let (c_alt, o_alt) = x.asec_with_period_prec_round_ref(2, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
float_unsigned_pair_gen_var_1().test_properties(|(x, prec)| {
let (c, o) = x.clone().asec_pi_prec(prec);
let (c_alt, o_alt) = x.asec_with_period_prec_ref(2, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_pi_prec_ref(prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_pi_prec_assign(prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
float_rounding_mode_pair_gen_var_50().test_properties(|(x, rm)| {
if !exact_ok(&x, x.significant_bits(), rm) {
return;
}
let (c, o) = x.clone().asec_pi_round(rm);
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = x.asec_with_period_round_ref(2, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = x.asec_pi_round_ref(rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let mut c_alt = x.clone();
let o_alt = c_alt.asec_pi_round_assign(rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
rational_unsigned_rounding_mode_triple_gen_var_12().test_properties(|(x, prec, rm)| {
if rm == Exact && Float::asec_with_period_rational_prec_ref(&x, 2, prec).1 != Equal {
assert_panic!(Float::asec_pi_rational_prec_round_ref(&x, prec, Exact));
return;
}
let (c, o) = Float::asec_pi_rational_prec_round(x.clone(), prec, rm);
assert!(c.is_valid());
assert_rounding_ordering_consistent(&c, rm, o);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_round_ref(&x, 2, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_pi_rational_prec_round_ref(&x, prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
if x != 0u32 {
let (c_alt, o_alt) =
Float::acos_pi_rational_prec_round(x.clone().reciprocal(), prec, rm);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o, "x = {x} prec = {prec} rm = {rm:?}");
}
if !c.is_nan()
&& let Ok(rug_rm) = rug_round_try_from_rounding_mode(rm)
{
let (rug_c, rug_o) = rug_asec_with_period_rational_prec_round(&x, 2, prec, rug_rm);
assert_eq!(
ComparableFloatRef(&Float::from(&rug_c)),
ComparableFloatRef(&c)
);
assert_eq!(rug_o, o);
}
});
rational_unsigned_pair_gen_var_3().test_properties(|(x, prec)| {
let (c, o) = Float::asec_pi_rational_prec(x.clone(), prec);
let (c_alt, o_alt) = Float::asec_with_period_rational_prec_ref(&x, 2, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
let (c_alt, o_alt) = Float::asec_pi_rational_prec_ref(&x, prec);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
assert_eq!(o_alt, o);
});
float_gen().test_properties(|x| {
let c = x.clone().asec_pi();
assert!(c.is_valid());
let c_alt = x.asec_pi_ref();
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let mut c_alt = x.clone();
c_alt.asec_pi_assign();
assert!(c_alt.is_valid());
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let c_alt = x.asec_with_period_ref(2);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
let (c_alt, _) = x.asec_pi_prec_round_ref(x.significant_bits(), Nearest);
assert_eq!(ComparableFloatRef(&c_alt), ComparableFloatRef(&c));
});
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec_pi() {
fn test<T: PrimitiveFloat>(x: T, out: T)
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
assert_eq!(NiceFloat(primitive_float_asec_pi(x)), NiceFloat(out));
}
test::<f32>(f32::NAN, f32::NAN);
test::<f32>(f32::INFINITY, 0.5);
test::<f32>(f32::NEGATIVE_INFINITY, 0.5);
test::<f32>(0.0, f32::NAN);
test::<f32>(0.5, f32::NAN);
test::<f32>(1.0, 0.0);
test::<f32>(-1.0, 1.0);
test::<f32>(2.0, 0.33333334);
test::<f32>(-2.0, 0.6666667);
test::<f32>(2.5, 0.36901012);
test::<f32>(1.5, 0.26772046);
test::<f32>(100.0, 0.49681684);
test::<f32>(1.0e30, 0.5);
test::<f64>(f64::NAN, f64::NAN);
test::<f64>(f64::INFINITY, 0.5);
test::<f64>(f64::NEGATIVE_INFINITY, 0.5);
test::<f64>(0.0, f64::NAN);
test::<f64>(0.5, f64::NAN);
test::<f64>(1.0, 0.0);
test::<f64>(-1.0, 1.0);
test::<f64>(2.0, 0.3333333333333333);
test::<f64>(-2.0, 0.6666666666666666);
test::<f64>(2.5, 0.36901011956554536);
test::<f64>(1.5, 0.26772047280123);
test::<f64>(100.0, 0.4968168480841269);
test::<f64>(1.0e300, 0.5);
}
#[test]
#[allow(clippy::type_repetition_in_bounds)]
fn test_primitive_float_asec_pi_rational() {
fn test<T: PrimitiveFloat>(s: &str, out: T)
where
Float: PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float>,
{
assert_eq!(
NiceFloat(primitive_float_asec_pi_rational::<T>(
&Rational::from_str(s).unwrap()
)),
NiceFloat(out)
);
}
test::<f32>("0", f32::NAN);
test::<f32>("1/2", f32::NAN);
test::<f32>("1", 0.0);
test::<f32>("-1", 1.0);
test::<f32>("2", 0.33333334);
test::<f32>("-2", 0.6666667);
test::<f32>("5/3", 0.29516724);
test::<f32>("-5/3", 0.7048328);
test::<f32>("100/99", 0.045053415);
test::<f32>("100", 0.49681684);
test::<f64>("0", f64::NAN);
test::<f64>("1/2", f64::NAN);
test::<f64>("1", 0.0);
test::<f64>("-1", 1.0);
test::<f64>("2", 0.3333333333333333);
test::<f64>("-2", 0.6666666666666666);
test::<f64>("5/3", 0.2951672353008665);
test::<f64>("-5/3", 0.7048327646991335);
test::<f64>("100/99", 0.0450534136444121);
test::<f64>("100", 0.4968168480841269);
}
#[allow(clippy::type_repetition_in_bounds)]
fn primitive_float_asec_pi_properties_helper<T: PrimitiveFloat>()
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
primitive_float_gen::<T>().test_properties(|x| {
assert_eq!(
NiceFloat(primitive_float_asec_pi(x)),
NiceFloat(primitive_float_asec_with_period(x, 2))
);
});
rational_gen().test_properties(|x| {
assert_eq!(
NiceFloat(primitive_float_asec_pi_rational::<T>(&x)),
NiceFloat(primitive_float_asec_with_period_rational::<T>(&x, 2))
);
});
}
#[test]
fn primitive_float_asec_pi_properties() {
apply_fn_to_primitive_floats!(primitive_float_asec_pi_properties_helper);
}