]> git.lizzy.rs Git - rust.git/blob - src/librustc_apfloat/ppc.rs
Rollup merge of #66045 - mzabaluev:unwrap-infallible, r=dtolnay
[rust.git] / src / librustc_apfloat / ppc.rs
1 use crate::ieee;
2 use crate::{Category, ExpInt, Float, FloatConvert, ParseError, Round, Status, StatusAnd};
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(F::smallest_normalized().scalbn(F::PRECISION as ExpInt), F::ZERO)
169     }
170
171     // Implement addition, subtraction, multiplication and division based on:
172     // "Software for Doubled-Precision Floating-Point Computations",
173     // by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
174
175     fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
176         match (self.category(), rhs.category()) {
177             (Category::Infinity, Category::Infinity) => {
178                 if self.is_negative() != rhs.is_negative() {
179                     Status::INVALID_OP.and(Self::NAN.copy_sign(self))
180                 } else {
181                     Status::OK.and(self)
182                 }
183             }
184
185             (_, Category::Zero) | (Category::NaN, _) | (Category::Infinity, Category::Normal) => {
186                 Status::OK.and(self)
187             }
188
189             (Category::Zero, _) | (_, Category::NaN) | (_, Category::Infinity) => {
190                 Status::OK.and(rhs)
191             }
192
193             (Category::Normal, Category::Normal) => {
194                 let mut status = Status::OK;
195                 let (a, aa, c, cc) = (self.0, self.1, rhs.0, rhs.1);
196                 let mut z = a;
197                 z = unpack!(status|=, z.add_r(c, round));
198                 if !z.is_finite() {
199                     if !z.is_infinite() {
200                         return status.and(DoubleFloat(z, F::ZERO));
201                     }
202                     status = Status::OK;
203                     let a_cmp_c = a.cmp_abs_normal(c);
204                     z = cc;
205                     z = unpack!(status|=, z.add_r(aa, round));
206                     if a_cmp_c == Ordering::Greater {
207                         // z = cc + aa + c + a;
208                         z = unpack!(status|=, z.add_r(c, round));
209                         z = unpack!(status|=, z.add_r(a, round));
210                     } else {
211                         // z = cc + aa + a + c;
212                         z = unpack!(status|=, z.add_r(a, round));
213                         z = unpack!(status|=, z.add_r(c, round));
214                     }
215                     if !z.is_finite() {
216                         return status.and(DoubleFloat(z, F::ZERO));
217                     }
218                     self.0 = z;
219                     let mut zz = aa;
220                     zz = unpack!(status|=, zz.add_r(cc, round));
221                     if a_cmp_c == Ordering::Greater {
222                         // self.1 = a - z + c + zz;
223                         self.1 = a;
224                         self.1 = unpack!(status|=, self.1.sub_r(z, round));
225                         self.1 = unpack!(status|=, self.1.add_r(c, round));
226                         self.1 = unpack!(status|=, self.1.add_r(zz, round));
227                     } else {
228                         // self.1 = c - z + a + zz;
229                         self.1 = c;
230                         self.1 = unpack!(status|=, self.1.sub_r(z, round));
231                         self.1 = unpack!(status|=, self.1.add_r(a, round));
232                         self.1 = unpack!(status|=, self.1.add_r(zz, round));
233                     }
234                 } else {
235                     // q = a - z;
236                     let mut q = a;
237                     q = unpack!(status|=, q.sub_r(z, round));
238
239                     // zz = q + c + (a - (q + z)) + aa + cc;
240                     // Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
241                     let mut zz = q;
242                     zz = unpack!(status|=, zz.add_r(c, round));
243                     q = unpack!(status|=, q.add_r(z, round));
244                     q = unpack!(status|=, q.sub_r(a, round));
245                     q = -q;
246                     zz = unpack!(status|=, zz.add_r(q, round));
247                     zz = unpack!(status|=, zz.add_r(aa, round));
248                     zz = unpack!(status|=, zz.add_r(cc, round));
249                     if zz.is_zero() && !zz.is_negative() {
250                         return Status::OK.and(DoubleFloat(z, F::ZERO));
251                     }
252                     self.0 = z;
253                     self.0 = unpack!(status|=, self.0.add_r(zz, round));
254                     if !self.0.is_finite() {
255                         self.1 = F::ZERO;
256                         return status.and(self);
257                     }
258                     self.1 = z;
259                     self.1 = unpack!(status|=, self.1.sub_r(self.0, round));
260                     self.1 = unpack!(status|=, self.1.add_r(zz, round));
261                 }
262                 status.and(self)
263             }
264         }
265     }
266
267     fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
268         // Interesting observation: For special categories, finding the lowest
269         // common ancestor of the following layered graph gives the correct
270         // return category:
271         //
272         //    NaN
273         //   /   \
274         // Zero  Inf
275         //   \   /
276         //   Normal
277         //
278         // e.g., NaN * NaN = NaN
279         //      Zero * Inf = NaN
280         //      Normal * Zero = Zero
281         //      Normal * Inf = Inf
282         match (self.category(), rhs.category()) {
283             (Category::NaN, _) => Status::OK.and(self),
284
285             (_, Category::NaN) => Status::OK.and(rhs),
286
287             (Category::Zero, Category::Infinity) | (Category::Infinity, Category::Zero) => {
288                 Status::OK.and(Self::NAN)
289             }
290
291             (Category::Zero, _) | (Category::Infinity, _) => Status::OK.and(self),
292
293             (_, Category::Zero) | (_, Category::Infinity) => Status::OK.and(rhs),
294
295             (Category::Normal, Category::Normal) => {
296                 let mut status = Status::OK;
297                 let (a, b, c, d) = (self.0, self.1, rhs.0, rhs.1);
298                 // t = a * c
299                 let mut t = a;
300                 t = unpack!(status|=, t.mul_r(c, round));
301                 if !t.is_finite_non_zero() {
302                     return status.and(DoubleFloat(t, F::ZERO));
303                 }
304
305                 // tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
306                 let mut tau = a;
307                 tau = unpack!(status|=, tau.mul_add_r(c, -t, round));
308                 // v = a * d
309                 let mut v = a;
310                 v = unpack!(status|=, v.mul_r(d, round));
311                 // w = b * c
312                 let mut w = b;
313                 w = unpack!(status|=, w.mul_r(c, round));
314                 v = unpack!(status|=, v.add_r(w, round));
315                 // tau += v + w
316                 tau = unpack!(status|=, tau.add_r(v, round));
317                 // u = t + tau
318                 let mut u = t;
319                 u = unpack!(status|=, u.add_r(tau, round));
320
321                 self.0 = u;
322                 if !u.is_finite() {
323                     self.1 = F::ZERO;
324                 } else {
325                     // self.1 = (t - u) + tau
326                     t = unpack!(status|=, t.sub_r(u, round));
327                     t = unpack!(status|=, t.add_r(tau, round));
328                     self.1 = t;
329                 }
330                 status.and(self)
331             }
332         }
333     }
334
335     fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
336         Fallback::from(self)
337             .mul_add_r(Fallback::from(multiplicand), Fallback::from(addend), round)
338             .map(Self::from)
339     }
340
341     fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
342         Fallback::from(self).div_r(Fallback::from(rhs), round).map(Self::from)
343     }
344
345     fn c_fmod(self, rhs: Self) -> StatusAnd<Self> {
346         Fallback::from(self).c_fmod(Fallback::from(rhs)).map(Self::from)
347     }
348
349     fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
350         Fallback::from(self).round_to_integral(round).map(Self::from)
351     }
352
353     fn next_up(self) -> StatusAnd<Self> {
354         Fallback::from(self).next_up().map(Self::from)
355     }
356
357     fn from_bits(input: u128) -> Self {
358         let (a, b) = (input, input >> F::BITS);
359         DoubleFloat(F::from_bits(a & ((1 << F::BITS) - 1)), F::from_bits(b & ((1 << F::BITS) - 1)))
360     }
361
362     fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
363         Fallback::from_u128_r(input, round).map(Self::from)
364     }
365
366     fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
367         Fallback::from_str_r(s, round).map(|r| r.map(Self::from))
368     }
369
370     fn to_bits(self) -> u128 {
371         self.0.to_bits() | (self.1.to_bits() << F::BITS)
372     }
373
374     fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
375         Fallback::from(self).to_u128_r(width, round, is_exact)
376     }
377
378     fn cmp_abs_normal(self, rhs: Self) -> Ordering {
379         self.0.cmp_abs_normal(rhs.0).then_with(|| {
380             let result = self.1.cmp_abs_normal(rhs.1);
381             if result != Ordering::Equal {
382                 let against = self.0.is_negative() ^ self.1.is_negative();
383                 let rhs_against = rhs.0.is_negative() ^ rhs.1.is_negative();
384                 (!against)
385                     .cmp(&!rhs_against)
386                     .then_with(|| if against { result.reverse() } else { result })
387             } else {
388                 result
389             }
390         })
391     }
392
393     fn bitwise_eq(self, rhs: Self) -> bool {
394         self.0.bitwise_eq(rhs.0) && self.1.bitwise_eq(rhs.1)
395     }
396
397     fn is_negative(self) -> bool {
398         self.0.is_negative()
399     }
400
401     fn is_denormal(self) -> bool {
402         self.category() == Category::Normal
403             && (self.0.is_denormal() || self.0.is_denormal() ||
404           // (double)(Hi + Lo) == Hi defines a normal number.
405           !(self.0 + self.1).value.bitwise_eq(self.0))
406     }
407
408     fn is_signaling(self) -> bool {
409         self.0.is_signaling()
410     }
411
412     fn category(self) -> Category {
413         self.0.category()
414     }
415
416     fn get_exact_inverse(self) -> Option<Self> {
417         Fallback::from(self).get_exact_inverse().map(Self::from)
418     }
419
420     fn ilogb(self) -> ExpInt {
421         self.0.ilogb()
422     }
423
424     fn scalbn_r(self, exp: ExpInt, round: Round) -> Self {
425         DoubleFloat(self.0.scalbn_r(exp, round), self.1.scalbn_r(exp, round))
426     }
427
428     fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self {
429         let a = self.0.frexp_r(exp, round);
430         let mut b = self.1;
431         if self.category() == Category::Normal {
432             b = b.scalbn_r(-*exp, round);
433         }
434         DoubleFloat(a, b)
435     }
436 }