1 use rustc_apfloat::ppc::DoubleDouble;
2 use rustc_apfloat::{Category, Float, Round};
3 
4 use std::cmp::Ordering;
5 
6 #[test]
ppc_double_double()7 fn ppc_double_double() {
8     let test = DoubleDouble::ZERO;
9     let expected = "0x0p+0".parse::<DoubleDouble>().unwrap();
10     assert!(test.is_zero());
11     assert!(!test.is_negative());
12     assert!(test.bitwise_eq(expected));
13     assert_eq!(0, test.to_bits());
14 
15     let test = -DoubleDouble::ZERO;
16     let expected = "-0x0p+0".parse::<DoubleDouble>().unwrap();
17     assert!(test.is_zero());
18     assert!(test.is_negative());
19     assert!(test.bitwise_eq(expected));
20     assert_eq!(0x8000000000000000, test.to_bits());
21 
22     let test = "1.0".parse::<DoubleDouble>().unwrap();
23     assert_eq!(0x3ff0000000000000, test.to_bits());
24 
25     // LDBL_MAX
26     let test = "1.79769313486231580793728971405301e+308".parse::<DoubleDouble>().unwrap();
27     assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, test.to_bits());
28 
29     // LDBL_MIN
30     let test = "2.00416836000897277799610805135016e-292".parse::<DoubleDouble>().unwrap();
31     assert_eq!(0x0000000000000000_0360000000000000, test.to_bits());
32 }
33 
34 #[test]
ppc_double_double_add_special()35 fn ppc_double_double_add_special() {
36     let data = [
37         // (1 + 0) + (-1 + 0) = Category::Zero
38         (0x3ff0000000000000, 0xbff0000000000000, Category::Zero, Round::NearestTiesToEven),
39         // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
40         (
41             0x7c8ffffffffffffe_7fefffffffffffff,
42             0x7948000000000000,
43             Category::Infinity,
44             Round::NearestTiesToEven,
45         ),
46         // FIXME: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
47         // DoubleDouble's fallback is gone.
48         // LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
49         // 160))) = Category::Normal
50         (
51             0x7c8ffffffffffffe_7fefffffffffffff,
52             0x75effffffffffffe_7947ffffffffffff,
53             Category::Normal,
54             Round::NearestTiesToEven,
55         ),
56         // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
57         (
58             0x7c8ffffffffffffe_7fefffffffffffff,
59             0x7c8ffffffffffffe_7fefffffffffffff,
60             Category::Infinity,
61             Round::NearestTiesToEven,
62         ),
63         // NaN + (1 + 0) = Category::NaN
64         (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
65     ];
66 
67     for (op1, op2, expected, round) in data {
68         {
69             let mut a1 = DoubleDouble::from_bits(op1);
70             let a2 = DoubleDouble::from_bits(op2);
71             a1 = a1.add_r(a2, round).value;
72 
73             assert_eq!(expected, a1.category(), "{:#x} + {:#x}", op1, op2);
74         }
75         {
76             let a1 = DoubleDouble::from_bits(op1);
77             let mut a2 = DoubleDouble::from_bits(op2);
78             a2 = a2.add_r(a1, round).value;
79 
80             assert_eq!(expected, a2.category(), "{:#x} + {:#x}", op2, op1);
81         }
82     }
83 }
84 
85 #[test]
ppc_double_double_add()86 fn ppc_double_double_add() {
87     let data = [
88         // (1 + 0) + (1e-105 + 0) = (1 + 1e-105)
89         (
90             0x3ff0000000000000,
91             0x3960000000000000,
92             0x3960000000000000_3ff0000000000000,
93             Round::NearestTiesToEven,
94         ),
95         // (1 + 0) + (1e-106 + 0) = (1 + 1e-106)
96         (
97             0x3ff0000000000000,
98             0x3950000000000000,
99             0x3950000000000000_3ff0000000000000,
100             Round::NearestTiesToEven,
101         ),
102         // (1 + 1e-106) + (1e-106 + 0) = (1 + 1e-105)
103         (
104             0x3950000000000000_3ff0000000000000,
105             0x3950000000000000,
106             0x3960000000000000_3ff0000000000000,
107             Round::NearestTiesToEven,
108         ),
109         // (1 + 0) + (epsilon + 0) = (1 + epsilon)
110         (
111             0x3ff0000000000000,
112             0x0000000000000001,
113             0x0000000000000001_3ff0000000000000,
114             Round::NearestTiesToEven,
115         ),
116         // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
117         // DoubleDouble's fallback is gone.
118         // (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
119         // 1.11111... << (1023 - 52)
120         (
121             0xf950000000000000_7fefffffffffffff,
122             0x7c90000000000000,
123             0x7c8ffffffffffffe_7fefffffffffffff,
124             Round::NearestTiesToEven,
125         ),
126         // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
127         // DoubleDouble's fallback is gone.
128         // (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
129         // 1.11111... << (1023 - 52)
130         (
131             0x7c90000000000000,
132             0xf950000000000000_7fefffffffffffff,
133             0x7c8ffffffffffffe_7fefffffffffffff,
134             Round::NearestTiesToEven,
135         ),
136     ];
137 
138     for (op1, op2, expected, round) in data {
139         {
140             let mut a1 = DoubleDouble::from_bits(op1);
141             let a2 = DoubleDouble::from_bits(op2);
142             a1 = a1.add_r(a2, round).value;
143 
144             assert_eq!(expected, a1.to_bits(), "{:#x} + {:#x}", op1, op2);
145         }
146         {
147             let a1 = DoubleDouble::from_bits(op1);
148             let mut a2 = DoubleDouble::from_bits(op2);
149             a2 = a2.add_r(a1, round).value;
150 
151             assert_eq!(expected, a2.to_bits(), "{:#x} + {:#x}", op2, op1);
152         }
153     }
154 }
155 
156 #[test]
ppc_double_double_subtract()157 fn ppc_double_double_subtract() {
158     let data = [
159         // (1 + 0) - (-1e-105 + 0) = (1 + 1e-105)
160         (
161             0x3ff0000000000000,
162             0xb960000000000000,
163             0x3960000000000000_3ff0000000000000,
164             Round::NearestTiesToEven,
165         ),
166         // (1 + 0) - (-1e-106 + 0) = (1 + 1e-106)
167         (
168             0x3ff0000000000000,
169             0xb950000000000000,
170             0x3950000000000000_3ff0000000000000,
171             Round::NearestTiesToEven,
172         ),
173     ];
174 
175     for (op1, op2, expected, round) in data {
176         let mut a1 = DoubleDouble::from_bits(op1);
177         let a2 = DoubleDouble::from_bits(op2);
178         a1 = a1.sub_r(a2, round).value;
179 
180         assert_eq!(expected, a1.to_bits(), "{:#x} - {:#x}", op1, op2);
181     }
182 }
183 
184 #[test]
ppc_double_double_multiply_special()185 fn ppc_double_double_multiply_special() {
186     let data = [
187         // Category::NaN * Category::NaN = Category::NaN
188         (0x7ff8000000000000, 0x7ff8000000000000, Category::NaN, Round::NearestTiesToEven),
189         // Category::NaN * Category::Zero = Category::NaN
190         (0x7ff8000000000000, 0, Category::NaN, Round::NearestTiesToEven),
191         // Category::NaN * Category::Infinity = Category::NaN
192         (0x7ff8000000000000, 0x7ff0000000000000, Category::NaN, Round::NearestTiesToEven),
193         // Category::NaN * Category::Normal = Category::NaN
194         (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
195         // Category::Infinity * Category::Infinity = Category::Infinity
196         (0x7ff0000000000000, 0x7ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
197         // Category::Infinity * Category::Zero = Category::NaN
198         (0x7ff0000000000000, 0, Category::NaN, Round::NearestTiesToEven),
199         // Category::Infinity * Category::Normal = Category::Infinity
200         (0x7ff0000000000000, 0x3ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
201         // Category::Zero * Category::Zero = Category::Zero
202         (0, 0, Category::Zero, Round::NearestTiesToEven),
203         // Category::Zero * Category::Normal = Category::Zero
204         (0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
205     ];
206 
207     for (op1, op2, expected, round) in data {
208         {
209             let mut a1 = DoubleDouble::from_bits(op1);
210             let a2 = DoubleDouble::from_bits(op2);
211             a1 = a1.mul_r(a2, round).value;
212 
213             assert_eq!(expected, a1.category(), "{:#x} * {:#x}", op1, op2);
214         }
215         {
216             let a1 = DoubleDouble::from_bits(op1);
217             let mut a2 = DoubleDouble::from_bits(op2);
218             a2 = a2.mul_r(a1, round).value;
219 
220             assert_eq!(expected, a2.category(), "{:#x} * {:#x}", op2, op1);
221         }
222     }
223 }
224 
225 #[test]
ppc_double_double_multiply()226 fn ppc_double_double_multiply() {
227     let data = [
228         // 1/3 * 3 = 1.0
229         (
230             0x3c75555555555556_3fd5555555555555,
231             0x4008000000000000,
232             0x3ff0000000000000,
233             Round::NearestTiesToEven,
234         ),
235         // (1 + epsilon) * (1 + 0) = Category::Zero
236         (
237             0x0000000000000001_3ff0000000000000,
238             0x3ff0000000000000,
239             0x0000000000000001_3ff0000000000000,
240             Round::NearestTiesToEven,
241         ),
242         // (1 + epsilon) * (1 + epsilon) = 1 + 2 * epsilon
243         (
244             0x0000000000000001_3ff0000000000000,
245             0x0000000000000001_3ff0000000000000,
246             0x0000000000000002_3ff0000000000000,
247             Round::NearestTiesToEven,
248         ),
249         // -(1 + epsilon) * (1 + epsilon) = -1
250         (
251             0x0000000000000001_bff0000000000000,
252             0x0000000000000001_3ff0000000000000,
253             0xbff0000000000000,
254             Round::NearestTiesToEven,
255         ),
256         // (0.5 + 0) * (1 + 2 * epsilon) = 0.5 + epsilon
257         (
258             0x3fe0000000000000,
259             0x0000000000000002_3ff0000000000000,
260             0x0000000000000001_3fe0000000000000,
261             Round::NearestTiesToEven,
262         ),
263         // (0.5 + 0) * (1 + epsilon) = 0.5
264         (
265             0x3fe0000000000000,
266             0x0000000000000001_3ff0000000000000,
267             0x3fe0000000000000,
268             Round::NearestTiesToEven,
269         ),
270         // __LDBL_MAX__ * (1 + 1 << 106) = inf
271         (
272             0x7c8ffffffffffffe_7fefffffffffffff,
273             0x3950000000000000_3ff0000000000000,
274             0x7ff0000000000000,
275             Round::NearestTiesToEven,
276         ),
277         // __LDBL_MAX__ * (1 + 1 << 107) > __LDBL_MAX__, but not inf, yes =_=|||
278         (
279             0x7c8ffffffffffffe_7fefffffffffffff,
280             0x3940000000000000_3ff0000000000000,
281             0x7c8fffffffffffff_7fefffffffffffff,
282             Round::NearestTiesToEven,
283         ),
284         // __LDBL_MAX__ * (1 + 1 << 108) = __LDBL_MAX__
285         (
286             0x7c8ffffffffffffe_7fefffffffffffff,
287             0x3930000000000000_3ff0000000000000,
288             0x7c8ffffffffffffe_7fefffffffffffff,
289             Round::NearestTiesToEven,
290         ),
291     ];
292 
293     for (op1, op2, expected, round) in data {
294         {
295             let mut a1 = DoubleDouble::from_bits(op1);
296             let a2 = DoubleDouble::from_bits(op2);
297             a1 = a1.mul_r(a2, round).value;
298 
299             assert_eq!(expected, a1.to_bits(), "{:#x} * {:#x}", op1, op2);
300         }
301         {
302             let a1 = DoubleDouble::from_bits(op1);
303             let mut a2 = DoubleDouble::from_bits(op2);
304             a2 = a2.mul_r(a1, round).value;
305 
306             assert_eq!(expected, a2.to_bits(), "{:#x} * {:#x}", op2, op1);
307         }
308     }
309 }
310 
311 #[test]
ppc_double_double_divide()312 fn ppc_double_double_divide() {
313     // FIXME: Only a sanity check for now. Add more edge cases when the
314     // double-double algorithm is implemented.
315     let data = [
316         // 1 / 3 = 1/3
317         (
318             0x3ff0000000000000,
319             0x4008000000000000,
320             0x3c75555555555556_3fd5555555555555,
321             Round::NearestTiesToEven,
322         ),
323     ];
324 
325     for (op1, op2, expected, round) in data {
326         let mut a1 = DoubleDouble::from_bits(op1);
327         let a2 = DoubleDouble::from_bits(op2);
328         a1 = a1.div_r(a2, round).value;
329 
330         assert_eq!(expected, a1.to_bits(), "{:#x} / {:#x}", op1, op2);
331     }
332 }
333 
334 #[test]
ppc_double_double_remainder()335 fn ppc_double_double_remainder() {
336     let data = [
337         // ieee_rem(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
338         (
339             0x3cb8000000000000_4008000000000000,
340             0x3ca4000000000000_3ff4000000000000,
341             0x3c90000000000000_3fe0000000000000,
342         ),
343         // ieee_rem(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (-0.5 - 0.5 << 53)
344         (
345             0x3cb8000000000000_4008000000000000,
346             0x3cac000000000000_3ffc000000000000,
347             0xbc90000000000000_bfe0000000000000,
348         ),
349     ];
350 
351     for (op1, op2, expected) in data {
352         let a1 = DoubleDouble::from_bits(op1);
353         let a2 = DoubleDouble::from_bits(op2);
354         let result = a1.ieee_rem(a2).value;
355 
356         assert_eq!(expected, result.to_bits(), "ieee_rem({:#x}, {:#x})", op1, op2);
357     }
358 }
359 
360 #[test]
ppc_double_double_mod()361 fn ppc_double_double_mod() {
362     let data = [
363         // mod(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
364         (
365             0x3cb8000000000000_4008000000000000,
366             0x3ca4000000000000_3ff4000000000000,
367             0x3c90000000000000_3fe0000000000000,
368         ),
369         // mod(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (1.25 + 1.25 << 53)
370         // 0xbc98000000000000 doesn't seem right, but it's what we currently have.
371         // FIXME: investigate
372         (
373             0x3cb8000000000000_4008000000000000,
374             0x3cac000000000000_3ffc000000000000,
375             0xbc98000000000000_3ff4000000000001,
376         ),
377     ];
378 
379     for (op1, op2, expected) in data {
380         let a1 = DoubleDouble::from_bits(op1);
381         let a2 = DoubleDouble::from_bits(op2);
382         let r = (a1 % a2).value;
383 
384         assert_eq!(expected, r.to_bits(), "fmod({:#x}, {:#x})", op1, op2);
385     }
386 }
387 
388 #[test]
ppc_double_double_fma()389 fn ppc_double_double_fma() {
390     // Sanity check for now.
391     let mut a = "2".parse::<DoubleDouble>().unwrap();
392     a = a.mul_add("3".parse::<DoubleDouble>().unwrap(), "4".parse::<DoubleDouble>().unwrap()).value;
393     assert_eq!(Some(Ordering::Equal), "10".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
394 }
395 
396 #[test]
ppc_double_double_round_to_integral()397 fn ppc_double_double_round_to_integral() {
398     {
399         let a = "1.5".parse::<DoubleDouble>().unwrap();
400         let a = a.round_to_integral(Round::NearestTiesToEven).value;
401         assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
402     }
403     {
404         let a = "2.5".parse::<DoubleDouble>().unwrap();
405         let a = a.round_to_integral(Round::NearestTiesToEven).value;
406         assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
407     }
408 }
409 
410 #[test]
ppc_double_double_compare()411 fn ppc_double_double_compare() {
412     let data = [
413         // (1 + 0) = (1 + 0)
414         (0x3ff0000000000000, 0x3ff0000000000000, Some(Ordering::Equal)),
415         // (1 + 0) < (1.00...1 + 0)
416         (0x3ff0000000000000, 0x3ff0000000000001, Some(Ordering::Less)),
417         // (1.00...1 + 0) > (1 + 0)
418         (0x3ff0000000000001, 0x3ff0000000000000, Some(Ordering::Greater)),
419         // (1 + 0) < (1 + epsilon)
420         (0x3ff0000000000000, 0x0000000000000001_3ff0000000000001, Some(Ordering::Less)),
421         // NaN != NaN
422         (0x7ff8000000000000, 0x7ff8000000000000, None),
423         // (1 + 0) != NaN
424         (0x3ff0000000000000, 0x7ff8000000000000, None),
425         // Inf = Inf
426         (0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
427     ];
428 
429     for (op1, op2, expected) in data {
430         let a1 = DoubleDouble::from_bits(op1);
431         let a2 = DoubleDouble::from_bits(op2);
432         assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
433     }
434 }
435 
436 #[test]
ppc_double_double_bitwise_eq()437 fn ppc_double_double_bitwise_eq() {
438     let data = [
439         // (1 + 0) = (1 + 0)
440         (0x3ff0000000000000, 0x3ff0000000000000, true),
441         // (1 + 0) != (1.00...1 + 0)
442         (0x3ff0000000000000, 0x3ff0000000000001, false),
443         // NaN = NaN
444         (0x7ff8000000000000, 0x7ff8000000000000, true),
445         // NaN != NaN with a different bit pattern
446         (0x7ff8000000000000, 0x3ff0000000000000_7ff8000000000000, false),
447         // Inf = Inf
448         (0x7ff0000000000000, 0x7ff0000000000000, true),
449     ];
450 
451     for (op1, op2, expected) in data {
452         let a1 = DoubleDouble::from_bits(op1);
453         let a2 = DoubleDouble::from_bits(op2);
454         assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
455     }
456 }
457 
458 #[test]
ppc_double_double_change_sign()459 fn ppc_double_double_change_sign() {
460     let float = DoubleDouble::from_bits(0xbcb0000000000000_400f000000000000);
461     {
462         let actual = float.copy_sign("1".parse::<DoubleDouble>().unwrap());
463         assert_eq!(0xbcb0000000000000_400f000000000000, actual.to_bits());
464     }
465     {
466         let actual = float.copy_sign("-1".parse::<DoubleDouble>().unwrap());
467         assert_eq!(0x3cb0000000000000_c00f000000000000, actual.to_bits());
468     }
469 }
470 
471 #[test]
ppc_double_double_factories()472 fn ppc_double_double_factories() {
473     assert_eq!(0, DoubleDouble::ZERO.to_bits());
474     assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, DoubleDouble::largest().to_bits());
475     assert_eq!(0x0000000000000001, DoubleDouble::SMALLEST.to_bits());
476     assert_eq!(0x0360000000000000, DoubleDouble::smallest_normalized().to_bits());
477     assert_eq!(0x0000000000000000_8000000000000000, (-DoubleDouble::ZERO).to_bits());
478     assert_eq!(0xfc8ffffffffffffe_ffefffffffffffff, (-DoubleDouble::largest()).to_bits());
479     assert_eq!(0x0000000000000000_8000000000000001, (-DoubleDouble::SMALLEST).to_bits());
480     assert_eq!(
481         0x0000000000000000_8360000000000000,
482         (-DoubleDouble::smallest_normalized()).to_bits()
483     );
484     assert!(DoubleDouble::SMALLEST.is_smallest());
485     assert!(DoubleDouble::largest().is_largest());
486 }
487 
488 #[test]
ppc_double_double_is_denormal()489 fn ppc_double_double_is_denormal() {
490     assert!(DoubleDouble::SMALLEST.is_denormal());
491     assert!(!DoubleDouble::largest().is_denormal());
492     assert!(!DoubleDouble::smallest_normalized().is_denormal());
493     {
494         // (4 + 3) is not normalized
495         let data = 0x4008000000000000_4010000000000000;
496         assert!(DoubleDouble::from_bits(data).is_denormal());
497     }
498 }
499 
500 #[test]
ppc_double_double_exact_inverse()501 fn ppc_double_double_exact_inverse() {
502     assert!(
503         "2.0"
504             .parse::<DoubleDouble>()
505             .unwrap()
506             .get_exact_inverse()
507             .unwrap()
508             .bitwise_eq("0.5".parse::<DoubleDouble>().unwrap())
509     );
510 }
511 
512 #[test]
ppc_double_double_scalbn()513 fn ppc_double_double_scalbn() {
514     // 3.0 + 3.0 << 53
515     let input = 0x3cb8000000000000_4008000000000000;
516     let result = DoubleDouble::from_bits(input).scalbn(1);
517     // 6.0 + 6.0 << 53
518     assert_eq!(0x3cc8000000000000_4018000000000000, result.to_bits());
519 }
520 
521 #[test]
ppc_double_double_frexp()522 fn ppc_double_double_frexp() {
523     // 3.0 + 3.0 << 53
524     let input = 0x3cb8000000000000_4008000000000000;
525     let mut exp = 0;
526     // 0.75 + 0.75 << 53
527     let result = DoubleDouble::from_bits(input).frexp(&mut exp);
528     assert_eq!(2, exp);
529     assert_eq!(0x3c98000000000000_3fe8000000000000, result.to_bits());
530 }
531