softfloat_wrapper_riscv/
lib.rs

1//! softfloat-wrapper is a safe wrapper of [Berkeley SoftFloat](https://github.com/ucb-bar/berkeley-softfloat-3) based on [softfloat-sys](https://crates.io/crates/softfloat-sys).
2//!
3//! ## Examples
4//!
5//! ```
6//! use softfloat_wrapper::{Float, F16, RoundingMode};
7//!
8//! fn main() {
9//!     let a = 0x1234;
10//!     let b = 0x1479;
11//!
12//!     let a = F16::from_bits(a);
13//!     let b = F16::from_bits(b);
14//!     let d = a.add(b, RoundingMode::TiesToEven);
15//!
16//!     let a = f32::from_bits(a.to_f32(RoundingMode::TiesToEven).bits());
17//!     let b = f32::from_bits(b.to_f32(RoundingMode::TiesToEven).bits());
18//!     let d = f32::from_bits(d.to_f32(RoundingMode::TiesToEven).bits());
19//!
20//!     println!("{} + {} = {}", a, b, d);
21//! }
22//! ```
23
24mod f128;
25mod f16;
26mod f32;
27mod f64;
28pub use crate::f128::F128;
29pub use crate::f16::F16;
30pub use crate::f32::F32;
31pub use crate::f64::F64;
32
33use num_traits::{
34    identities::{One, Zero},
35    PrimInt,
36};
37use std::borrow::Borrow;
38use std::cmp::Ordering;
39use std::fmt::{LowerHex, UpperHex};
40
41/// floating-point rounding mode defined by standard
42#[derive(Copy, Clone, Debug)]
43pub enum RoundingMode {
44    /// to nearest, ties to even
45    TiesToEven,
46    /// toward 0
47    TowardZero,
48    /// toward −∞
49    TowardNegative,
50    /// toward +∞
51    TowardPositive,
52    /// to nearest, ties away from zero
53    TiesToAway,
54}
55
56impl RoundingMode {
57    fn set(&self) {
58        unsafe {
59            softfloat_sys_riscv::softfloat_roundingMode_write_helper(self.to_softfloat());
60        }
61    }
62
63    fn to_softfloat(&self) -> u8 {
64        match self {
65            RoundingMode::TiesToEven => softfloat_sys_riscv::softfloat_round_near_even,
66            RoundingMode::TowardZero => softfloat_sys_riscv::softfloat_round_minMag,
67            RoundingMode::TowardNegative => softfloat_sys_riscv::softfloat_round_min,
68            RoundingMode::TowardPositive => softfloat_sys_riscv::softfloat_round_max,
69            RoundingMode::TiesToAway => softfloat_sys_riscv::softfloat_round_near_maxMag,
70        }
71    }
72}
73
74/// exception flags defined by standard
75///
76/// ## Examples
77///
78/// ```
79/// use softfloat_wrapper::{ExceptionFlags, Float, RoundingMode, F16};
80///
81/// let a = 0x0;
82/// let b = 0x0;
83/// let a = F16::from_bits(a);
84/// let b = F16::from_bits(b);
85/// let mut flag = ExceptionFlags::default();
86/// flag.set();
87/// let _d = a.div(b, RoundingMode::TiesToEven);
88/// flag.get();
89/// assert!(flag.is_invalid());
90/// ```
91#[derive(Copy, Clone, Debug, Default)]
92pub struct ExceptionFlags(u8);
93
94impl ExceptionFlags {
95    const FLAG_INEXACT: u8 = softfloat_sys_riscv::softfloat_flag_inexact;
96    const FLAG_INFINITE: u8 = softfloat_sys_riscv::softfloat_flag_infinite;
97    const FLAG_INVALID: u8 = softfloat_sys_riscv::softfloat_flag_invalid;
98    const FLAG_OVERFLOW: u8 = softfloat_sys_riscv::softfloat_flag_overflow;
99    const FLAG_UNDERFLOW: u8 = softfloat_sys_riscv::softfloat_flag_underflow;
100
101    pub fn from_bits(x: u8) -> Self {
102        Self(x)
103    }
104
105    pub fn bits(&self) -> u8 {
106        self.0
107    }
108
109    pub fn is_inexact(&self) -> bool {
110        self.0 & Self::FLAG_INEXACT != 0
111    }
112
113    pub fn is_infinite(&self) -> bool {
114        self.0 & Self::FLAG_INFINITE != 0
115    }
116
117    pub fn is_invalid(&self) -> bool {
118        self.0 & Self::FLAG_INVALID != 0
119    }
120
121    pub fn is_overflow(&self) -> bool {
122        self.0 & Self::FLAG_OVERFLOW != 0
123    }
124
125    pub fn is_underflow(&self) -> bool {
126        self.0 & Self::FLAG_UNDERFLOW != 0
127    }
128
129    pub fn set(&self) {
130        unsafe {
131            softfloat_sys_riscv::softfloat_exceptionFlags_write_helper(self.bits());
132        }
133    }
134
135    pub fn get(&mut self) {
136        let x = unsafe { softfloat_sys_riscv::softfloat_exceptionFlags_read_helper() };
137        self.0 = x;
138    }
139}
140
141/// arbitrary floting-point type
142///
143/// ## Examples
144///
145/// `Float` can be used for generic functions.
146///
147/// ```
148/// use softfloat_wrapper::{Float, RoundingMode, F16, F32};
149///
150/// fn rsqrt<T: Float>(x: T) -> T {
151///     let ret = x.sqrt(RoundingMode::TiesToEven);
152///     let one = T::from_u8(1, RoundingMode::TiesToEven);
153///     one.div(ret, RoundingMode::TiesToEven)
154/// }
155///
156/// let a = F16::from_bits(0x1234);
157/// let a = rsqrt(a);
158/// let a = F32::from_bits(0x12345678);
159/// let a = rsqrt(a);
160/// ```
161pub trait Float {
162    type Payload: PrimInt + UpperHex + LowerHex;
163
164    const EXPONENT_BIT: Self::Payload;
165    const FRACTION_BIT: Self::Payload;
166    const SIGN_POS: usize;
167    const EXPONENT_POS: usize;
168
169    fn set_payload(&mut self, x: Self::Payload);
170
171    fn from_bits(v: Self::Payload) -> Self;
172
173    fn bits(&self) -> Self::Payload;
174
175    fn add<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
176
177    fn sub<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
178
179    fn mul<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
180
181    fn fused_mul_add<T: Borrow<Self>>(&self, x: T, y: T, rnd: RoundingMode) -> Self;
182
183    fn div<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
184
185    fn rem<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
186
187    fn sqrt(&self, rnd: RoundingMode) -> Self;
188
189    fn compare<T: Borrow<Self>>(&self, x: T) -> Option<Ordering>;
190
191    fn from_u32(x: u32, rnd: RoundingMode) -> Self;
192
193    fn from_u64(x: u64, rnd: RoundingMode) -> Self;
194
195    fn from_i32(x: i32, rnd: RoundingMode) -> Self;
196
197    fn from_i64(x: i64, rnd: RoundingMode) -> Self;
198
199    fn to_u32(&self, rnd: RoundingMode) -> u32;
200
201    fn to_u64(&self, rnd: RoundingMode) -> u64;
202
203    fn to_i32(&self, rnd: RoundingMode) -> i32;
204
205    fn to_i64(&self, rnd: RoundingMode) -> i64;
206
207    fn to_f16(&self, rnd: RoundingMode) -> F16;
208
209    fn to_f32(&self, rnd: RoundingMode) -> F32;
210
211    fn to_f64(&self, rnd: RoundingMode) -> F64;
212
213    fn to_f128(&self, rnd: RoundingMode) -> F128;
214
215    fn round_to_integral(&self, rnd: RoundingMode) -> Self;
216
217    #[inline]
218    fn from_u8(x: u8, rnd: RoundingMode) -> Self
219    where
220        Self: Sized,
221    {
222        Self::from_u32(x as u32, rnd)
223    }
224
225    #[inline]
226    fn from_u16(x: u16, rnd: RoundingMode) -> Self
227    where
228        Self: Sized,
229    {
230        Self::from_u32(x as u32, rnd)
231    }
232
233    #[inline]
234    fn from_i8(x: i8, rnd: RoundingMode) -> Self
235    where
236        Self: Sized,
237    {
238        Self::from_i32(x as i32, rnd)
239    }
240
241    #[inline]
242    fn from_i16(x: i16, rnd: RoundingMode) -> Self
243    where
244        Self: Sized,
245    {
246        Self::from_i32(x as i32, rnd)
247    }
248
249    #[inline]
250    fn neg(&self) -> Self
251    where
252        Self: Sized,
253    {
254        let mut ret = Self::from_bits(self.bits());
255        ret.set_sign(!self.sign());
256        ret
257    }
258
259    #[inline]
260    fn abs(&self) -> Self
261    where
262        Self: Sized,
263    {
264        let mut ret = Self::from_bits(self.bits());
265        ret.set_sign(Self::Payload::zero());
266        ret
267    }
268
269    #[inline]
270    fn sign(&self) -> Self::Payload {
271        (self.bits() >> Self::SIGN_POS) & Self::Payload::one()
272    }
273
274    #[inline]
275    fn exponent(&self) -> Self::Payload {
276        (self.bits() >> Self::EXPONENT_POS) & Self::EXPONENT_BIT
277    }
278
279    #[inline]
280    fn fraction(&self) -> Self::Payload {
281        self.bits() & Self::FRACTION_BIT
282    }
283
284    #[inline]
285    fn is_positive(&self) -> bool {
286        self.sign() == Self::Payload::zero()
287    }
288
289    #[inline]
290    fn is_positive_zero(&self) -> bool {
291        self.is_positive()
292            && self.exponent() == Self::Payload::zero()
293            && self.fraction() == Self::Payload::zero()
294    }
295
296    #[inline]
297    fn is_positive_subnormal(&self) -> bool {
298        self.is_positive()
299            && self.exponent() == Self::Payload::zero()
300            && self.fraction() != Self::Payload::zero()
301    }
302
303    #[inline]
304    fn is_positive_normal(&self) -> bool {
305        self.is_positive()
306            && self.exponent() != Self::Payload::zero()
307            && self.exponent() != Self::EXPONENT_BIT
308    }
309
310    #[inline]
311    fn is_positive_infinity(&self) -> bool {
312        self.is_positive()
313            && self.exponent() == Self::EXPONENT_BIT
314            && self.fraction() == Self::Payload::zero()
315    }
316
317    #[inline]
318    fn is_negative(&self) -> bool {
319        self.sign() == Self::Payload::one()
320    }
321
322    #[inline]
323    fn is_negative_zero(&self) -> bool {
324        self.is_negative()
325            && self.exponent() == Self::Payload::zero()
326            && self.fraction() == Self::Payload::zero()
327    }
328
329    #[inline]
330    fn is_negative_subnormal(&self) -> bool {
331        self.is_negative()
332            && self.exponent() == Self::Payload::zero()
333            && self.fraction() != Self::Payload::zero()
334    }
335
336    #[inline]
337    fn is_negative_normal(&self) -> bool {
338        self.is_negative()
339            && self.exponent() != Self::Payload::zero()
340            && self.exponent() != Self::EXPONENT_BIT
341    }
342
343    #[inline]
344    fn is_negative_infinity(&self) -> bool {
345        self.is_negative()
346            && self.exponent() == Self::EXPONENT_BIT
347            && self.fraction() == Self::Payload::zero()
348    }
349
350    #[inline]
351    fn is_nan(&self) -> bool {
352        self.exponent() == Self::EXPONENT_BIT && self.fraction() != Self::Payload::zero()
353    }
354
355    #[inline]
356    fn is_zero(&self) -> bool {
357        self.is_positive_zero() || self.is_negative_zero()
358    }
359
360    #[inline]
361    fn is_subnormal(&self) -> bool {
362        self.exponent() == Self::Payload::zero()
363    }
364
365    #[inline]
366    fn set_sign(&mut self, x: Self::Payload) {
367        self.set_payload(
368            (self.bits() & !(Self::Payload::one() << Self::SIGN_POS))
369                | ((x & Self::Payload::one()) << Self::SIGN_POS),
370        );
371    }
372
373    #[inline]
374    fn set_exponent(&mut self, x: Self::Payload) {
375        self.set_payload(
376            (self.bits() & !(Self::EXPONENT_BIT << Self::EXPONENT_POS))
377                | ((x & Self::EXPONENT_BIT) << Self::EXPONENT_POS),
378        );
379    }
380
381    #[inline]
382    fn set_fraction(&mut self, x: Self::Payload) {
383        self.set_payload((self.bits() & !Self::FRACTION_BIT) | (x & Self::FRACTION_BIT));
384    }
385
386    #[inline]
387    fn positive_infinity() -> Self
388    where
389        Self: Sized,
390    {
391        let mut x = Self::from_bits(Self::Payload::zero());
392        x.set_exponent(Self::EXPONENT_BIT);
393        x
394    }
395
396    #[inline]
397    fn positive_zero() -> Self
398    where
399        Self: Sized,
400    {
401        let x = Self::from_bits(Self::Payload::zero());
402        x
403    }
404
405    #[inline]
406    fn negative_infinity() -> Self
407    where
408        Self: Sized,
409    {
410        let mut x = Self::from_bits(Self::Payload::zero());
411        x.set_sign(Self::Payload::one());
412        x.set_exponent(Self::EXPONENT_BIT);
413        x
414    }
415
416    #[inline]
417    fn negative_zero() -> Self
418    where
419        Self: Sized,
420    {
421        let mut x = Self::from_bits(Self::Payload::zero());
422        x.set_sign(Self::Payload::one());
423        x
424    }
425
426    #[inline]
427    fn quiet_nan() -> Self
428    where
429        Self: Sized,
430    {
431        let mut x = Self::from_bits(Self::Payload::zero());
432        x.set_exponent(Self::EXPONENT_BIT);
433        x.set_fraction(Self::Payload::one() << (Self::EXPONENT_POS - 1));
434        x
435    }
436}
437
438#[cfg(test)]
439mod tests {
440    use super::*;
441
442    #[test]
443    fn flag_inexact() {
444        let a = 0x1234;
445        let b = 0x7654;
446        let a = F16::from_bits(a);
447        let b = F16::from_bits(b);
448        let mut flag = ExceptionFlags::default();
449        flag.set();
450        let _d = a.add(b, RoundingMode::TiesToEven);
451        flag.get();
452        assert!(flag.is_inexact());
453        assert!(!flag.is_infinite());
454        assert!(!flag.is_invalid());
455        assert!(!flag.is_overflow());
456        assert!(!flag.is_underflow());
457    }
458
459    #[test]
460    fn flag_infinite() {
461        let a = 0x1234;
462        let b = 0x0;
463        let a = F16::from_bits(a);
464        let b = F16::from_bits(b);
465        let mut flag = ExceptionFlags::default();
466        flag.set();
467        let _d = a.div(b, RoundingMode::TiesToEven);
468        flag.get();
469        assert!(!flag.is_inexact());
470        assert!(flag.is_infinite());
471        assert!(!flag.is_invalid());
472        assert!(!flag.is_overflow());
473        assert!(!flag.is_underflow());
474    }
475
476    #[test]
477    fn flag_invalid() {
478        let a = 0x0;
479        let b = 0x0;
480        let a = F16::from_bits(a);
481        let b = F16::from_bits(b);
482        let mut flag = ExceptionFlags::default();
483        flag.set();
484        let _d = a.div(b, RoundingMode::TiesToEven);
485        flag.get();
486        assert!(!flag.is_inexact());
487        assert!(!flag.is_infinite());
488        assert!(flag.is_invalid());
489        assert!(!flag.is_overflow());
490        assert!(!flag.is_underflow());
491    }
492
493    #[test]
494    fn flag_overflow() {
495        let a = 0x7bff;
496        let b = 0x7bff;
497        let a = F16::from_bits(a);
498        let b = F16::from_bits(b);
499        let mut flag = ExceptionFlags::default();
500        flag.set();
501        let _d = a.add(b, RoundingMode::TiesToEven);
502        flag.get();
503        assert!(flag.is_inexact());
504        assert!(!flag.is_infinite());
505        assert!(!flag.is_invalid());
506        assert!(flag.is_overflow());
507        assert!(!flag.is_underflow());
508    }
509
510    #[test]
511    fn flag_underflow() {
512        let a = 0x0001;
513        let b = 0x0001;
514        let a = F16::from_bits(a);
515        let b = F16::from_bits(b);
516        let mut flag = ExceptionFlags::default();
517        flag.set();
518        let _d = a.mul(b, RoundingMode::TiesToEven);
519        flag.get();
520        assert!(flag.is_inexact());
521        assert!(!flag.is_infinite());
522        assert!(!flag.is_invalid());
523        assert!(!flag.is_overflow());
524        assert!(flag.is_underflow());
525    }
526}