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