wasmi_core/
nan_preserving_float.rs

1macro_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            /// Creates a float from its underlying bits.
46            #[inline]
47            pub fn from_bits(other: $rep) -> Self {
48                Self(other)
49            }
50
51            /// Returns the underlying bits of the float.
52            #[inline]
53            pub fn to_bits(self) -> $rep {
54                self.0
55            }
56
57            /// Creates a float from the respective primitive float type.
58            #[inline]
59            pub fn from_float(float: $is) -> Self {
60                Self(float.to_bits())
61            }
62
63            /// Returns the respective primitive float type.
64            #[inline]
65            pub fn to_float(self) -> $is {
66                <$is>::from_bits(self.0)
67            }
68
69            /// Returns `true` if the float is not a number (NaN).
70            #[inline]
71            pub fn is_nan(self) -> ::core::primitive::bool {
72                self.to_float().is_nan()
73            }
74
75            /// Returns the absolute value of the float.
76            #[must_use]
77            #[inline]
78            pub fn abs(self) -> Self {
79                Self(self.0 & !$sign_bit)
80            }
81
82            /// Returns the fractional part of the float.
83            #[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            /// Returns the minimum float between `self` and `other`.
92            #[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            /// Returns the maximum float between `self` and `other`.
99            #[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    /// A NaN preserving `f32` type.
173    struct F32(u32 as f32);
174}
175
176float! {
177    /// A NaN preserving `f64` type.
178    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}