ferroui_base/numerics/
single.rs1use std::fmt::{self, Write};
6
7use crate::utilities::math_utilities::{max_f32, min_f32};
8
9struct StackBuf {
11 bytes: [u8; 32],
12 len: usize,
13}
14
15impl Write for StackBuf {
16 fn write_str(&mut self, s: &str) -> fmt::Result {
17 let end = self.len + s.len();
18 if end > self.bytes.len() {
19 return Err(fmt::Error);
20 }
21 self.bytes[self.len..end].copy_from_slice(s.as_bytes());
22 self.len = end;
23 Ok(())
24 }
25}
26
27#[derive(Clone, Copy, Debug)]
33pub struct InvariantF32(pub f32);
34
35impl fmt::Display for InvariantF32 {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 let value = self.0;
38 if value.is_nan() {
39 return f.write_str("NaN");
40 }
41 if value.is_infinite() {
42 return f.write_str(if value > 0.0 { "Infinity" } else { "-Infinity" });
43 }
44 if value == 0.0 {
45 return write!(f, "{}", value);
46 }
47
48 let mut buf = StackBuf {
49 bytes: [0; 32],
50 len: 0,
51 };
52 write!(buf, "{:e}", value)?;
53 let text = std::str::from_utf8(&buf.bytes[..buf.len]).map_err(|_| fmt::Error)?;
54 let (mantissa, exponent) = text.split_once('e').ok_or(fmt::Error)?;
55 let exponent: i32 = exponent.parse().map_err(|_| fmt::Error)?;
56 if (-4..=8).contains(&exponent) {
57 return write!(f, "{}", value);
58 }
59 write!(
60 f,
61 "{}E{}{:02}",
62 mantissa,
63 if exponent < 0 { '-' } else { '+' },
64 exponent.unsigned_abs()
65 )
66 }
67}
68
69#[inline]
71pub(crate) fn max(value1: f32, value2: f32) -> f32 {
72 max_f32(value1, value2)
73}
74
75#[inline]
77pub(crate) fn min(value1: f32, value2: f32) -> f32 {
78 min_f32(value1, value2)
79}
80
81pub(crate) fn ieee_remainder(x: f32, y: f32) -> f32 {
84 if x.is_nan() {
85 return x;
86 }
87 if y.is_nan() {
88 return y;
89 }
90
91 let regular_mod = x % y;
92 if regular_mod.is_nan() {
93 return f32::NAN;
94 }
95 if regular_mod == 0.0 && x.is_sign_negative() {
96 return -0.0;
97 }
98
99 let sign = if x > 0.0 { 1.0 } else { -1.0 };
101 let alternative_result = regular_mod - (y.abs() * sign);
102 if alternative_result.abs() == regular_mod.abs() {
103 let division_result = x / y;
104 let rounded_result = division_result.round_ties_even();
105 if rounded_result.abs() > division_result.abs() {
106 return alternative_result;
107 }
108 return regular_mod;
109 }
110 if alternative_result.abs() < regular_mod.abs() {
111 return alternative_result;
112 }
113 regular_mod
114}