use crate::Float;
use crate::float::conversion::string::get_str::get_str;
use crate::float::conversion::string::strtofr::strtofr;
use crate::test_util::common::rug_round_exact_from_rounding_mode;
use alloc::string::{String, ToString};
use core::cmp::Ordering::Equal;
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::conversion::string::options::FromSciStringOptions;
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::rounding_modes::RoundingMode::{self, Down, Exact};
use malachite_base::test_util::generators::common::It;
use malachite_nz::integer::Integer;
use malachite_nz::natural::Natural;
use malachite_q::Rational;
pub fn valid_float_get_str_quadruple(x: &Float, b0: i64, m: usize, rnd: RoundingMode) -> bool {
rnd != Exact || matches!(get_str(x, b0, m, Down), Some((_, _, Equal)))
}
pub fn valid_strtofr_quadruple(s: &str, base: u8, prec: u64, rnd: RoundingMode) -> bool {
rnd != Exact || strtofr(s, base, prec, Down).1 == Equal
}
const DIGIT_CHARS_36: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
const DIGIT_CHARS_62: &[u8; 62] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
pub fn valid_float_from_sci_string_triple(
s: &str,
options: FromSciStringOptions,
prec: u64,
) -> bool {
if options.get_rounding_mode() != Exact {
return true;
}
let mut probe = options;
probe.set_rounding_mode(Down);
Float::from_sci_string_with_options_prec(s, probe, prec).is_none_or(|(_, o)| o == Equal)
}
pub const SCI_STRING_COMBO_COUNT: u32 = 3 * 3 * 3 * 5;
pub fn sci_string_from_parts(base: u8, combo: u32, digits: &[u8], exp: i64) -> String {
let kind = combo % 3;
let marker = (combo / 3) % 3;
let sign = usize::exact_from((combo / 9) % 3);
let point = usize::exact_from((combo / 27) % 5);
if kind == 1 {
return String::from("NaN");
}
if kind == 2 {
return String::from(if sign == 1 { "-Infinity" } else { "Infinity" });
}
let mut s = String::new();
s.push_str(["", "-", "+"][sign]);
let default_digits = [0];
let digits = if digits.is_empty() {
&default_digits[..]
} else {
digits
};
let chars: &[u8] = if base <= 36 {
DIGIT_CHARS_36
} else {
DIGIT_CHARS_62
};
let point = point % (digits.len() + 1);
for (i, &d) in digits.iter().enumerate() {
if i == point {
s.push('.');
}
s.push(char::from(chars[usize::from(d % base)]));
}
if point == digits.len() {
s.push('.');
}
if marker != 0 {
let exp = exp.max(i64::MIN + i64::exact_from(digits.len()));
s.push(if marker == 1 { 'e' } else { 'E' });
if exp >= 0 && base >= 15 {
s.push('+');
}
s.push_str(&exp.to_string());
}
s
}
pub const STRTOFR_STRING_CHARS: &str = "+-.0123456789abfinxzABFINXZ@epP()_ \t";
pub const STRTOFR_COMBO_COUNT: u32 = 8 * 5 * 4 * 6 * 3 * 4;
pub fn strtofr_string_from_parts(
base: u8,
combo: u32,
digits: &[u8],
exp: i64,
rug_compatible: bool,
) -> String {
let kind = combo % 8;
let marker = (combo / 8) % 6;
let variant = usize::exact_from((combo / 48) % 4);
let point = usize::exact_from((combo / 192) % 5);
let sign = ["", "-", "+"][usize::exact_from((combo / 960) % 3)];
let whitespace = ["", " ", "\t", " \n\t"][usize::exact_from((combo / 2880) % 4)];
let mut s = String::new();
s.push_str(whitespace);
s.push_str(sign);
let bare_specials_ok = base <= if rug_compatible { 10 } else { 16 };
if kind == 0 {
s.push_str(if bare_specials_ok {
["nan", "NaN", "@nan@", "nan(_a1)"][variant]
} else {
["@nan@", "@NAN@", "@Nan@", "@nan@(_a1)"][variant]
});
return s;
}
if kind == 1 {
s.push_str(if bare_specials_ok {
["inf", "INF", "infinity", "@inf@"][variant]
} else {
["@inf@", "@INF@", "@Inf@", "@inf@"][variant]
});
return s;
}
let prefix = if rug_compatible {
""
} else {
match variant {
1 if base == 0 || base == 16 => "0x",
2 if base == 0 || base == 2 => "0b",
3 if base == 0 || base == 16 => "0X",
_ => "",
}
};
let effective_base = match prefix {
"0x" | "0X" => 16,
"0b" => 2,
_ if base == 0 => 10,
_ => base,
};
s.push_str(prefix);
let default_digits = [0];
let digits = if digits.is_empty() {
&default_digits[..]
} else {
digits
};
let chars: &[u8] = if effective_base <= 36 {
DIGIT_CHARS_36
} else {
DIGIT_CHARS_62
};
let point = point % (digits.len() + 1);
for (i, &d) in digits.iter().enumerate() {
if i == point {
s.push('.');
}
s.push(char::from(chars[usize::from(d % effective_base)]));
}
if point == digits.len() {
s.push('.');
}
let marker = match marker {
0 => None,
2 if !rug_compatible && (effective_base == 2 || effective_base == 16) => Some('p'),
3 if effective_base <= 10 => Some('e'),
4 if !rug_compatible && (effective_base == 2 || effective_base == 16) => Some('P'),
5 if effective_base <= 10 => Some('E'),
_ => Some('@'),
};
if let Some(marker) = marker {
s.push(marker);
s.push_str(&exp.to_string());
}
s
}
const FLOAT_FORMAT_CONV_CHARS: &[u8; 9] = b"aAbeEfFgG";
const FLOAT_FORMAT_FLAG_CHARS: &[u8; 6] = b"#0+ -'";
const FLOAT_FORMAT_RND_CHARS: &[u8; 5] = b"DUYZN";
pub const FLOAT_FORMAT_COMBO_COUNT: u16 = 64 * 9 * 6;
pub fn format_string_output_is_bounded(fmt: &str) -> bool {
!fmt.ends_with(['b', 'f', 'F'])
}
pub fn format_string_from_parts(combo: u16, width: Option<u64>, prec: Option<u64>) -> String {
let flags = combo & 0x3f;
let selector = combo >> 6; let conv = usize::from(selector % 9);
let rnd = selector / 9; let mut s = vec![b'%'];
for (i, &c) in FLOAT_FORMAT_FLAG_CHARS.iter().enumerate() {
if flags & (1 << i) != 0 {
s.push(c);
}
}
if let Some(w) = width {
s.extend_from_slice(w.to_string().as_bytes());
}
if let Some(p) = prec {
s.push(b'.');
s.extend_from_slice(p.to_string().as_bytes());
}
s.push(b'R');
if rnd != 0 {
s.push(FLOAT_FORMAT_RND_CHARS[usize::from(rnd) - 1]);
}
s.push(FLOAT_FORMAT_CONV_CHARS[conv]);
String::from_utf8(s).unwrap()
}
pub fn float_rm(xs: It<Float>) -> It<(rug::Float, Float)> {
Box::new(xs.map(|x| (rug::Float::exact_from(&x), x)))
}
pub fn float_pair_rm(xs: It<(Float, Float)>) -> It<((rug::Float, rug::Float), (Float, Float))> {
Box::new(xs.map(|(x, y)| {
(
(rug::Float::exact_from(&x), rug::Float::exact_from(&y)),
(x, y),
)
}))
}
pub fn float_natural_pair_rm(
xs: It<(Float, Natural)>,
) -> It<((rug::Float, rug::Integer), (Float, Natural))> {
Box::new(xs.map(|(x, y)| {
(
(rug::Float::exact_from(&x), rug::Integer::exact_from(&y)),
(x, y),
)
}))
}
pub fn float_integer_pair_rm(
xs: It<(Float, Integer)>,
) -> It<((rug::Float, rug::Integer), (Float, Integer))> {
Box::new(xs.map(|(x, y)| {
(
(rug::Float::exact_from(&x), rug::Integer::exact_from(&y)),
(x, y),
)
}))
}
pub fn float_rational_pair_rm(
xs: It<(Float, Rational)>,
) -> It<((rug::Float, rug::Rational), (Float, Rational))> {
Box::new(xs.map(|(x, y)| {
(
(rug::Float::exact_from(&x), rug::Rational::exact_from(&y)),
(x, y),
)
}))
}
pub fn float_primitive_int_pair_rm<T: PrimitiveInt>(
xs: It<(Float, T)>,
) -> It<((rug::Float, T), (Float, T))> {
Box::new(xs.map(|(x, y)| ((rug::Float::exact_from(&x), y), (x, y))))
}
pub fn float_primitive_float_pair_rm<T: PrimitiveFloat>(
xs: It<(Float, T)>,
) -> It<((rug::Float, T), (Float, T))> {
Box::new(xs.map(|(x, y)| ((rug::Float::exact_from(&x), y), (x, y))))
}
pub fn float_t_rounding_mode_triple_rm<T: Clone + 'static>(
xs: It<(Float, T, RoundingMode)>,
) -> It<((rug::Float, T, rug::float::Round), (Float, T, RoundingMode))> {
Box::new(xs.filter(|(_, _, rm)| *rm != Exact).map(|(x, p, rm)| {
(
(
rug::Float::exact_from(&x),
p.clone(),
rug_round_exact_from_rounding_mode(rm),
),
(x, p, rm),
)
}))
}
pub fn float_t_u_triple_rm<T: Clone + 'static, U: Clone + 'static>(
xs: It<(Float, T, U)>,
) -> It<((rug::Float, T, U), (Float, T, U))> {
Box::new(xs.map(|(x, p, q)| {
(
(rug::Float::exact_from(&x), p.clone(), q.clone()),
(x, p, q),
)
}))
}
pub fn string_u_u_rounding_mode_quadruple_rm(
xs: It<(String, u8, u64, RoundingMode)>,
) -> It<(
(String, i32, u32, rug::float::Round),
(String, u8, u64, RoundingMode),
)> {
Box::new(xs.map(|(s, base, prec, rm)| {
(
(
s.clone(),
i32::from(base),
u32::exact_from(prec),
rug_round_exact_from_rounding_mode(rm),
),
(s, base, prec, rm),
)
}))
}
pub fn float_t_u_rounding_mode_quadruple_rm<T: Clone + 'static, U: Clone + 'static>(
xs: It<(Float, T, U, RoundingMode)>,
) -> It<(
(rug::Float, T, U, rug::float::Round),
(Float, T, U, RoundingMode),
)> {
Box::new(
xs.filter(|(_, _, _, rm)| *rm != Exact)
.map(|(x, p, q, rm)| {
(
(
rug::Float::exact_from(&x),
p.clone(),
q.clone(),
rug_round_exact_from_rounding_mode(rm),
),
(x, p, q, rm),
)
}),
)
}
pub fn float_rounding_mode_pair_rm(
xs: It<(Float, RoundingMode)>,
) -> It<((rug::Float, rug::float::Round), (Float, RoundingMode))> {
Box::new(xs.filter(|(_, rm)| *rm != Exact).map(|(x, rm)| {
(
(
rug::Float::exact_from(&x),
rug_round_exact_from_rounding_mode(rm),
),
(x, rm),
)
}))
}
pub fn float_float_rounding_mode_triple_rm(
xs: It<(Float, Float, RoundingMode)>,
) -> It<(
(rug::Float, rug::Float, rug::float::Round),
(Float, Float, RoundingMode),
)> {
Box::new(xs.filter(|(_, _, rm)| *rm != Exact).map(|(x, y, rm)| {
(
(
rug::Float::exact_from(&x),
rug::Float::exact_from(&y),
rug_round_exact_from_rounding_mode(rm),
),
(x, y, rm),
)
}))
}
pub fn float_float_anything_triple_rm<T: Clone + 'static>(
xs: It<(Float, Float, T)>,
) -> It<((rug::Float, rug::Float, T), (Float, Float, T))> {
Box::new(xs.map(|(x, y, z)| {
(
(
rug::Float::exact_from(&x),
rug::Float::exact_from(&y),
z.clone(),
),
(x, y, z),
)
}))
}
pub fn float_rational_anything_triple_rm<T: Clone + 'static>(
xs: It<(Float, Rational, T)>,
) -> It<((rug::Float, rug::Rational, T), (Float, Rational, T))> {
Box::new(xs.map(|(x, y, z)| {
(
(
rug::Float::exact_from(&x),
rug::Rational::exact_from(&y),
z.clone(),
),
(x, y, z),
)
}))
}
pub fn float_rational_rounding_mode_triple_rm(
xs: It<(Float, Rational, RoundingMode)>,
) -> It<(
(rug::Float, rug::Rational, rug::float::Round),
(Float, Rational, RoundingMode),
)> {
Box::new(xs.filter(|(_, _, rm)| *rm != Exact).map(|(x, y, rm)| {
(
(
rug::Float::exact_from(&x),
rug::Rational::exact_from(&y),
rug_round_exact_from_rounding_mode(rm),
),
(x, y, rm),
)
}))
}
pub fn float_float_anything_rounding_mode_quadruple_rm<T: Clone + 'static>(
xs: It<(Float, Float, T, RoundingMode)>,
) -> It<(
(rug::Float, rug::Float, T, rug::float::Round),
(Float, Float, T, RoundingMode),
)> {
Box::new(
xs.filter(|(_, _, _, rm)| *rm != Exact)
.map(|(x, y, z, rm)| {
(
(
rug::Float::exact_from(&x),
rug::Float::exact_from(&y),
z.clone(),
rug_round_exact_from_rounding_mode(rm),
),
(x, y, z, rm),
)
}),
)
}
pub fn float_rational_anything_rounding_mode_quadruple_rm<T: Clone + 'static>(
xs: It<(Float, Rational, T, RoundingMode)>,
) -> It<(
(rug::Float, rug::Rational, T, rug::float::Round),
(Float, Rational, T, RoundingMode),
)> {
Box::new(
xs.filter(|(_, _, _, rm)| *rm != Exact)
.map(|(x, y, z, rm)| {
(
(
rug::Float::exact_from(&x),
rug::Rational::exact_from(&y),
z.clone(),
rug_round_exact_from_rounding_mode(rm),
),
(x, y, z, rm),
)
}),
)
}