softfloat_wrapper/
f64.rs

1use crate::{Float, RoundingMode, BF16, F128, F16, F32};
2use softfloat_sys::float64_t;
3use std::borrow::Borrow;
4
5/// standard 64-bit float
6#[derive(Copy, Clone, Debug)]
7pub struct F64(float64_t);
8
9impl F64 {
10    /// Converts primitive `f32` to `F64`
11    pub fn from_f32(v: f32) -> Self {
12        F32::from_bits(v.to_bits()).to_f64(RoundingMode::TiesToEven)
13    }
14
15    /// Converts primitive `f64` to `F64`
16    pub fn from_f64(v: f64) -> Self {
17        Self::from_bits(v.to_bits())
18    }
19}
20
21impl Float for F64 {
22    type Payload = u64;
23
24    const EXPONENT_BIT: Self::Payload = 0x7ff;
25    const FRACTION_BIT: Self::Payload = 0xf_ffff_ffff_ffff;
26    const SIGN_POS: usize = 63;
27    const EXPONENT_POS: usize = 52;
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(float64_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::f64_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::f64_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::f64_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::f64_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::f64_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::f64_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::f64_sqrt(self.0) };
88        Self(ret)
89    }
90
91    fn eq<T: Borrow<Self>>(&self, x: T) -> bool {
92        unsafe { softfloat_sys::f64_eq(self.0, x.borrow().0) }
93    }
94
95    fn lt<T: Borrow<Self>>(&self, x: T) -> bool {
96        unsafe { softfloat_sys::f64_lt(self.0, x.borrow().0) }
97    }
98
99    fn le<T: Borrow<Self>>(&self, x: T) -> bool {
100        unsafe { softfloat_sys::f64_le(self.0, x.borrow().0) }
101    }
102
103    fn lt_quiet<T: Borrow<Self>>(&self, x: T) -> bool {
104        unsafe { softfloat_sys::f64_lt_quiet(self.0, x.borrow().0) }
105    }
106
107    fn le_quiet<T: Borrow<Self>>(&self, x: T) -> bool {
108        unsafe { softfloat_sys::f64_le_quiet(self.0, x.borrow().0) }
109    }
110
111    fn eq_signaling<T: Borrow<Self>>(&self, x: T) -> bool {
112        unsafe { softfloat_sys::f64_eq_signaling(self.0, x.borrow().0) }
113    }
114
115    fn is_signaling_nan(&self) -> bool {
116        unsafe { softfloat_sys::f64_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_f64(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_f64(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_f64(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_f64(x) };
140        Self(ret)
141    }
142
143    fn to_u32(&self, rnd: RoundingMode, exact: bool) -> u32 {
144        let ret = unsafe { softfloat_sys::f64_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::f64_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::f64_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::f64_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::f64_to_f16(self.0) };
166        F16::from_bits(ret.v)
167    }
168
169    fn to_bf16(&self, rnd: RoundingMode) -> BF16 {
170        rnd.set();
171        let ret = unsafe { softfloat_sys::f64_to_f32(self.0) };
172        BF16::from_bits((ret.v >> 16) as u16)
173    }
174
175    fn to_f32(&self, rnd: RoundingMode) -> F32 {
176        rnd.set();
177        let ret = unsafe { softfloat_sys::f64_to_f32(self.0) };
178        F32::from_bits(ret.v)
179    }
180
181    fn to_f64(&self, _rnd: RoundingMode) -> F64 {
182        Self::from_bits(self.to_bits())
183    }
184
185    fn to_f128(&self, rnd: RoundingMode) -> F128 {
186        rnd.set();
187        let ret = unsafe { softfloat_sys::f64_to_f128(self.0) };
188        let mut v = 0u128;
189        v |= ret.v[0] as u128;
190        v |= (ret.v[1] as u128) << 64;
191        F128::from_bits(v)
192    }
193
194    fn round_to_integral(&self, rnd: RoundingMode) -> Self {
195        let ret = unsafe { softfloat_sys::f64_roundToInt(self.0, rnd.to_softfloat(), false) };
196        Self(ret)
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203    use crate::ExceptionFlags;
204    use std::cmp::Ordering;
205
206    #[test]
207    fn f64_add() {
208        let a = 0x12345678ffffffff;
209        let b = 0x76546410aaaaaaaa;
210        let a0 = F64::from_bits(a);
211        let b0 = F64::from_bits(b);
212        let d0 = a0.add(b0, RoundingMode::TiesToEven);
213        let a1 = simple_soft_float::F64::from_bits(a);
214        let b1 = simple_soft_float::F64::from_bits(b);
215        let d1 = a1.add(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
216        assert_eq!(d0.to_bits(), *d1.bits());
217    }
218
219    #[test]
220    fn f64_sub() {
221        let a = 0x12345678ffffffff;
222        let b = 0x76546410aaaaaaaa;
223        let a0 = F64::from_bits(a);
224        let b0 = F64::from_bits(b);
225        let d0 = a0.sub(b0, RoundingMode::TiesToEven);
226        let a1 = simple_soft_float::F64::from_bits(a);
227        let b1 = simple_soft_float::F64::from_bits(b);
228        let d1 = a1.sub(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
229        assert_eq!(d0.to_bits(), *d1.bits());
230    }
231
232    #[test]
233    fn f64_mul() {
234        let a = 0x12345678ffffffff;
235        let b = 0x76546410aaaaaaaa;
236        let a0 = F64::from_bits(a);
237        let b0 = F64::from_bits(b);
238        let d0 = a0.mul(b0, RoundingMode::TiesToEven);
239        let a1 = simple_soft_float::F64::from_bits(a);
240        let b1 = simple_soft_float::F64::from_bits(b);
241        let d1 = a1.mul(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
242        assert_eq!(d0.to_bits(), *d1.bits());
243    }
244
245    #[test]
246    fn f64_fused_mul_add() {
247        let a = 0x12345678ffffffff;
248        let b = 0x12345678aaaaaaaa;
249        let c = 0x12345678aaaaaaaa;
250        let a0 = F64::from_bits(a);
251        let b0 = F64::from_bits(b);
252        let c0 = F64::from_bits(c);
253        let d0 = a0.fused_mul_add(b0, c0, RoundingMode::TiesToEven);
254        let a1 = simple_soft_float::F64::from_bits(a);
255        let b1 = simple_soft_float::F64::from_bits(b);
256        let c1 = simple_soft_float::F64::from_bits(c);
257        let d1 = a1.fused_mul_add(
258            &b1,
259            &c1,
260            Some(simple_soft_float::RoundingMode::TiesToEven),
261            None,
262        );
263        assert_eq!(d0.to_bits(), *d1.bits());
264    }
265
266    #[test]
267    fn f64_div() {
268        let a = 0x76545678ffffffff;
269        let b = 0x12346410aaaaaaaa;
270        let a0 = F64::from_bits(a);
271        let b0 = F64::from_bits(b);
272        let d0 = a0.div(b0, RoundingMode::TiesToEven);
273        let a1 = simple_soft_float::F64::from_bits(a);
274        let b1 = simple_soft_float::F64::from_bits(b);
275        let d1 = a1.div(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
276        assert_eq!(d0.to_bits(), *d1.bits());
277    }
278
279    #[test]
280    fn f64_rem() {
281        let a = 0x76545678ffffffff;
282        let b = 0x12346410aaaaaaaa;
283        let a0 = F64::from_bits(a);
284        let b0 = F64::from_bits(b);
285        let d0 = a0.rem(b0, RoundingMode::TiesToEven);
286        let a1 = simple_soft_float::F64::from_bits(a);
287        let b1 = simple_soft_float::F64::from_bits(b);
288        let d1 = a1.ieee754_remainder(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
289        assert_eq!(d0.to_bits(), *d1.bits());
290    }
291
292    #[test]
293    fn f64_sqrt() {
294        let a = 0x76546410aaaaaaaa;
295        let a0 = F64::from_bits(a);
296        let d0 = a0.sqrt(RoundingMode::TiesToEven);
297        let a1 = simple_soft_float::F64::from_bits(a);
298        let d1 = a1.sqrt(Some(simple_soft_float::RoundingMode::TiesToEven), None);
299        assert_eq!(d0.to_bits(), *d1.bits());
300    }
301
302    #[test]
303    fn f64_compare() {
304        let a = F64::from_bits(0x76546410ffffffff);
305        let b = F64::from_bits(0x12345678aaaaaaaa);
306        let d = a.compare(b);
307        assert_eq!(d, Some(Ordering::Greater));
308
309        let a = F64::from_bits(0x12345678ffffffff);
310        let b = F64::from_bits(0x76546410aaaaaaaa);
311        let d = a.compare(b);
312        assert_eq!(d, Some(Ordering::Less));
313
314        let a = F64::from_bits(0x12345678aaaaaaaa);
315        let b = F64::from_bits(0x12345678aaaaaaaa);
316        let d = a.compare(b);
317        assert_eq!(d, Some(Ordering::Equal));
318    }
319
320    #[test]
321    fn f64_signaling() {
322        let a = F64::from_bits(0x7ff0000000000001);
323        let b = F64::from_bits(0x7ff8000000000001);
324        assert_eq!(a.is_signaling_nan(), true);
325        assert_eq!(b.is_signaling_nan(), false);
326
327        let mut flag = ExceptionFlags::default();
328        flag.set();
329        assert_eq!(a.eq(a), false);
330        flag.get();
331        assert_eq!(flag.is_invalid(), true);
332
333        let mut flag = ExceptionFlags::default();
334        flag.set();
335        assert_eq!(b.eq(b), false);
336        flag.get();
337        assert_eq!(flag.is_invalid(), false);
338
339        let mut flag = ExceptionFlags::default();
340        flag.set();
341        assert_eq!(a.eq_signaling(a), false);
342        flag.get();
343        assert_eq!(flag.is_invalid(), true);
344
345        let mut flag = ExceptionFlags::default();
346        flag.set();
347        assert_eq!(b.eq_signaling(b), false);
348        flag.get();
349        assert_eq!(flag.is_invalid(), true);
350    }
351
352    #[test]
353    fn from_f32() {
354        let a = F64::from_f32(0.1);
355        assert_eq!(a.to_bits(), 0x3fb99999a0000000);
356    }
357
358    #[test]
359    fn from_f64() {
360        let a = F64::from_f64(0.1);
361        assert_eq!(a.to_bits(), 0x3fb999999999999a);
362    }
363}