1use crate::{Float, RoundingMode, BF16, F128, F16, F64};
2use softfloat_sys::float32_t;
3use std::borrow::Borrow;
4
5#[derive(Copy, Clone, Debug)]
7pub struct F32(float32_t);
8
9impl F32 {
10 pub fn from_f32(v: f32) -> Self {
12 Self::from_bits(v.to_bits())
13 }
14
15 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}