use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
use crate::{ComparableFloatRef, Float, significand_bits};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{
Infinity as InfinityTrait, NaN as NaNTrait, NegativeInfinity, NegativeZero, Zero as ZeroTrait,
};
use malachite_base::num::conversion::traits::{ExactFrom, FromStringBase};
use malachite_base::num::logic::traits::{BitAccess, SignificantBits};
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_nz::natural::Natural;
use malachite_nz::platform::Limb;
use rug::float::{Round, Special};
use std::cmp::Ordering;
pub const fn rounding_mode_from_rug_round(rm: Round) -> RoundingMode {
match rm {
Round::Nearest => Nearest,
Round::Zero => Down,
Round::Up => Ceiling,
Round::Down => Floor,
Round::AwayZero => Up,
_ => panic!(),
}
}
#[allow(clippy::result_unit_err)]
pub const fn rug_round_try_from_rounding_mode(rm: RoundingMode) -> Result<Round, ()> {
match rm {
Floor => Ok(Round::Down),
Ceiling => Ok(Round::Up),
Down => Ok(Round::Zero),
Up => Ok(Round::AwayZero),
Nearest => Ok(Round::Nearest),
Exact => Err(()),
}
}
#[inline]
pub fn rug_round_exact_from_rounding_mode(rm: RoundingMode) -> Round {
rug_round_try_from_rounding_mode(rm).unwrap()
}
impl From<&rug::Float> for Float {
fn from(x: &rug::Float) -> Self {
if x.is_nan() {
Self::NAN
} else if x.is_infinite() {
if x.is_sign_positive() {
Self::INFINITY
} else {
Self::NEGATIVE_INFINITY
}
} else if x.is_zero() {
if x.is_sign_positive() {
Self::ZERO
} else {
Self::NEGATIVE_ZERO
}
} else {
let mut significand = Natural::exact_from(&*x.get_significand().unwrap());
let precision = u64::from(x.prec());
if significand.significant_bits() - precision >= Limb::WIDTH {
significand >>= Limb::WIDTH;
}
let result = Self(Finite {
sign: x.is_sign_positive(),
exponent: x.get_exp().unwrap(),
precision,
significand,
});
assert!(result.is_valid());
result
}
}
}
fn convert_prec(prec: u64) -> Result<u32, ()> {
u32::try_from(prec).map_err(|_| ())
}
#[allow(clippy::unnecessary_wraps)]
fn special_float(prec: u32, value: Special) -> Result<rug::Float, ()> {
Ok(rug::Float::with_val_round(prec, value, Round::Zero).0)
}
pub fn rug_float_significant_bits(x: &rug::Float) -> u64 {
if x.is_normal() {
u64::from(x.prec())
} else {
1
}
}
impl TryFrom<&Float> for rug::Float {
type Error = ();
fn try_from(x: &Float) -> Result<Self, ()> {
match x {
float_nan!() => special_float(1, Special::Nan),
float_infinity!() => special_float(1, Special::Infinity),
float_negative_infinity!() => special_float(1, Special::NegInfinity),
float_zero!() => special_float(1, Special::Zero),
float_negative_zero!() => special_float(1, Special::NegZero),
Float(Finite {
sign,
exponent,
precision,
significand,
}) => {
let mut f = Self::with_val_round(
convert_prec(*precision)?,
rug::Integer::from(significand),
Round::Zero,
)
.0;
f >>= i32::try_from(
i64::exact_from(significand_bits(significand)) - i64::from(*exponent),
)
.map_err(|_| ())?;
if !sign {
f = -f;
}
Ok(f)
}
}
}
}
pub fn parse_hex_string(s_hex: &str) -> Float {
let x = Float::from_string_base(16, s_hex).unwrap();
assert_eq!(format!("{:#x}", ComparableFloatRef(&x)), s_hex);
x
}
pub fn to_hex_string(x: &Float) -> String {
format!("{:#x}", ComparableFloatRef(x))
}
pub const ORDERED_FLOAT_STRINGS: [&str; 21] = [
"-Infinity",
"-3.1415926535897931",
"-2.0",
"-1.4142135623730951",
"-1.0",
"-1.0",
"-1.0",
"-0.5",
"-0.33333333333333331",
"-0.0",
"NaN",
"0.0",
"0.33333333333333331",
"0.5",
"1.0",
"1.0",
"1.0",
"1.4142135623730951",
"2.0",
"3.1415926535897931",
"Infinity",
];
pub const ORDERED_FLOAT_HEX_STRINGS: [&str; 21] = [
"-Infinity",
"-0x3.243f6a8885a30#53",
"-0x2.0#1",
"-0x1.6a09e667f3bcd#53",
"-0x1.0000000000000000000000000#100",
"-0x1.0#2",
"-0x1.0#1",
"-0x0.8#1",
"-0x0.55555555555554#53",
"-0x0.0",
"NaN",
"0x0.0",
"0x0.55555555555554#53",
"0x0.8#1",
"0x1.0#1",
"0x1.0#2",
"0x1.0000000000000000000000000#100",
"0x1.6a09e667f3bcd#53",
"0x2.0#1",
"0x3.243f6a8885a30#53",
"Infinity",
];
pub const ORDERED_F32S: [f32; 17] = [
f32::NEGATIVE_INFINITY,
-std::f32::consts::PI,
-2.0,
-std::f32::consts::SQRT_2,
-1.0,
-0.5,
-1.0 / 3.0,
-0.0,
f32::NAN,
0.0,
1.0 / 3.0,
0.5,
1.0,
std::f32::consts::SQRT_2,
2.0,
std::f32::consts::PI,
f32::INFINITY,
];
pub const ORDERED_F64S: [f64; 17] = [
f64::NEGATIVE_INFINITY,
-std::f64::consts::PI,
-2.0,
-std::f64::consts::SQRT_2,
-1.0,
-0.5,
-1.0 / 3.0,
-0.0,
f64::NAN,
0.0,
1.0 / 3.0,
0.5,
1.0,
std::f64::consts::SQRT_2,
2.0,
std::f64::consts::PI,
f64::INFINITY,
];
pub fn test_constant<F: Fn(u64, RoundingMode) -> (Float, Ordering)>(f: F, limit: u64) {
let mut bit_index = Limb::WIDTH - 1;
let mut significand = Natural::ZERO;
for prec in 1..limit {
let x = f(prec, Floor).0;
let x_sig = x.significand_ref().unwrap();
if *x_sig != significand {
significand.set_bit(bit_index);
assert_eq!(*x_sig, significand);
}
if bit_index == 0 {
significand <<= Limb::WIDTH;
bit_index = Limb::WIDTH - 1;
} else {
bit_index -= 1;
}
}
}