]> git.lizzy.rs Git - rust.git/blob - src/librustc_apfloat/ppc.rs
Merge pull request #13 from rust-lang/master
[rust.git] / src / librustc_apfloat / ppc.rs
1 use crate::{Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd};
2 use crate::ieee;
3
4 use core::cmp::Ordering;
5 use core::fmt;
6 use core::ops::Neg;
7
8 #[must_use]
9 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
10 pub struct DoubleFloat<F>(F, F);
11 pub type DoubleDouble = DoubleFloat<ieee::Double>;
12
13 // These are legacy semantics for the Fallback, inaccurate implementation of
14 // IBM double-double, if the accurate DoubleDouble doesn't handle the
15 // operation. It's equivalent to having an IEEE number with consecutive 106
16 // bits of mantissa and 11 bits of exponent.
17 //
18 // It's not equivalent to IBM double-double. For example, a legit IBM
19 // double-double, 1 + epsilon:
20 //
21 //   1 + epsilon = 1 + (1 >> 1076)
22 //
23 // is not representable by a consecutive 106 bits of mantissa.
24 //
25 // Currently, these semantics are used in the following way:
26 //
27 //   DoubleDouble -> (Double, Double) ->
28 //   DoubleDouble's Fallback -> IEEE operations
29 //
30 // FIXME: Implement all operations in DoubleDouble, and delete these
31 // semantics.
32 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
33 pub struct FallbackS<F>(F);
34 type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
35 impl<F: Float> ieee::Semantics for FallbackS<F> {
36     // Forbid any conversion to/from bits.
37     const BITS: usize = 0;
38     const PRECISION: usize = F::PRECISION * 2;
39     const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
40     const MIN_EXP: ExpInt = F::MIN_EXP as ExpInt + F::PRECISION as ExpInt;
41 }
42
43 // Convert number to F. To avoid spurious underflows, we re-
44 // normalize against the F exponent range first, and only *then*
45 // truncate the mantissa. The result of that second conversion
46 // may be inexact, but should never underflow.
47 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
48 pub struct FallbackExtendedS<F>(F);
49 type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
50 impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
51     // Forbid any conversion to/from bits.
52     const BITS: usize = 0;
53     const PRECISION: usize = Fallback::<F>::PRECISION;
54     const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
55 }
56
57 impl<F: Float> From<Fallback<F>> for DoubleFloat<F>
58 where
59     F: FloatConvert<FallbackExtended<F>>,
60     FallbackExtended<F>: FloatConvert<F>,
61 {
62     fn from(x: Fallback<F>) -> Self {
63         let mut status;
64         let mut loses_info = false;
65
66         let extended: FallbackExtended<F> = unpack!(status=, x.convert(&mut loses_info));
67         assert_eq!((status, loses_info), (Status::OK, false));
68
69         let a = unpack!(status=, extended.convert(&mut loses_info));
70         assert_eq!(status - Status::INEXACT, Status::OK);
71
72         // If conversion was exact or resulted in a special case, we're done;
73         // just set the second double to zero. Otherwise, re-convert back to
74         // the extended format and compute the difference. This now should
75         // convert exactly to double.
76         let b = if a.is_finite_non_zero() && loses_info {
77             let u: FallbackExtended<F> = unpack!(status=, a.convert(&mut loses_info));
78             assert_eq!((status, loses_info), (Status::OK, false));
79             let v = unpack!(status=, extended - u);
80             assert_eq!(status, Status::OK);
81             let v = unpack!(status=, v.convert(&mut loses_info));
82             assert_eq!((status, loses_info), (Status::OK, false));
83             v
84         } else {
85             F::ZERO
86         };
87
88         DoubleFloat(a, b)
89     }
90 }
91
92 impl<F: FloatConvert<Self>> From<DoubleFloat<F>> for Fallback<F> {
93     fn from(DoubleFloat(a, b): DoubleFloat<F>) -> Self {
94         let mut status;
95         let mut loses_info = false;
96
97         // Get the first F and convert to our format.
98         let a = unpack!(status=, a.convert(&mut loses_info));
99         assert_eq!((status, loses_info), (Status::OK, false));
100
101         // Unless we have a special case, add in second F.
102         if a.is_finite_non_zero() {
103             let b = unpack!(status=, b.convert(&mut loses_info));
104             assert_eq!((status, loses_info), (Status::OK, false));
105
106             (a + b).value
107         } else {
108             a
109         }
110     }
111 }
112
113 float_common_impls!(DoubleFloat<F>);
114
115 impl<F: Float> Neg for DoubleFloat<F> {
116     type Output = Self;
117     fn neg(self) -> Self {
118         if self.1.is_finite_non_zero() {
119             DoubleFloat(-self.0, -self.1)
120         } else {
121             DoubleFloat(-self.0, self.1)
122         }
123     }
124 }
125
126 impl<F: FloatConvert<Fallback<F>>> fmt::Display for DoubleFloat<F> {
127     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128         fmt::Display::fmt(&Fallback::from(*self), f)
129     }
130 }
131
132 impl<F: FloatConvert<Fallback<F>>> Float for DoubleFloat<F>
133 where
134     Self: From<Fallback<F>>,
135 {
136     const BITS: usize = F::BITS * 2;
137     const PRECISION: usize = Fallback::<F>::PRECISION;
138     const MAX_EXP: ExpInt = Fallback::<F>::MAX_EXP;
139     const MIN_EXP: ExpInt = Fallback::<F>::MIN_EXP;
140
141     const ZERO: Self = DoubleFloat(F::ZERO, F::ZERO);
142
143     const INFINITY: Self = DoubleFloat(F::INFINITY, F::ZERO);
144
145     // FIXME(eddyb) remove when qnan becomes const fn.
146     const NAN: Self = DoubleFloat(F::NAN, F::ZERO);
147
148     fn qnan(payload: Option<u128>) -> Self {
149         DoubleFloat(F::qnan(payload), F::ZERO)
150     }
151
152     fn snan(payload: Option<u128>) -> Self {
153         DoubleFloat(F::snan(payload), F::ZERO)
154     }
155
156     fn largest() -> Self {
157         let status;
158         let mut r = DoubleFloat(F::largest(), F::largest());
159         r.1 = r.1.scalbn(-(F::PRECISION as ExpInt + 1));
160         r.1 = unpack!(status=, r.1.next_down());
161         assert_eq!(status, Status::OK);
162         r
163     }
164
165     const SMALLEST: Self = DoubleFloat(F::SMALLEST, F::ZERO);
166
167     fn smallest_normalized() -> Self {
168         DoubleFloat(
169             F::smallest_normalized().scalbn(F::PRECISION as ExpInt),
170             F::ZERO,
171         )
172     }
173
174     // Implement addition, subtraction, multiplication and division based on:
175     // "Software for Doubled-Precision Floating-Point Computations",
176     // by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
177
178     fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
179         match (self.category(), rhs.category()) {
180             (Category::Infinity, Category::Infinity) => {
181                 if self.is_negative() != rhs.is_negative() {
182                     Status::INVALID_OP.and(Self::NAN.copy_sign(self))
183                 } else {
184                     Status::OK.and(self)
185                 }
186             }
187
188             (_, Category::Zero) |
189             (Category::NaN, _) |
190             (Category::Infinity, Category::Normal) => Status::OK.and(self),
191
192             (Category::Zero, _) |
193             (_, Category::NaN) |
194             (_, Category::Infinity) => Status::OK.and(rhs),
195
196             (Category::Normal, Category::Normal) => {
197                 let mut status = Status::OK;
198                 let (a, aa, c, cc) = (self.0, self.1, rhs.0, rhs.1);
199                 let mut z = a;
200                 z = unpack!(status|=, z.add_r(c, round));
201                 if !z.is_finite() {
202                     if !z.is_infinite() {
203                         return status.and(DoubleFloat(z, F::ZERO));
204                     }
205                     status = Status::OK;
206                     let a_cmp_c = a.cmp_abs_normal(c);
207                     z = cc;
208                     z = unpack!(status|=, z.add_r(aa, round));
209                     if a_cmp_c == Ordering::Greater {
210                         // z = cc + aa + c + a;
211                         z = unpack!(status|=, z.add_r(c, round));
212                         z = unpack!(status|=, z.add_r(a, round));
213                     } else {
214                         // z = cc + aa + a + c;
215                         z = unpack!(status|=, z.add_r(a, round));
216                         z = unpack!(status|=, z.add_r(c, round));
217                     }
218                     if !z.is_finite() {
219                         return status.and(DoubleFloat(z, F::ZERO));
220                     }
221                     self.0 = z;
222                     let mut zz = aa;
223                     zz = unpack!(status|=, zz.add_r(cc, round));
224                     if a_cmp_c == Ordering::Greater {
225                         // self.1 = a - z + c + zz;
226                         self.1 = a;
227                         self.1 = unpack!(status|=, self.1.sub_r(z, round));
228                         self.1 = unpack!(status|=, self.1.add_r(c, round));
229                         self.1 = unpack!(status|=, self.1.add_r(zz, round));
230                     } else {
231                         // self.1 = c - z + a + zz;
232                         self.1 = c;
233                         self.1 = unpack!(status|=, self.1.sub_r(z, round));
234                         self.1 = unpack!(status|=, self.1.add_r(a, round));
235                         self.1 = unpack!(status|=, self.1.add_r(zz, round));
236                     }
237                 } else {
238                     // q = a - z;
239                     let mut q = a;
240                     q = unpack!(status|=, q.sub_r(z, round));
241
242                     // zz = q + c + (a - (q + z)) + aa + cc;
243                     // Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
244                     let mut zz = q;
245                     zz = unpack!(status|=, zz.add_r(c, round));
246                     q = unpack!(status|=, q.add_r(z, round));
247                     q = unpack!(status|=, q.sub_r(a, round));
248                     q = -q;
249                     zz = unpack!(status|=, zz.add_r(q, round));
250                     zz = unpack!(status|=, zz.add_r(aa, round));
251                     zz = unpack!(status|=, zz.add_r(cc, round));
252                     if zz.is_zero() && !zz.is_negative() {
253                         return Status::OK.and(DoubleFloat(z, F::ZERO));
254                     }
255                     self.0 = z;
256                     self.0 = unpack!(status|=, self.0.add_r(zz, round));
257                     if !self.0.is_finite() {
258                         self.1 = F::ZERO;
259                         return status.and(self);
260                     }
261                     self.1 = z;
262                     self.1 = unpack!(status|=, self.1.sub_r(self.0, round));
263                     self.1 = unpack!(status|=, self.1.add_r(zz, round));
264                 }
265                 status.and(self)
266             }
267         }
268     }
269
270     fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
271         // Interesting observation: For special categories, finding the lowest
272         // common ancestor of the following layered graph gives the correct
273         // return category:
274         //
275         //    NaN
276         //   /   \
277         // Zero  Inf
278         //   \   /
279         //   Normal
280         //
281         // e.g., NaN * NaN = NaN
282         //      Zero * Inf = NaN
283         //      Normal * Zero = Zero
284         //      Normal * Inf = Inf
285         match (self.category(), rhs.category()) {
286             (Category::NaN, _) => Status::OK.and(self),
287
288             (_, Category::NaN) => Status::OK.and(rhs),
289
290             (Category::Zero, Category::Infinity) |
291             (Category::Infinity, Category::Zero) => Status::OK.and(Self::NAN),
292
293             (Category::Zero, _) |
294             (Category::Infinity, _) => Status::OK.and(self),
295
296             (_, Category::Zero) |
297             (_, Category::Infinity) => Status::OK.and(rhs),
298
299             (Category::Normal, Category::Normal) => {
300                 let mut status = Status::OK;
301                 let (a, b, c, d) = (self.0, self.1, rhs.0, rhs.1);
302                 // t = a * c
303                 let mut t = a;
304                 t = unpack!(status|=, t.mul_r(c, round));
305                 if !t.is_finite_non_zero() {
306                     return status.and(DoubleFloat(t, F::ZERO));
307                 }
308
309                 // tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
310                 let mut tau = a;
311                 tau = unpack!(status|=, tau.mul_add_r(c, -t, round));
312                 // v = a * d
313                 let mut v = a;
314                 v = unpack!(status|=, v.mul_r(d, round));
315                 // w = b * c
316                 let mut w = b;
317                 w = unpack!(status|=, w.mul_r(c, round));
318                 v = unpack!(status|=, v.add_r(w, round));
319                 // tau += v + w
320                 tau = unpack!(status|=, tau.add_r(v, round));
321                 // u = t + tau
322                 let mut u = t;
323                 u = unpack!(status|=, u.add_r(tau, round));
324
325                 self.0 = u;
326                 if !u.is_finite() {
327                     self.1 = F::ZERO;
328                 } else {
329                     // self.1 = (t - u) + tau
330                     t = unpack!(status|=, t.sub_r(u, round));
331                     t = unpack!(status|=, t.add_r(tau, round));
332                     self.1 = t;
333                 }
334                 status.and(self)
335             }
336         }
337     }
338
339     fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
340         Fallback::from(self)
341             .mul_add_r(Fallback::from(multiplicand), Fallback::from(addend), round)
342             .map(Self::from)
343     }
344
345     fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
346         Fallback::from(self).div_r(Fallback::from(rhs), round).map(
347             Self::from,
348         )
349     }
350
351     fn c_fmod(self, rhs: Self) -> StatusAnd<Self> {
352         Fallback::from(self).c_fmod(Fallback::from(rhs)).map(
353             Self::from,
354         )
355     }
356
357     fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
358         Fallback::from(self).round_to_integral(round).map(
359             Self::from,
360         )
361     }
362
363     fn next_up(self) -> StatusAnd<Self> {
364         Fallback::from(self).next_up().map(Self::from)
365     }
366
367     fn from_bits(input: u128) -> Self {
368         let (a, b) = (input, input >> F::BITS);
369         DoubleFloat(
370             F::from_bits(a & ((1 << F::BITS) - 1)),
371             F::from_bits(b & ((1 << F::BITS) - 1)),
372         )
373     }
374
375     fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
376         Fallback::from_u128_r(input, round).map(Self::from)
377     }
378
379     fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
380         Fallback::from_str_r(s, round).map(|r| r.map(Self::from))
381     }
382
383     fn to_bits(self) -> u128 {
384         self.0.to_bits() | (self.1.to_bits() << F::BITS)
385     }
386
387     fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
388         Fallback::from(self).to_u128_r(width, round, is_exact)
389     }
390
391     fn cmp_abs_normal(self, rhs: Self) -> Ordering {
392         self.0.cmp_abs_normal(rhs.0).then_with(|| {
393             let result = self.1.cmp_abs_normal(rhs.1);
394             if result != Ordering::Equal {
395                 let against = self.0.is_negative() ^ self.1.is_negative();
396                 let rhs_against = rhs.0.is_negative() ^ rhs.1.is_negative();
397                 (!against).cmp(&!rhs_against).then_with(|| if against {
398                     result.reverse()
399                 } else {
400                     result
401                 })
402             } else {
403                 result
404             }
405         })
406     }
407
408     fn bitwise_eq(self, rhs: Self) -> bool {
409         self.0.bitwise_eq(rhs.0) && self.1.bitwise_eq(rhs.1)
410     }
411
412     fn is_negative(self) -> bool {
413         self.0.is_negative()
414     }
415
416     fn is_denormal(self) -> bool {
417         self.category() == Category::Normal &&
418             (self.0.is_denormal() || self.0.is_denormal() ||
419           // (double)(Hi + Lo) == Hi defines a normal number.
420           !(self.0 + self.1).value.bitwise_eq(self.0))
421     }
422
423     fn is_signaling(self) -> bool {
424         self.0.is_signaling()
425     }
426
427     fn category(self) -> Category {
428         self.0.category()
429     }
430
431     fn get_exact_inverse(self) -> Option<Self> {
432         Fallback::from(self).get_exact_inverse().map(Self::from)
433     }
434
435     fn ilogb(self) -> ExpInt {
436         self.0.ilogb()
437     }
438
439     fn scalbn_r(self, exp: ExpInt, round: Round) -> Self {
440         DoubleFloat(self.0.scalbn_r(exp, round), self.1.scalbn_r(exp, round))
441     }
442
443     fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self {
444         let a = self.0.frexp_r(exp, round);
445         let mut b = self.1;
446         if self.category() == Category::Normal {
447             b = b.scalbn_r(-*exp, round);
448         }
449         DoubleFloat(a, b)
450     }
451 }