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