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