use crate::prelude::*;
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn f64_equal(target: f64, num: usize, denom: usize) -> bool {
let fnum = num as f64;
let fdenom = denom as f64;
let lower = 2.0f64.mul_add(fnum, -1.0) / (2.0 * fdenom);
let upper = 2.0f64.mul_add(fnum, 1.0) / (2.0 * fdenom);
(lower..upper).contains(&target)
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn f64_greater(target: f64, num: usize, denom: usize) -> bool {
let fnum = num as f64;
let fdenom = denom as f64;
let lower = 2.0f64.mul_add(fnum, -1.0) / (2.0 * fdenom);
target > lower
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn f64_less(target: f64, num: usize, denom: usize) -> bool {
let fnum = num as f64;
let fdenom = denom as f64;
let upper = 2.0f64.mul_add(fnum, 1.0) / (2.0 * fdenom);
target < upper
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum JunkType {
#[default]
Any,
Trailing,
None,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum JunkVal {
Min,
#[default]
Max,
}
pub trait JunkValue {
fn val(j: JunkVal) -> Self;
}
macro_rules! jv {
($e:ty) => {
impl JunkValue for $e {
fn val(j: JunkVal) -> Self {
if j == JunkVal::Min { Self::MIN } else { Self::MAX }
}
}
};
}
jv!(f64);
jv!(i64);
jv!(u64);
jv!(isize);
jv!(usize);
#[derive(Debug, Default, Copy, Clone)]
pub struct Junk {
pub junk_type: JunkType,
pub junk_val: JunkVal,
}
impl Junk {
#[must_use]
pub fn val<T: JunkValue>(&self) -> T {
T::val(self.junk_val)
}
}
#[must_use]
pub fn fcmp(x: f64, y: f64) -> Ordering {
if x == y {
return Ordering::Equal;
}
if x > y {
return Ordering::Greater;
}
Ordering::Less
}
#[must_use]
pub const fn ulp_to_ulong(d: f64) -> u64 {
let x = u64::from_ne_bytes(d.to_ne_bytes());
if (x & 0x8000_0000_0000_0000_u64) != 0 {
x ^ 0xffff_ffff_ffff_ffff_u64
} else {
x | 0x8000_0000_0000_0000_u64
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum NumFormat {
Short(Option<usize>),
Plain(Option<usize>),
Float(Option<usize>),
Power2,
Power10,
}
impl Default for NumFormat {
fn default() -> Self {
Self::Plain(None)
}
}
impl NumFormat {
pub fn new(spec: &str) -> Result<Self> {
if spec.eq_ignore_ascii_case("plain") {
Ok(Self::Plain(None))
} else if spec.eq_ignore_ascii_case("short") {
Ok(Self::Short(None))
} else if spec.eq_ignore_ascii_case("float") {
Ok(Self::Float(None))
} else if spec.eq_ignore_ascii_case("power2") || spec.eq_ignore_ascii_case("p2") {
Ok(Self::Power2)
} else if spec.eq_ignore_ascii_case("power10") || spec.eq_ignore_ascii_case("p10") {
Ok(Self::Power10)
} else if let Some((a, b)) = spec.split_once('.') {
let p = b.to_usize_whole(spec.as_bytes(), "Num Format")?;
if a.eq_ignore_ascii_case("plain") {
Ok(Self::Plain(Some(p)))
} else if a.eq_ignore_ascii_case("short") {
Ok(Self::Short(Some(p)))
} else if a.eq_ignore_ascii_case("float") {
Ok(Self::Float(Some(p)))
} else {
err!("Number format must be short[.N], plain[.N], float[.N], power2 or power10")
}
} else {
err!("Number format must be short[.N], plain[.N], float[.N], power2 or power10")
}
}
fn new_format(self, num: f64) -> Self {
match self {
Self::Short(x) => {
let num = num.abs();
if (0.0001..1000.0).contains(&num) { Self::Plain(x) } else { Self::Float(x) }
}
_ => self,
}
}
pub fn print(self, mut num: f64, mut w: impl Write) -> Result<()> {
let nfmt = self.new_format(num);
if let Self::Plain(n) = nfmt {
if let Some(prec) = n {
write!(w, "{num:.prec$}")?;
} else {
write!(w, "{num}")?;
}
return Ok(());
}
if let Self::Float(n) = nfmt {
if let Some(prec) = n {
write!(w, "{num:.prec$e}")?;
} else {
write!(w, "{num:e}")?;
}
return Ok(());
}
num = num.round();
if num.abs() < 1000.0 || num.is_nan() || num.is_infinite() {
write!(w, "{num}")?;
return Ok(());
}
if nfmt == Self::Power2 {
write!(w, "{}", crate::format::format_power2f(num))?;
} else {
write!(w, "{}", crate::format::format_power10f(num))?;
}
Ok(())
}
}
pub const P2_LETTERS: &[u8] = b"0KMGTPEZYRQ";
pub const P10_LETTERS: &[u8] = b"0kmgtpezyrq";
const P2_VALUES_U: [usize; 11] = [
1,
1024,
1024 ^ 2,
1024 ^ 3,
1024 ^ 4,
1024 ^ 5,
1024 ^ 6,
usize::MAX,
usize::MAX,
usize::MAX,
usize::MAX,
];
const P2_VALUES_F: [f64; 11] = [
1.0,
1024.0,
1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0,
];
const P10_VALUES_U: [usize; 11] = [
1,
1000,
1000 ^ 2,
1000 ^ 3,
1000 ^ 4,
1000 ^ 5,
1000 ^ 6,
usize::MAX,
usize::MAX,
usize::MAX,
usize::MAX,
];
const P10_VALUES_F: [f64; 11] = [
1.0,
1000.0,
1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0,
];
#[must_use]
pub fn suffix_valf(ch: u8) -> Option<f64> {
for (i, x) in P2_LETTERS.iter().enumerate() {
if *x == ch {
return Some(P2_VALUES_F[i]);
}
}
for (i, x) in P10_LETTERS.iter().enumerate() {
if *x == ch {
return Some(P10_VALUES_F[i]);
}
}
None
}
#[must_use]
pub fn suffix_value(ch: u8) -> Option<usize> {
for (i, x) in P2_LETTERS.iter().enumerate() {
if *x == ch {
return Some(P2_VALUES_U[i]);
}
}
for (i, x) in P10_LETTERS.iter().enumerate() {
if *x == ch {
return Some(P10_VALUES_U[i]);
}
}
None
}