// Copyright © 2024 Mikhail Hogrefe
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See .
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::traits::NegativeInfinity;
use malachite_base::num::conversion::traits::RoundingFrom;
use malachite_base::rounding_modes::RoundingMode::*;
use malachite_base::strings::ToDebugString;
use malachite_base::test_util::generators::primitive_float_gen_var_8;
use malachite_q::conversion::from_primitive_float::RationalFromPrimitiveFloatError;
use malachite_q::test_util::generators::rational_gen_var_7;
use malachite_q::Rational;
#[test]
fn test_try_from_f32_simplest() {
let test = |f: f32, out| {
let x = Rational::try_from_float_simplest(f);
assert_eq!(x.to_debug_string(), out);
if let Ok(x) = x {
assert!(x.is_valid());
}
};
test(f32::NAN, "Err(RationalFromPrimitiveFloatError)");
test(f32::INFINITY, "Err(RationalFromPrimitiveFloatError)");
test(
f32::NEGATIVE_INFINITY,
"Err(RationalFromPrimitiveFloatError)",
);
test(0.0, "Ok(0)");
test(-0.0, "Ok(0)");
test(123.0, "Ok(123)");
test(-123.0, "Ok(-123)");
test(1.0e9, "Ok(1000000000)");
test(-1.0e9, "Ok(-1000000000)");
test(4294967295.0, "Ok(4294967296)");
test(-4294967295.0, "Ok(-4294967296)");
test(4294967296.0, "Ok(4294967296)");
test(-4294967296.0, "Ok(-4294967296)");
test(18446744073709551615.0, "Ok(18446744073709551616)");
test(-18446744073709551615.0, "Ok(-18446744073709551616)");
test(18446744073709551616.0, "Ok(18446744073709551616)");
test(-18446744073709551616.0, "Ok(-18446744073709551616)");
test(1.0e20, "Ok(100000002004087734272)");
test(-1.0e20, "Ok(-100000002004087734272)");
test(1.23e20, "Ok(122999999650278146048)");
test(-1.23e20, "Ok(-122999999650278146048)");
test(123.1, "Ok(1231/10)");
test(-123.1, "Ok(-1231/10)");
test(123.9, "Ok(1239/10)");
test(-123.9, "Ok(-1239/10)");
test(123.5, "Ok(247/2)");
test(-123.5, "Ok(-247/2)");
test(124.5, "Ok(249/2)");
test(-124.5, "Ok(-249/2)");
test(-0.499, "Ok(-499/1000)");
test(-0.5, "Ok(-1/2)");
test(0.1, "Ok(1/10)");
test(
f32::MIN_POSITIVE_SUBNORMAL,
"Ok(1/475749230901986627019428656483165045460915542)",
);
test(
-f32::MIN_POSITIVE_SUBNORMAL,
"Ok(-1/475749230901986627019428656483165045460915542)",
);
test(
f32::MAX_SUBNORMAL,
"Ok(1/85070596800837319010234175901631774785)",
);
test(
-f32::MAX_SUBNORMAL,
"Ok(-1/85070596800837319010234175901631774785)",
);
test(
f32::MIN_POSITIVE_NORMAL,
"Ok(1/85070586659632517184362935130987167681)",
);
test(
-f32::MIN_POSITIVE_NORMAL,
"Ok(-1/85070586659632517184362935130987167681)",
);
test(
f32::MAX_FINITE,
"Ok(340282346638528859811704183484516925440)",
);
test(
-f32::MAX_FINITE,
"Ok(-340282346638528859811704183484516925440)",
);
test(std::f32::consts::SQRT_2, "Ok(4756/3363)");
test(std::f32::consts::PI, "Ok(93343/29712)");
test(std::f32::consts::E, "Ok(2721/1001)");
test(0.33333334, "Ok(1/3)");
test(0.3333333, "Ok(3195660/9586981)");
}
#[test]
fn test_try_from_f64_simplest() {
let test = |f: f64, out| {
let x = Rational::try_from_float_simplest(f);
assert_eq!(x.to_debug_string(), out);
if let Ok(x) = x {
assert!(x.is_valid());
}
};
test(f64::NAN, "Err(RationalFromPrimitiveFloatError)");
test(f64::INFINITY, "Err(RationalFromPrimitiveFloatError)");
test(
f64::NEGATIVE_INFINITY,
"Err(RationalFromPrimitiveFloatError)",
);
test(0.0, "Ok(0)");
test(-0.0, "Ok(0)");
test(123.0, "Ok(123)");
test(-123.0, "Ok(-123)");
test(1.0e9, "Ok(1000000000)");
test(-1.0e9, "Ok(-1000000000)");
test(4294967295.0, "Ok(4294967295)");
test(-4294967295.0, "Ok(-4294967295)");
test(4294967296.0, "Ok(4294967296)");
test(-4294967296.0, "Ok(-4294967296)");
test(18446744073709551615.0, "Ok(18446744073709551616)");
test(-18446744073709551615.0, "Ok(-18446744073709551616)");
test(18446744073709551616.0, "Ok(18446744073709551616)");
test(-18446744073709551616.0, "Ok(-18446744073709551616)");
test(1.0e20, "Ok(100000000000000000000)");
test(-1.0e20, "Ok(-100000000000000000000)");
test(1.23e20, "Ok(123000000000000000000)");
test(-1.23e20, "Ok(-123000000000000000000)");
test(
1.0e100,
"Ok(10000000000000000159028911097599180468360808563945281389781327557747838772170381060813\
469985856815104)",
);
test(
-1.0e100,
"Ok(-1000000000000000015902891109759918046836080856394528138978132755774783877217038106081\
3469985856815104)",
);
test(
1.23e100,
"Ok(12300000000000000836686295084537585379506223785413935301425289783235883702867663918638\
982200322686976)",
);
test(
-1.23e100,
"Ok(-1230000000000000083668629508453758537950622378541393530142528978323588370286766391863\
8982200322686976)",
);
test(123.1, "Ok(1231/10)");
test(-123.1, "Ok(-1231/10)");
test(123.9, "Ok(1239/10)");
test(-123.9, "Ok(-1239/10)");
test(123.5, "Ok(247/2)");
test(-123.5, "Ok(-247/2)");
test(124.5, "Ok(249/2)");
test(-124.5, "Ok(-249/2)");
test(-0.499, "Ok(-499/1000)");
test(-0.5, "Ok(-1/2)");
test(
f64::MIN_POSITIVE_SUBNORMAL,
"Ok(1/134934835538207078901663564479278204699704433176094745571267572018286893045330231261\
306922467624749663458051909544541274259872491590528984578008933293825673281011616184377574\
242977938494728810894159845118981830045708004988949795132412068903766106370893873371008239\
179701555609743487001688124218339097337508871805160728996523)",
);
test(
-f64::MIN_POSITIVE_SUBNORMAL,
"Ok(-1/13493483553820707890166356447927820469970443317609474557126757201828689304533023126\
130692246762474966345805190954454127425987249159052898457800893329382567328101161618437757\
424297793849472881089415984511898183004570800498894979513241206890376610637089387337100823\
9179701555609743487001688124218339097337508871805160728996523)",
);
test(
f64::MAX_SUBNORMAL,
"Ok(1/449423283715579026828334036065257014383474871770369402158895481105061903177076758952\
991447760350212414247530205607522865754608382719974023705572587637923509973673766132988527\
495573581641607121816936686895147170329503865639571478615835487722625286251243883901055723\
06631238281271786009918606677660346752204801)",
);
test(
-f64::MAX_SUBNORMAL,
"Ok(-1/44942328371557902682833403606525701438347487177036940215889548110506190317707675895\
299144776035021241424753020560752286575460838271997402370557258763792350997367376613298852\
749557358164160712181693668689514717032950386563957147861583548772262528625124388390105572\
306631238281271786009918606677660346752204801)",
);
test(
f64::MIN_POSITIVE_NORMAL,
"Ok(1/449423283715578927036318559329266431564839219927211067229101097246506353572882385286\
930040496229077692647131520826525095187415228669222594373726590254689108839132120159189741\
421503549517982068519788656012202297150024869750306233834035420571989467252315767391654946\
28061906253051009157224240331719237716377601)",
);
test(
-f64::MIN_POSITIVE_NORMAL,
"Ok(-1/44942328371557892703631855932926643156483921992721106722910109724650635357288238528\
693004049622907769264713152082652509518741522866922259437372659025468910883913212015918974\
142150354951798206851978865601220229715002486975030623383403542057198946725231576739165494\
628061906253051009157224240331719237716377601)",
);
test(
f64::MAX_FINITE,
"Ok(17976931348623157081452742373170435679807056752584499659891747680315726078002853876058\
955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207\
624549009038932894407586850845513394230458323690322294816580855933212334827479782620414472\
3168738177180919299881250404026184124858368)",
);
test(
-f64::MAX_FINITE,
"Ok(-1797693134862315708145274237317043567980705675258449965989174768031572607800285387605\
895586327668781715404589535143824642343213268894641827684675467035375169860499105765512820\
762454900903893289440758685084551339423045832369032229481658085593321233482747978262041447\
23168738177180919299881250404026184124858368)",
);
test(std::f64::consts::SQRT_2, "Ok(131836323/93222358)");
test(std::f64::consts::PI, "Ok(245850922/78256779)");
test(std::f64::consts::E, "Ok(268876667/98914198)");
test(0.3333333333333333, "Ok(1/3)");
test(0.3333333333333337, "Ok(279293000147008/837879000441023)");
}
#[allow(clippy::trait_duplication_in_bounds)]
fn try_from_float_simplest_properties_helper<
T: for<'a> RoundingFrom<&'a Rational> + for<'a> TryFrom<&'a Rational> + PrimitiveFloat,
>()
where
Rational: TryFrom,
{
primitive_float_gen_var_8::().test_properties(|f| {
let q = Rational::try_from_float_simplest(f);
if let Ok(q) = q {
assert!(q.is_valid());
assert_eq!(Rational::try_from_float_simplest(-f), Ok(-&q));
}
});
rational_gen_var_7().test_properties(|q| {
// This only works for simple `Rational`s, i.e. those `Rational`s q that round to a float x
// such that no simpler `Rational` rounds to x.
assert_eq!(
Rational::try_from_float_simplest(T::rounding_from(&q, Nearest).0),
Ok(q)
);
});
}
#[test]
fn try_from_float_simplest_properties() {
apply_fn_to_primitive_floats!(try_from_float_simplest_properties_helper);
}