softfloat_wrapper/
f128.rs

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