oxidd_rules_mtbdd/terminal/
f64.rs1use std::fmt;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::ops::{Add, Div, Mul, Sub};
5use std::str::FromStr;
6
7use oxidd_core::function::NumberBase;
8
9#[derive(Clone, Copy)]
13pub struct F64(f64);
14
15impl PartialEq for F64 {
16 #[inline]
17 fn eq(&self, other: &Self) -> bool {
18 self.0.to_bits() == other.0.to_bits()
19 }
20}
21impl Eq for F64 {}
22impl PartialOrd for F64 {
23 #[inline]
24 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
25 if self.0.to_bits() == f64::NAN.to_bits() {
26 if other.0.to_bits() == f64::NAN.to_bits() {
27 Some(std::cmp::Ordering::Equal)
28 } else {
29 None
30 }
31 } else {
32 self.0.partial_cmp(&other.0)
33 }
34 }
35}
36
37impl Hash for F64 {
38 #[inline]
39 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
40 self.0.to_bits().hash(state);
41 }
42}
43
44impl From<f64> for F64 {
45 #[inline]
46 fn from(value: f64) -> Self {
47 Self(if value.is_nan() {
48 f64::NAN
49 } else if value.to_bits() == (-0.0f64).to_bits() {
50 0.0
51 } else {
52 value
53 })
54 }
55}
56impl From<F64> for f64 {
57 #[inline(always)]
58 fn from(value: F64) -> Self {
59 value.0
60 }
61}
62
63impl NumberBase for F64 {
64 #[inline]
65 fn zero() -> Self {
66 Self(0.)
67 }
68 #[inline]
69 fn one() -> Self {
70 Self(1.)
71 }
72 #[inline]
73 fn nan() -> Self {
74 Self(f64::NAN)
75 }
76
77 #[inline]
78 fn add(&self, rhs: &Self) -> Self {
79 Self::from(self.0 + rhs.0)
80 }
81 #[inline]
82 fn sub(&self, rhs: &Self) -> Self {
83 Self::from(self.0 - rhs.0)
84 }
85 #[inline]
86 fn mul(&self, rhs: &Self) -> Self {
87 Self::from(self.0 * rhs.0)
88 }
89 #[inline]
90 fn div(&self, rhs: &Self) -> Self {
91 Self::from(self.0 / rhs.0)
92 }
93}
94
95impl<Tag: Default> oxidd_dump::ParseTagged<Tag> for F64 {
96 fn parse(s: &str) -> Option<(Self, Tag)> {
97 let val = match s {
98 "nan" | "NaN" | "NAN" => Self(f64::NAN),
99 "-∞" | "-inf" | "-infinity" | "-Inf" | "-Infinity" | "-INF" | "-INFINITY"
100 | "MinusInf" => Self(f64::NEG_INFINITY),
101 "∞" | "inf" | "infinity" | "Inf" | "Infinity" | "INF" | "INFINITY" | "+∞" | "+inf"
102 | "+infinity" | "+Inf" | "+Infinity" | "+INF" | "+INFINITY" | "PlusInf" => {
103 Self(f64::INFINITY)
104 }
105 _ => Self(f64::from_str(s).ok()?),
106 };
107 Some((val, Tag::default()))
108 }
109}
110
111impl Display for F64 {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 if self.0.to_bits() == f64::NAN.to_bits() {
114 f.write_str("NaN")
115 } else if self.0.to_bits() == f64::NEG_INFINITY.to_bits() {
116 f.write_str("-∞")
117 } else if self.0.to_bits() == f64::INFINITY.to_bits() {
118 f.write_str("+∞")
119 } else {
120 self.0.fmt(f)
121 }
122 }
123}
124impl fmt::Debug for F64 {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 Display::fmt(self, f)
127 }
128}
129
130impl oxidd_dump::AsciiDisplay for F64 {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 if self.0.to_bits() == f64::NAN.to_bits() {
133 f.write_str("NaN")
134 } else if self.0.to_bits() == f64::NEG_INFINITY.to_bits() {
135 f.write_str("-INF")
136 } else if self.0.to_bits() == f64::INFINITY.to_bits() {
137 f.write_str("+INF")
138 } else {
139 self.0.fmt(f)
140 }
141 }
142}
143
144impl Add for F64 {
145 type Output = F64;
146
147 #[inline]
148 fn add(self, rhs: Self) -> F64 {
149 Self::from(self.0 + rhs.0)
150 }
151}
152
153impl Sub for F64 {
154 type Output = F64;
155
156 #[inline]
157 fn sub(self, rhs: Self) -> F64 {
158 Self::from(self.0 - rhs.0)
159 }
160}
161
162impl Mul for F64 {
163 type Output = F64;
164
165 #[inline]
166 fn mul(self, rhs: Self) -> F64 {
167 Self::from(self.0 * rhs.0)
168 }
169}
170
171impl Div for F64 {
172 type Output = F64;
173
174 #[inline]
175 fn div(self, rhs: Self) -> F64 {
176 Self::from(self.0 / rhs.0)
177 }
178}
179
180super::impl_ref_op!(F64, Add, add);
181super::impl_ref_op!(F64, Sub, sub);
182super::impl_ref_op!(F64, Mul, mul);
183super::impl_ref_op!(F64, Div, div);
184
185#[cfg(test)]
186mod test {
187 use oxidd_core::function::NumberBase;
188
189 use super::F64;
190
191 #[test]
192 fn nan_eq_ord() {
193 let nan = F64::nan();
194 assert!(nan <= nan);
195 assert!(nan == nan);
196 assert!(nan >= nan);
197 }
198
199 #[test]
200 fn zero_ord() {
201 assert!(F64::from(-0.0) <= F64::from(0.0));
202 assert!(F64::from(-0.0) == F64::from(0.0));
203 assert!(F64::from(-0.0) >= F64::from(0.0));
204 }
205}