// 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::{ConvertibleFrom, ExactFrom};
use malachite_base::num::float::NiceFloat;
use malachite_base::strings::ToDebugString;
use malachite_base::test_util::generators::{primitive_float_gen, primitive_float_gen_var_8};
use malachite_q::Rational;
#[test]
fn test_try_from_f32() {
let test = |f: f32, out| {
let x = Rational::try_from(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(16134963/131072)");
test(-123.1, "Ok(-16134963/131072)");
test(123.9, "Ok(16239821/131072)");
test(-123.9, "Ok(-16239821/131072)");
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(-8371831/16777216)");
test(-0.5, "Ok(-1/2)");
test(0.1, "Ok(13421773/134217728)");
test(
f32::MIN_POSITIVE_SUBNORMAL,
"Ok(1/713623846352979940529142984724747568191373312)",
);
test(
-f32::MIN_POSITIVE_SUBNORMAL,
"Ok(-1/713623846352979940529142984724747568191373312)",
);
test(
f32::MAX_SUBNORMAL,
"Ok(8388607/713623846352979940529142984724747568191373312)",
);
test(
-f32::MAX_SUBNORMAL,
"Ok(-8388607/713623846352979940529142984724747568191373312)",
);
test(
f32::MIN_POSITIVE_NORMAL,
"Ok(1/85070591730234615865843651857942052864)",
);
test(
-f32::MIN_POSITIVE_NORMAL,
"Ok(-1/85070591730234615865843651857942052864)",
);
test(
f32::MAX_FINITE,
"Ok(340282346638528859811704183484516925440)",
);
test(
-f32::MAX_FINITE,
"Ok(-340282346638528859811704183484516925440)",
);
test(std::f32::consts::SQRT_2, "Ok(11863283/8388608)");
test(std::f32::consts::PI, "Ok(13176795/4194304)");
test(std::f32::consts::E, "Ok(2850325/1048576)");
}
#[test]
fn test_try_from_f64() {
let test = |f: f64, out| {
let x = Rational::try_from(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(4331196204135219/35184372088832)");
test(-123.1, "Ok(-4331196204135219/35184372088832)");
test(123.9, "Ok(4359343701806285/35184372088832)");
test(-123.9, "Ok(-4359343701806285/35184372088832)");
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(-4494592428115755/9007199254740992)");
test(-0.5, "Ok(-1/2)");
test(
f64::MIN_POSITIVE_SUBNORMAL,
"Ok(1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891\
960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361\
364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358\
769552333414615230502532186327508646006263307707741093494784)",
);
test(
-f64::MIN_POSITIVE_SUBNORMAL,
"Ok(-1/20240225330731061835249534671891730704955664976414211835690135802743033956799534689\
196038370143712449518707786431681191138980873738579347686701339994073850992151742427656636\
136446690774209321634123976767847274506856200748342469269861810335564915955634081005651235\
8769552333414615230502532186327508646006263307707741093494784)",
);
test(
f64::MAX_SUBNORMAL,
"Ok(4503599627370495/202402253307310618352495346718917307049556649764142118356901358027430\
339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921\
517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556\
340810056512358769552333414615230502532186327508646006263307707741093494784)",
);
test(
-f64::MAX_SUBNORMAL,
"Ok(-4503599627370495/20240225330731061835249534671891730704955664976414211835690135802743\
033956799534689196038370143712449518707786431681191138980873738579347686701339994073850992\
151742427656636136446690774209321634123976767847274506856200748342469269861810335564915955\
6340810056512358769552333414615230502532186327508646006263307707741093494784)",
);
test(
f64::MIN_POSITIVE_NORMAL,
"Ok(1/449423283715578976932326297697256183404494244735576643183575202894331689513752407831\
771193306018840052800284699678483394146974422036041556232118576598685310944419733562163713\
190755549003115235298632707380212514422095376705856157203684782776352068092908376276711465\
74559986811484619929076208839082406056034304)",
);
test(
-f64::MIN_POSITIVE_NORMAL,
"Ok(-1/44942328371557897693232629769725618340449424473557664318357520289433168951375240783\
177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371\
319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146\
574559986811484619929076208839082406056034304)",
);
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(6369051672525773/4503599627370496)",
);
test(std::f64::consts::PI, "Ok(884279719003555/281474976710656)");
test(std::f64::consts::E, "Ok(6121026514868073/2251799813685248)");
}
#[test]
fn test_rational_convertible_from_f32() {
let test = |f: f32, out| {
assert_eq!(Rational::convertible_from(f), out);
};
test(0.0, true);
test(1.0, true);
test(1.5, true);
test(0.1, true);
test(f32::NAN, false);
test(f32::INFINITY, false);
test(f32::NEGATIVE_INFINITY, false);
}
#[test]
fn test_rational_convertible_from_f64() {
let test = |f: f64, out| {
assert_eq!(Rational::convertible_from(f), out);
};
test(0.0, true);
test(1.0, true);
test(1.5, true);
test(0.1, true);
test(f64::NAN, false);
test(f64::INFINITY, false);
test(f64::NEGATIVE_INFINITY, false);
}
fn try_from_float_properties_helper + PrimitiveFloat>()
where
Rational: ConvertibleFrom + TryFrom,
{
primitive_float_gen::().test_properties(|f| {
let n = Rational::try_from(f);
assert_eq!(n.is_ok(), Rational::convertible_from(f));
if let Ok(n) = n {
assert!(n.is_valid());
assert_eq!(Rational::exact_from(-f), -&n);
assert_eq!(
NiceFloat(T::exact_from(n)),
NiceFloat(f.abs_negative_zero())
);
}
});
}
#[test]
fn try_from_float_properties() {
apply_fn_to_primitive_floats!(try_from_float_properties_helper);
primitive_float_gen_var_8::().test_properties(|f| {
assert_eq!(
Rational::exact_from(f),
Rational::from(&rug::Rational::from_f32(f).unwrap())
);
});
primitive_float_gen_var_8::().test_properties(|f| {
assert_eq!(
Rational::exact_from(f),
Rational::from(&rug::Rational::from_f64(f).unwrap())
);
});
}
fn rational_convertible_from_primitive_float_properties_helper()
where
Rational: ConvertibleFrom,
{
primitive_float_gen().test_properties(|f| {
assert_eq!(
Rational::convertible_from(f),
Rational::convertible_from(-f)
);
});
}
#[test]
fn rational_convertible_from_primitive_float_properties() {
apply_fn_to_primitive_floats!(rational_convertible_from_primitive_float_properties_helper);
}