use std::fmt::{self, Write};
use crate::utilities::math_utilities::{max_f32, min_f32};
struct StackBuf {
bytes: [u8; 32],
len: usize,
}
impl Write for StackBuf {
fn write_str(&mut self, s: &str) -> fmt::Result {
let end = self.len + s.len();
if end > self.bytes.len() {
return Err(fmt::Error);
}
self.bytes[self.len..end].copy_from_slice(s.as_bytes());
self.len = end;
Ok(())
}
}
#[derive(Clone, Copy, Debug)]
pub struct InvariantF32(pub f32);
impl fmt::Display for InvariantF32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = self.0;
if value.is_nan() {
return f.write_str("NaN");
}
if value.is_infinite() {
return f.write_str(if value > 0.0 { "Infinity" } else { "-Infinity" });
}
if value == 0.0 {
return write!(f, "{}", value);
}
let mut buf = StackBuf {
bytes: [0; 32],
len: 0,
};
write!(buf, "{:e}", value)?;
let text = std::str::from_utf8(&buf.bytes[..buf.len]).map_err(|_| fmt::Error)?;
let (mantissa, exponent) = text.split_once('e').ok_or(fmt::Error)?;
let exponent: i32 = exponent.parse().map_err(|_| fmt::Error)?;
if (-4..=8).contains(&exponent) {
return write!(f, "{}", value);
}
write!(
f,
"{}E{}{:02}",
mantissa,
if exponent < 0 { '-' } else { '+' },
exponent.unsigned_abs()
)
}
}
#[inline]
pub(crate) fn max(value1: f32, value2: f32) -> f32 {
max_f32(value1, value2)
}
#[inline]
pub(crate) fn min(value1: f32, value2: f32) -> f32 {
min_f32(value1, value2)
}
pub(crate) fn ieee_remainder(x: f32, y: f32) -> f32 {
if x.is_nan() {
return x;
}
if y.is_nan() {
return y;
}
let regular_mod = x % y;
if regular_mod.is_nan() {
return f32::NAN;
}
if regular_mod == 0.0 && x.is_sign_negative() {
return -0.0;
}
let sign = if x > 0.0 { 1.0 } else { -1.0 };
let alternative_result = regular_mod - (y.abs() * sign);
if alternative_result.abs() == regular_mod.abs() {
let division_result = x / y;
let rounded_result = division_result.round_ties_even();
if rounded_result.abs() > division_result.abs() {
return alternative_result;
}
return regular_mod;
}
if alternative_result.abs() < regular_mod.abs() {
return alternative_result;
}
regular_mod
}