wasmi_core/
nan_preserving_float.rs1macro_rules! impl_binop {
2 ($for:ty, $is:ty, $op:ident, $func_name:ident) => {
3 impl<T: Into<$for>> ::core::ops::$op<T> for $for {
4 type Output = Self;
5
6 #[inline]
7 fn $func_name(self, other: T) -> Self {
8 Self(
9 ::core::ops::$op::$func_name(
10 <$is>::from_bits(self.0),
11 <$is>::from_bits(other.into().0),
12 )
13 .to_bits(),
14 )
15 }
16 }
17 };
18}
19
20macro_rules! float {
21 (
22 $( #[$docs:meta] )*
23 struct $for:ident($rep:ty as $is:ty);
24 ) => {
25 float!(
26 $(#[$docs])*
27 struct $for($rep as $is, #bits = 1 << (::core::mem::size_of::<$is>() * 8 - 1));
28 );
29 };
30 (
31 $( #[$docs:meta] )*
32 struct $for:ident($rep:ty as $is:ty, #bits = $sign_bit:expr);
33 ) => {
34 $(#[$docs])*
35 #[derive(Copy, Clone)]
36 pub struct $for($rep);
37
38 impl_binop!($for, $is, Add, add);
39 impl_binop!($for, $is, Sub, sub);
40 impl_binop!($for, $is, Mul, mul);
41 impl_binop!($for, $is, Div, div);
42 impl_binop!($for, $is, Rem, rem);
43
44 impl $for {
45 #[inline]
47 pub fn from_bits(other: $rep) -> Self {
48 Self(other)
49 }
50
51 #[inline]
53 pub fn to_bits(self) -> $rep {
54 self.0
55 }
56
57 #[inline]
59 pub fn from_float(float: $is) -> Self {
60 Self(float.to_bits())
61 }
62
63 #[inline]
65 pub fn to_float(self) -> $is {
66 <$is>::from_bits(self.0)
67 }
68
69 #[inline]
71 pub fn is_nan(self) -> ::core::primitive::bool {
72 self.to_float().is_nan()
73 }
74
75 #[must_use]
77 #[inline]
78 pub fn abs(self) -> Self {
79 Self(self.0 & !$sign_bit)
80 }
81
82 #[must_use]
84 #[inline]
85 pub fn fract(self) -> Self {
86 Self::from_float(
87 ::num_traits::float::FloatCore::fract(self.to_float())
88 )
89 }
90
91 #[must_use]
93 #[inline]
94 pub fn min(self, other: Self) -> Self {
95 Self::from(self.to_float().min(other.to_float()))
96 }
97
98 #[must_use]
100 #[inline]
101 pub fn max(self, other: Self) -> Self {
102 Self::from(self.to_float().max(other.to_float()))
103 }
104 }
105
106 impl ::core::convert::From<$is> for $for {
107 #[inline]
108 fn from(float: $is) -> $for {
109 Self::from_float(float)
110 }
111 }
112
113 impl ::core::convert::From<$for> for $is {
114 #[inline]
115 fn from(float: $for) -> $is {
116 float.to_float()
117 }
118 }
119
120 impl ::core::ops::Neg for $for {
121 type Output = Self;
122
123 #[inline]
124 fn neg(self) -> Self {
125 Self(self.0 ^ $sign_bit)
126 }
127 }
128
129 impl<T: ::core::convert::Into<$for> + ::core::marker::Copy> ::core::cmp::PartialEq<T> for $for {
130 #[inline]
131 fn eq(&self, other: &T) -> ::core::primitive::bool {
132 <$is as ::core::convert::From<Self>>::from(*self)
133 .eq(&<$is as ::core::convert::From<Self>>::from((*other).into()))
134 }
135 }
136
137 impl<T: ::core::convert::Into<$for> + ::core::marker::Copy> ::core::cmp::PartialOrd<T> for $for {
138 #[inline]
139 fn partial_cmp(&self, other: &T) -> ::core::option::Option<::core::cmp::Ordering> {
140 <$is as ::core::convert::From<Self>>::from(*self)
141 .partial_cmp(&<$is as ::core::convert::From<Self>>::from((*other).into()))
142 }
143 }
144
145 impl ::core::fmt::Debug for $for {
146 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
147 if self.is_nan() {
148 return core::write!(f, "nan:0x{:X?}", self.to_bits())
149 }
150 <$is as ::core::fmt::Debug>::fmt(
151 &<$is as ::core::convert::From<Self>>::from(*self),
152 f,
153 )
154 }
155 }
156
157 impl ::core::fmt::Display for $for {
158 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
159 if self.is_nan() {
160 return core::write!(f, "nan:0x{:X?}", self.to_bits())
161 }
162 <$is as ::core::fmt::Display>::fmt(
163 &<$is as ::core::convert::From<Self>>::from(*self),
164 f,
165 )
166 }
167 }
168 };
169}
170
171float! {
172 struct F32(u32 as f32);
174}
175
176float! {
177 struct F64(u64 as f64);
179}
180
181impl From<u32> for F32 {
182 #[inline]
183 fn from(other: u32) -> Self {
184 Self::from_bits(other)
185 }
186}
187
188impl From<F32> for u32 {
189 #[inline]
190 fn from(other: F32) -> Self {
191 other.to_bits()
192 }
193}
194
195impl From<u64> for F64 {
196 #[inline]
197 fn from(other: u64) -> Self {
198 Self::from_bits(other)
199 }
200}
201
202impl From<F64> for u64 {
203 #[inline]
204 fn from(other: F64) -> Self {
205 other.to_bits()
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 extern crate rand;
212
213 use self::rand::Rng;
214
215 use super::{F32, F64};
216
217 use core::{
218 fmt::Debug,
219 iter,
220 ops::{Add, Div, Mul, Neg, Sub},
221 };
222
223 fn test_ops<T, F, I>(iter: I)
224 where
225 T: Add<Output = T>
226 + Div<Output = T>
227 + Mul<Output = T>
228 + Sub<Output = T>
229 + Neg<Output = T>
230 + Copy
231 + Debug
232 + PartialEq,
233 F: Into<T>
234 + Add<Output = F>
235 + Div<Output = F>
236 + Mul<Output = F>
237 + Sub<Output = F>
238 + Neg<Output = F>
239 + Copy
240 + Debug,
241 I: IntoIterator<Item = (F, F)>,
242 {
243 for (a, b) in iter {
244 assert_eq!((a + b).into(), a.into() + b.into());
245 assert_eq!((a - b).into(), a.into() - b.into());
246 assert_eq!((a * b).into(), a.into() * b.into());
247 assert_eq!((a / b).into(), a.into() / b.into());
248 assert_eq!((-a).into(), -a.into());
249 assert_eq!((-b).into(), -b.into());
250 }
251 }
252
253 #[test]
254 fn test_ops_f32() {
255 let mut rng = rand::thread_rng();
256 let iter = iter::repeat(()).map(|_| rng.gen());
257
258 test_ops::<F32, f32, _>(iter.take(1000));
259 }
260
261 #[test]
262 fn test_ops_f64() {
263 let mut rng = rand::thread_rng();
264 let iter = iter::repeat(()).map(|_| rng.gen());
265
266 test_ops::<F64, f64, _>(iter.take(1000));
267 }
268
269 #[test]
270 fn test_neg_nan_f32() {
271 assert_eq!((-F32(0xff80_3210)).0, 0x7f80_3210);
272 }
273
274 #[test]
275 fn test_neg_nan_f64() {
276 assert_eq!((-F64(0xff80_3210_0000_0000)).0, 0x7f80_3210_0000_0000);
277 }
278}