use crate::Float;
use crate::InnerFloat::Finite;
use core::cmp::Ordering::{self, *};
use malachite_base::num::arithmetic::traits::{IsPowerOf2, Sign};
use malachite_base::num::basic::traits::{Infinity, NegativeInfinity, NegativeZero, Zero};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_nz::natural::Natural;
use malachite_nz::natural::arithmetic::float_extras::{SetStrResult, limbs_set_str};
pub(crate) fn overflow(sign: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
match (sign, rm) {
(true, Up | Ceiling | Nearest) => (Float::INFINITY, Greater),
(true, Floor | Down) => (Float::max_finite_value_with_prec(prec), Less),
(false, Up | Floor | Nearest) => (Float::NEGATIVE_INFINITY, Less),
(false, Ceiling | Down) => (-Float::max_finite_value_with_prec(prec), Greater),
(_, Exact) => panic!("Inexact conversion from string to Float"),
}
}
fn underflow(sign: bool, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
match (sign, rm) {
(true, Up | Ceiling | Nearest) => (Float::min_positive_value_prec(prec), Greater),
(true, Floor | Down) => (Float::ZERO, Less),
(false, Up | Floor | Nearest) => (-Float::min_positive_value_prec(prec), Less),
(false, Ceiling | Down) => (Float::NEGATIVE_ZERO, Greater),
(_, Exact) => panic!("Inexact conversion from string to Float"),
}
}
pub_crate_test! {
set_str_helper(
sign: bool,
digits: &[u8],
base: u8,
exp_base: i64,
exp_bin: i64,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(prec, 0);
let mag_rm = if sign { rm } else { -rm };
let away_from_0 = if sign { Greater } else { Less };
match limbs_set_str(digits, u64::from(base), exp_base, exp_bin, prec, mag_rm) {
SetStrResult::Overflow => overflow(sign, prec, rm),
SetStrResult::Underflow => underflow(sign, prec, if rm == Nearest { Down } else { rm }),
SetStrResult::Finite(significand, exp, dir) => {
assert!(
rm != Exact || dir == 0,
"Inexact conversion from string to Float"
);
let o = if sign { dir.sign() } else { dir.sign().reverse() };
let significand = Natural::from_owned_limbs_asc(significand);
if exp > i64::from(Float::MAX_EXPONENT) {
return overflow(sign, prec, rm);
}
if exp < i64::from(Float::MIN_EXPONENT) {
let rm = if rm == Nearest
&& !(exp == i64::from(Float::MIN_EXPONENT_MINUS_1)
&& (o == away_from_0.reverse() || !significand.is_power_of_2()))
{
Down
} else {
rm
};
return underflow(sign, prec, rm);
}
(
Float(Finite {
sign,
exponent: i32::exact_from(exp),
precision: prec,
significand,
}),
o,
)
}
}
}}