softfloat_wrapper/
f32.rs

1use crate::{Float, RoundingMode, BF16, F128, F16, F64};
2use softfloat_sys::float32_t;
3use std::borrow::Borrow;
4
5/// standard 32-bit float
6#[derive(Copy, Clone, Debug)]
7pub struct F32(float32_t);
8
9impl F32 {
10    /// Converts primitive `f32` to `F32`
11    pub fn from_f32(v: f32) -> Self {
12        Self::from_bits(v.to_bits())
13    }
14
15    /// Converts primitive `f64` to `F32`
16    pub fn from_f64(v: f64) -> Self {
17        F64::from_bits(v.to_bits()).to_f32(RoundingMode::TiesToEven)
18    }
19}
20
21impl Float for F32 {
22    type Payload = u32;
23
24    const EXPONENT_BIT: Self::Payload = 0xff;
25    const FRACTION_BIT: Self::Payload = 0x7f_ffff;
26    const SIGN_POS: usize = 31;
27    const EXPONENT_POS: usize = 23;
28
29    #[inline]
30    fn set_payload(&mut self, x: Self::Payload) {
31        self.0.v = x;
32    }
33
34    #[inline]
35    fn from_bits(v: Self::Payload) -> Self {
36        Self(float32_t { v })
37    }
38
39    #[inline]
40    fn to_bits(&self) -> Self::Payload {
41        self.0.v
42    }
43
44    #[inline]
45    fn bits(&self) -> Self::Payload {
46        self.to_bits()
47    }
48
49    fn add<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
50        rnd.set();
51        let ret = unsafe { softfloat_sys::f32_add(self.0, x.borrow().0) };
52        Self(ret)
53    }
54
55    fn sub<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
56        rnd.set();
57        let ret = unsafe { softfloat_sys::f32_sub(self.0, x.borrow().0) };
58        Self(ret)
59    }
60
61    fn mul<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
62        rnd.set();
63        let ret = unsafe { softfloat_sys::f32_mul(self.0, x.borrow().0) };
64        Self(ret)
65    }
66
67    fn fused_mul_add<T: Borrow<Self>>(&self, x: T, y: T, rnd: RoundingMode) -> Self {
68        rnd.set();
69        let ret = unsafe { softfloat_sys::f32_mulAdd(self.0, x.borrow().0, y.borrow().0) };
70        Self(ret)
71    }
72
73    fn div<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
74        rnd.set();
75        let ret = unsafe { softfloat_sys::f32_div(self.0, x.borrow().0) };
76        Self(ret)
77    }
78
79    fn rem<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
80        rnd.set();
81        let ret = unsafe { softfloat_sys::f32_rem(self.0, x.borrow().0) };
82        Self(ret)
83    }
84
85    fn sqrt(&self, rnd: RoundingMode) -> Self {
86        rnd.set();
87        let ret = unsafe { softfloat_sys::f32_sqrt(self.0) };
88        Self(ret)
89    }
90
91    fn eq<T: Borrow<Self>>(&self, x: T) -> bool {
92        unsafe { softfloat_sys::f32_eq(self.0, x.borrow().0) }
93    }
94
95    fn lt<T: Borrow<Self>>(&self, x: T) -> bool {
96        unsafe { softfloat_sys::f32_lt(self.0, x.borrow().0) }
97    }
98
99    fn le<T: Borrow<Self>>(&self, x: T) -> bool {
100        unsafe { softfloat_sys::f32_le(self.0, x.borrow().0) }
101    }
102
103    fn lt_quiet<T: Borrow<Self>>(&self, x: T) -> bool {
104        unsafe { softfloat_sys::f32_lt_quiet(self.0, x.borrow().0) }
105    }
106
107    fn le_quiet<T: Borrow<Self>>(&self, x: T) -> bool {
108        unsafe { softfloat_sys::f32_le_quiet(self.0, x.borrow().0) }
109    }
110
111    fn eq_signaling<T: Borrow<Self>>(&self, x: T) -> bool {
112        unsafe { softfloat_sys::f32_eq_signaling(self.0, x.borrow().0) }
113    }
114
115    fn is_signaling_nan(&self) -> bool {
116        unsafe { softfloat_sys::f32_isSignalingNaN(self.0) }
117    }
118
119    fn from_u32(x: u32, rnd: RoundingMode) -> Self {
120        rnd.set();
121        let ret = unsafe { softfloat_sys::ui32_to_f32(x) };
122        Self(ret)
123    }
124
125    fn from_u64(x: u64, rnd: RoundingMode) -> Self {
126        rnd.set();
127        let ret = unsafe { softfloat_sys::ui64_to_f32(x) };
128        Self(ret)
129    }
130
131    fn from_i32(x: i32, rnd: RoundingMode) -> Self {
132        rnd.set();
133        let ret = unsafe { softfloat_sys::i32_to_f32(x) };
134        Self(ret)
135    }
136
137    fn from_i64(x: i64, rnd: RoundingMode) -> Self {
138        rnd.set();
139        let ret = unsafe { softfloat_sys::i64_to_f32(x) };
140        Self(ret)
141    }
142
143    fn to_u32(&self, rnd: RoundingMode, exact: bool) -> u32 {
144        let ret = unsafe { softfloat_sys::f32_to_ui32(self.0, rnd.to_softfloat(), exact) };
145        ret as u32
146    }
147
148    fn to_u64(&self, rnd: RoundingMode, exact: bool) -> u64 {
149        let ret = unsafe { softfloat_sys::f32_to_ui64(self.0, rnd.to_softfloat(), exact) };
150        ret
151    }
152
153    fn to_i32(&self, rnd: RoundingMode, exact: bool) -> i32 {
154        let ret = unsafe { softfloat_sys::f32_to_i32(self.0, rnd.to_softfloat(), exact) };
155        ret as i32
156    }
157
158    fn to_i64(&self, rnd: RoundingMode, exact: bool) -> i64 {
159        let ret = unsafe { softfloat_sys::f32_to_i64(self.0, rnd.to_softfloat(), exact) };
160        ret
161    }
162
163    fn to_f16(&self, rnd: RoundingMode) -> F16 {
164        rnd.set();
165        let ret = unsafe { softfloat_sys::f32_to_f16(self.0) };
166        F16::from_bits(ret.v)
167    }
168
169    fn to_bf16(&self, _rnd: RoundingMode) -> BF16 {
170        BF16::from_bits((self.to_bits() >> 16) as u16)
171    }
172
173    fn to_f32(&self, _rnd: RoundingMode) -> F32 {
174        Self::from_bits(self.to_bits())
175    }
176
177    fn to_f64(&self, rnd: RoundingMode) -> F64 {
178        rnd.set();
179        let ret = unsafe { softfloat_sys::f32_to_f64(self.0) };
180        F64::from_bits(ret.v)
181    }
182
183    fn to_f128(&self, rnd: RoundingMode) -> F128 {
184        rnd.set();
185        let ret = unsafe { softfloat_sys::f32_to_f128(self.0) };
186        let mut v = 0u128;
187        v |= ret.v[0] as u128;
188        v |= (ret.v[1] as u128) << 64;
189        F128::from_bits(v)
190    }
191
192    fn round_to_integral(&self, rnd: RoundingMode) -> Self {
193        let ret = unsafe { softfloat_sys::f32_roundToInt(self.0, rnd.to_softfloat(), false) };
194        Self(ret)
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201    use crate::ExceptionFlags;
202    use std::cmp::Ordering;
203
204    #[test]
205    fn f32_add() {
206        let a = 0x12345678;
207        let b = 0x76543210;
208        let a0 = F32::from_bits(a);
209        let b0 = F32::from_bits(b);
210        let d0 = a0.add(b0, RoundingMode::TiesToEven);
211        let a1 = simple_soft_float::F32::from_bits(a);
212        let b1 = simple_soft_float::F32::from_bits(b);
213        let d1 = a1.add(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
214        assert_eq!(d0.to_bits(), *d1.bits());
215    }
216
217    #[test]
218    fn f32_sub() {
219        let a = 0x12345678;
220        let b = 0x76543210;
221        let a0 = F32::from_bits(a);
222        let b0 = F32::from_bits(b);
223        let d0 = a0.sub(b0, RoundingMode::TiesToEven);
224        let a1 = simple_soft_float::F32::from_bits(a);
225        let b1 = simple_soft_float::F32::from_bits(b);
226        let d1 = a1.sub(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
227        assert_eq!(d0.to_bits(), *d1.bits());
228    }
229
230    #[test]
231    fn f32_mul() {
232        let a = 0x12345678;
233        let b = 0x76543210;
234        let a0 = F32::from_bits(a);
235        let b0 = F32::from_bits(b);
236        let d0 = a0.mul(b0, RoundingMode::TiesToEven);
237        let a1 = simple_soft_float::F32::from_bits(a);
238        let b1 = simple_soft_float::F32::from_bits(b);
239        let d1 = a1.mul(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
240        assert_eq!(d0.to_bits(), *d1.bits());
241    }
242
243    #[test]
244    fn f32_fused_mul_add() {
245        let a = 0x12345678;
246        let b = 0x12345678;
247        let c = 0x12345678;
248        let a0 = F32::from_bits(a);
249        let b0 = F32::from_bits(b);
250        let c0 = F32::from_bits(c);
251        let d0 = a0.fused_mul_add(b0, c0, RoundingMode::TiesToEven);
252        let a1 = simple_soft_float::F32::from_bits(a);
253        let b1 = simple_soft_float::F32::from_bits(b);
254        let c1 = simple_soft_float::F32::from_bits(c);
255        let d1 = a1.fused_mul_add(
256            &b1,
257            &c1,
258            Some(simple_soft_float::RoundingMode::TiesToEven),
259            None,
260        );
261        assert_eq!(d0.to_bits(), *d1.bits());
262    }
263
264    #[test]
265    fn f32_div() {
266        let a = 0x76545678;
267        let b = 0x12343210;
268        let a0 = F32::from_bits(a);
269        let b0 = F32::from_bits(b);
270        let d0 = a0.div(b0, RoundingMode::TiesToEven);
271        let a1 = simple_soft_float::F32::from_bits(a);
272        let b1 = simple_soft_float::F32::from_bits(b);
273        let d1 = a1.div(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
274        assert_eq!(d0.to_bits(), *d1.bits());
275    }
276
277    #[test]
278    fn f32_rem() {
279        let a = 0x76545678;
280        let b = 0x12343210;
281        let a0 = F32::from_bits(a);
282        let b0 = F32::from_bits(b);
283        let d0 = a0.rem(b0, RoundingMode::TiesToEven);
284        let a1 = simple_soft_float::F32::from_bits(a);
285        let b1 = simple_soft_float::F32::from_bits(b);
286        let d1 = a1.ieee754_remainder(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
287        assert_eq!(d0.to_bits(), *d1.bits());
288    }
289
290    #[test]
291    fn f32_sqrt() {
292        let a = 0x76543210;
293        let a0 = F32::from_bits(a);
294        let d0 = a0.sqrt(RoundingMode::TiesToEven);
295        let a1 = simple_soft_float::F32::from_bits(a);
296        let d1 = a1.sqrt(Some(simple_soft_float::RoundingMode::TiesToEven), None);
297        assert_eq!(d0.to_bits(), *d1.bits());
298    }
299
300    #[test]
301    fn f32_compare() {
302        let a = F32::from_bits(0x76543210);
303        let b = F32::from_bits(0x12345678);
304        let d = a.compare(b);
305        assert_eq!(d, Some(Ordering::Greater));
306
307        let a = F32::from_bits(0x12345678);
308        let b = F32::from_bits(0x76543210);
309        let d = a.compare(b);
310        assert_eq!(d, Some(Ordering::Less));
311
312        let a = F32::from_bits(0x12345678);
313        let b = F32::from_bits(0x12345678);
314        let d = a.compare(b);
315        assert_eq!(d, Some(Ordering::Equal));
316    }
317
318    #[test]
319    fn f32_signaling() {
320        let a = F32::from_bits(0x7f800001);
321        let b = F32::from_bits(0x7fc00001);
322        assert_eq!(a.is_signaling_nan(), true);
323        assert_eq!(b.is_signaling_nan(), false);
324
325        let mut flag = ExceptionFlags::default();
326        flag.set();
327        assert_eq!(a.eq(a), false);
328        flag.get();
329        assert_eq!(flag.is_invalid(), true);
330
331        let mut flag = ExceptionFlags::default();
332        flag.set();
333        assert_eq!(b.eq(b), false);
334        flag.get();
335        assert_eq!(flag.is_invalid(), false);
336
337        let mut flag = ExceptionFlags::default();
338        flag.set();
339        assert_eq!(a.eq_signaling(a), false);
340        flag.get();
341        assert_eq!(flag.is_invalid(), true);
342
343        let mut flag = ExceptionFlags::default();
344        flag.set();
345        assert_eq!(b.eq_signaling(b), false);
346        flag.get();
347        assert_eq!(flag.is_invalid(), true);
348    }
349
350    #[test]
351    fn from_f32() {
352        let a = F32::from_f32(0.1);
353        assert_eq!(a.to_bits(), 0x3dcccccd);
354    }
355
356    #[test]
357    fn from_f64() {
358        let a = F32::from_f64(0.1);
359        assert_eq!(a.to_bits(), 0x3dcccccd);
360    }
361}