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