1 | //===-- lib/Evaluate/real.cpp ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "flang/Evaluate/real.h" |
10 | #include "int-power.h" |
11 | #include "flang/Common/idioms.h" |
12 | #include "flang/Decimal/decimal.h" |
13 | #include "flang/Parser/characters.h" |
14 | #include "llvm/Support/raw_ostream.h" |
15 | #include <limits> |
16 | |
17 | namespace Fortran::evaluate::value { |
18 | |
19 | template <typename W, int P> Relation Real<W, P>::Compare(const Real &y) const { |
20 | if (IsNotANumber() || y.IsNotANumber()) { // NaN vs x, x vs NaN |
21 | return Relation::Unordered; |
22 | } else if (IsInfinite()) { |
23 | if (y.IsInfinite()) { |
24 | if (IsNegative()) { // -Inf vs +/-Inf |
25 | return y.IsNegative() ? Relation::Equal : Relation::Less; |
26 | } else { // +Inf vs +/-Inf |
27 | return y.IsNegative() ? Relation::Greater : Relation::Equal; |
28 | } |
29 | } else { // +/-Inf vs finite |
30 | return IsNegative() ? Relation::Less : Relation::Greater; |
31 | } |
32 | } else if (y.IsInfinite()) { // finite vs +/-Inf |
33 | return y.IsNegative() ? Relation::Greater : Relation::Less; |
34 | } else { // two finite numbers |
35 | bool isNegative{IsNegative()}; |
36 | if (isNegative != y.IsNegative()) { |
37 | if (word_.IOR(y.word_).IBCLR(bits - 1).IsZero()) { |
38 | return Relation::Equal; // +/-0.0 == -/+0.0 |
39 | } else { |
40 | return isNegative ? Relation::Less : Relation::Greater; |
41 | } |
42 | } else { |
43 | // same sign |
44 | Ordering order{evaluate::Compare(Exponent(), y.Exponent())}; |
45 | if (order == Ordering::Equal) { |
46 | order = GetSignificand().CompareUnsigned(y.GetSignificand()); |
47 | } |
48 | if (isNegative) { |
49 | order = Reverse(order); |
50 | } |
51 | return RelationFromOrdering(order); |
52 | } |
53 | } |
54 | } |
55 | |
56 | template <typename W, int P> |
57 | ValueWithRealFlags<Real<W, P>> Real<W, P>::Add( |
58 | const Real &y, Rounding rounding) const { |
59 | ValueWithRealFlags<Real> result; |
60 | if (IsNotANumber() || y.IsNotANumber()) { |
61 | result.value = NotANumber(); // NaN + x -> NaN |
62 | if (IsSignalingNaN() || y.IsSignalingNaN()) { |
63 | result.flags.set(RealFlag::InvalidArgument); |
64 | } |
65 | return result; |
66 | } |
67 | bool isNegative{IsNegative()}; |
68 | bool yIsNegative{y.IsNegative()}; |
69 | if (IsInfinite()) { |
70 | if (y.IsInfinite()) { |
71 | if (isNegative == yIsNegative) { |
72 | result.value = *this; // +/-Inf + +/-Inf -> +/-Inf |
73 | } else { |
74 | result.value = NotANumber(); // +/-Inf + -/+Inf -> NaN |
75 | result.flags.set(RealFlag::InvalidArgument); |
76 | } |
77 | } else { |
78 | result.value = *this; // +/-Inf + x -> +/-Inf |
79 | } |
80 | return result; |
81 | } |
82 | if (y.IsInfinite()) { |
83 | result.value = y; // x + +/-Inf -> +/-Inf |
84 | return result; |
85 | } |
86 | int exponent{Exponent()}; |
87 | int yExponent{y.Exponent()}; |
88 | if (exponent < yExponent) { |
89 | // y is larger in magnitude; simplify by reversing operands |
90 | return y.Add(*this, rounding); |
91 | } |
92 | if (exponent == yExponent && isNegative != yIsNegative) { |
93 | Ordering order{GetSignificand().CompareUnsigned(y.GetSignificand())}; |
94 | if (order == Ordering::Less) { |
95 | // Same exponent, opposite signs, and y is larger in magnitude |
96 | return y.Add(*this, rounding); |
97 | } |
98 | if (order == Ordering::Equal) { |
99 | // x + (-x) -> +0.0 unless rounding is directed downwards |
100 | if (rounding.mode == common::RoundingMode::Down) { |
101 | result.value = NegativeZero(); |
102 | } |
103 | return result; |
104 | } |
105 | } |
106 | // Our exponent is greater than y's, or the exponents match and y is not |
107 | // of the opposite sign and greater magnitude. So (x+y) will have the |
108 | // same sign as x. |
109 | Fraction fraction{GetFraction()}; |
110 | Fraction yFraction{y.GetFraction()}; |
111 | int rshift = exponent - yExponent; |
112 | if (exponent > 0 && yExponent == 0) { |
113 | --rshift; // correct overshift when only y is subnormal |
114 | } |
115 | RoundingBits roundingBits{yFraction, rshift}; |
116 | yFraction = yFraction.SHIFTR(rshift); |
117 | bool carry{false}; |
118 | if (isNegative != yIsNegative) { |
119 | // Opposite signs: subtract via addition of two's complement of y and |
120 | // the rounding bits. |
121 | yFraction = yFraction.NOT(); |
122 | carry = roundingBits.Negate(); |
123 | } |
124 | auto sum{fraction.AddUnsigned(yFraction, carry)}; |
125 | fraction = sum.value; |
126 | if (isNegative == yIsNegative && sum.carry) { |
127 | roundingBits.ShiftRight(sum.value.BTEST(0)); |
128 | fraction = fraction.SHIFTR(1).IBSET(fraction.bits - 1); |
129 | ++exponent; |
130 | } |
131 | NormalizeAndRound( |
132 | result, isNegative, exponent, fraction, rounding, roundingBits); |
133 | return result; |
134 | } |
135 | |
136 | template <typename W, int P> |
137 | ValueWithRealFlags<Real<W, P>> Real<W, P>::Multiply( |
138 | const Real &y, Rounding rounding) const { |
139 | ValueWithRealFlags<Real> result; |
140 | if (IsNotANumber() || y.IsNotANumber()) { |
141 | result.value = NotANumber(); // NaN * x -> NaN |
142 | if (IsSignalingNaN() || y.IsSignalingNaN()) { |
143 | result.flags.set(RealFlag::InvalidArgument); |
144 | } |
145 | } else { |
146 | bool isNegative{IsNegative() != y.IsNegative()}; |
147 | if (IsInfinite() || y.IsInfinite()) { |
148 | if (IsZero() || y.IsZero()) { |
149 | result.value = NotANumber(); // 0 * Inf -> NaN |
150 | result.flags.set(RealFlag::InvalidArgument); |
151 | } else { |
152 | result.value = Infinity(isNegative); |
153 | } |
154 | } else { |
155 | auto product{GetFraction().MultiplyUnsigned(y.GetFraction())}; |
156 | std::int64_t exponent{CombineExponents(y, false)}; |
157 | if (exponent < 1) { |
158 | int rshift = 1 - exponent; |
159 | exponent = 1; |
160 | bool sticky{false}; |
161 | if (rshift >= product.upper.bits + product.lower.bits) { |
162 | sticky = !product.lower.IsZero() || !product.upper.IsZero(); |
163 | } else if (rshift >= product.lower.bits) { |
164 | sticky = !product.lower.IsZero() || |
165 | !product.upper |
166 | .IAND(product.upper.MASKR(rshift - product.lower.bits)) |
167 | .IsZero(); |
168 | } else { |
169 | sticky = !product.lower.IAND(product.lower.MASKR(rshift)).IsZero(); |
170 | } |
171 | product.lower = product.lower.SHIFTRWithFill(product.upper, rshift); |
172 | product.upper = product.upper.SHIFTR(rshift); |
173 | if (sticky) { |
174 | product.lower = product.lower.IBSET(0); |
175 | } |
176 | } |
177 | int leadz{product.upper.LEADZ()}; |
178 | if (leadz >= product.upper.bits) { |
179 | leadz += product.lower.LEADZ(); |
180 | } |
181 | int lshift{leadz}; |
182 | if (lshift > exponent - 1) { |
183 | lshift = exponent - 1; |
184 | } |
185 | exponent -= lshift; |
186 | product.upper = product.upper.SHIFTLWithFill(product.lower, lshift); |
187 | product.lower = product.lower.SHIFTL(lshift); |
188 | RoundingBits roundingBits{product.lower, product.lower.bits}; |
189 | NormalizeAndRound(result, isNegative, exponent, product.upper, rounding, |
190 | roundingBits, true /*multiply*/); |
191 | } |
192 | } |
193 | return result; |
194 | } |
195 | |
196 | template <typename W, int P> |
197 | ValueWithRealFlags<Real<W, P>> Real<W, P>::Divide( |
198 | const Real &y, Rounding rounding) const { |
199 | ValueWithRealFlags<Real> result; |
200 | if (IsNotANumber() || y.IsNotANumber()) { |
201 | result.value = NotANumber(); // NaN / x -> NaN, x / NaN -> NaN |
202 | if (IsSignalingNaN() || y.IsSignalingNaN()) { |
203 | result.flags.set(RealFlag::InvalidArgument); |
204 | } |
205 | } else { |
206 | bool isNegative{IsNegative() != y.IsNegative()}; |
207 | if (IsInfinite()) { |
208 | if (y.IsInfinite()) { |
209 | result.value = NotANumber(); // Inf/Inf -> NaN |
210 | result.flags.set(RealFlag::InvalidArgument); |
211 | } else { // Inf/x -> Inf, Inf/0 -> Inf |
212 | result.value = Infinity(isNegative); |
213 | } |
214 | } else if (y.IsZero()) { |
215 | if (IsZero()) { // 0/0 -> NaN |
216 | result.value = NotANumber(); |
217 | result.flags.set(RealFlag::InvalidArgument); |
218 | } else { // x/0 -> Inf, Inf/0 -> Inf |
219 | result.value = Infinity(isNegative); |
220 | result.flags.set(RealFlag::DivideByZero); |
221 | } |
222 | } else if (IsZero() || y.IsInfinite()) { // 0/x, x/Inf -> 0 |
223 | if (isNegative) { |
224 | result.value = NegativeZero(); |
225 | } |
226 | } else { |
227 | // dividend and divisor are both finite and nonzero numbers |
228 | Fraction top{GetFraction()}, divisor{y.GetFraction()}; |
229 | std::int64_t exponent{CombineExponents(y, true)}; |
230 | Fraction quotient; |
231 | bool msb{false}; |
232 | if (!top.BTEST(top.bits - 1) || !divisor.BTEST(divisor.bits - 1)) { |
233 | // One or two subnormals |
234 | int topLshift{top.LEADZ()}; |
235 | top = top.SHIFTL(topLshift); |
236 | int divisorLshift{divisor.LEADZ()}; |
237 | divisor = divisor.SHIFTL(divisorLshift); |
238 | exponent += divisorLshift - topLshift; |
239 | } |
240 | for (int j{1}; j <= quotient.bits; ++j) { |
241 | if (NextQuotientBit(top, msb, divisor)) { |
242 | quotient = quotient.IBSET(quotient.bits - j); |
243 | } |
244 | } |
245 | bool guard{NextQuotientBit(top, msb, divisor)}; |
246 | bool round{NextQuotientBit(top, msb, divisor)}; |
247 | bool sticky{msb || !top.IsZero()}; |
248 | RoundingBits roundingBits{guard, round, sticky}; |
249 | if (exponent < 1) { |
250 | std::int64_t rshift{1 - exponent}; |
251 | for (; rshift > 0; --rshift) { |
252 | roundingBits.ShiftRight(quotient.BTEST(0)); |
253 | quotient = quotient.SHIFTR(1); |
254 | } |
255 | exponent = 1; |
256 | } |
257 | NormalizeAndRound( |
258 | result, isNegative, exponent, quotient, rounding, roundingBits); |
259 | } |
260 | } |
261 | return result; |
262 | } |
263 | |
264 | template <typename W, int P> |
265 | ValueWithRealFlags<Real<W, P>> Real<W, P>::SQRT(Rounding rounding) const { |
266 | ValueWithRealFlags<Real> result; |
267 | if (IsNotANumber()) { |
268 | result.value = NotANumber(); |
269 | if (IsSignalingNaN()) { |
270 | result.flags.set(RealFlag::InvalidArgument); |
271 | } |
272 | } else if (IsNegative()) { |
273 | if (IsZero()) { |
274 | // SQRT(-0) == -0 in IEEE-754. |
275 | result.value = NegativeZero(); |
276 | } else { |
277 | result.flags.set(RealFlag::InvalidArgument); |
278 | result.value = NotANumber(); |
279 | } |
280 | } else if (IsInfinite()) { |
281 | // SQRT(+Inf) == +Inf |
282 | result.value = Infinity(false); |
283 | } else if (IsZero()) { |
284 | result.value = PositiveZero(); |
285 | } else { |
286 | int expo{UnbiasedExponent()}; |
287 | if (expo < -1 || expo > 1) { |
288 | // Reduce the range to [0.5 .. 4.0) by dividing by an integral power |
289 | // of four to avoid trouble with very large and very small values |
290 | // (esp. truncation of subnormals). |
291 | // SQRT(2**(2a) * x) = SQRT(2**(2a)) * SQRT(x) = 2**a * SQRT(x) |
292 | Real scaled; |
293 | int adjust{expo / 2}; |
294 | scaled.Normalize(false, expo - 2 * adjust + exponentBias, GetFraction()); |
295 | result = scaled.SQRT(rounding); |
296 | result.value.Normalize(false, |
297 | result.value.UnbiasedExponent() + adjust + exponentBias, |
298 | result.value.GetFraction()); |
299 | return result; |
300 | } |
301 | // (-1) <= expo <= 1; use it as a shift to set the desired square. |
302 | using Extended = typename value::Integer<(binaryPrecision + 2)>; |
303 | Extended goal{ |
304 | Extended::ConvertUnsigned(GetFraction()).value.SHIFTL(expo + 1)}; |
305 | // Calculate the exact square root by maximizing a value whose square |
306 | // does not exceed the goal. Use two extra bits of precision for |
307 | // rounding. |
308 | bool sticky{true}; |
309 | Extended extFrac{}; |
310 | for (int bit{Extended::bits - 1}; bit >= 0; --bit) { |
311 | Extended next{extFrac.IBSET(bit)}; |
312 | auto squared{next.MultiplyUnsigned(next)}; |
313 | auto cmp{squared.upper.CompareUnsigned(goal)}; |
314 | if (cmp == Ordering::Less) { |
315 | extFrac = next; |
316 | } else if (cmp == Ordering::Equal && squared.lower.IsZero()) { |
317 | extFrac = next; |
318 | sticky = false; |
319 | break; // exact result |
320 | } |
321 | } |
322 | RoundingBits roundingBits{extFrac.BTEST(1), extFrac.BTEST(0), sticky}; |
323 | NormalizeAndRound(result, false, exponentBias, |
324 | Fraction::ConvertUnsigned(extFrac.SHIFTR(2)).value, rounding, |
325 | roundingBits); |
326 | } |
327 | return result; |
328 | } |
329 | |
330 | template <typename W, int P> |
331 | ValueWithRealFlags<Real<W, P>> Real<W, P>::NEAREST(bool upward) const { |
332 | ValueWithRealFlags<Real> result; |
333 | if (IsFinite()) { |
334 | Fraction fraction{GetFraction()}; |
335 | int expo{Exponent()}; |
336 | Fraction one{1}; |
337 | Fraction nearest; |
338 | bool isNegative{IsNegative()}; |
339 | if (upward != isNegative) { // upward in magnitude |
340 | auto next{fraction.AddUnsigned(one)}; |
341 | if (next.carry) { |
342 | ++expo; |
343 | nearest = Fraction::Least(); // MSB only |
344 | } else { |
345 | nearest = next.value; |
346 | } |
347 | } else { // downward in magnitude |
348 | if (IsZero()) { |
349 | nearest = 1; // smallest magnitude negative subnormal |
350 | isNegative = !isNegative; |
351 | } else { |
352 | auto sub1{fraction.SubtractSigned(one)}; |
353 | if (sub1.overflow && expo > 1) { |
354 | nearest = Fraction{0}.NOT(); |
355 | --expo; |
356 | } else { |
357 | nearest = sub1.value; |
358 | } |
359 | } |
360 | } |
361 | result.flags = result.value.Normalize(isNegative, expo, nearest); |
362 | } else { |
363 | result.flags.set(RealFlag::InvalidArgument); |
364 | result.value = *this; |
365 | } |
366 | return result; |
367 | } |
368 | |
369 | // HYPOT(x,y) = SQRT(x**2 + y**2) by definition, but those squared intermediate |
370 | // values are susceptible to over/underflow when computed naively. |
371 | // Assuming that x>=y, calculate instead: |
372 | // HYPOT(x,y) = SQRT(x**2 * (1+(y/x)**2)) |
373 | // = ABS(x) * SQRT(1+(y/x)**2) |
374 | template <typename W, int P> |
375 | ValueWithRealFlags<Real<W, P>> Real<W, P>::HYPOT( |
376 | const Real &y, Rounding rounding) const { |
377 | ValueWithRealFlags<Real> result; |
378 | if (IsNotANumber() || y.IsNotANumber()) { |
379 | result.flags.set(RealFlag::InvalidArgument); |
380 | result.value = NotANumber(); |
381 | } else if (ABS().Compare(y.ABS()) == Relation::Less) { |
382 | return y.HYPOT(*this); |
383 | } else if (IsZero()) { |
384 | return result; // x==y==0 |
385 | } else { |
386 | auto yOverX{y.Divide(*this, rounding)}; // y/x |
387 | bool inexact{yOverX.flags.test(RealFlag::Inexact)}; |
388 | auto squared{yOverX.value.Multiply(yOverX.value, rounding)}; // (y/x)**2 |
389 | inexact |= squared.flags.test(RealFlag::Inexact); |
390 | Real one; |
391 | one.Normalize(false, exponentBias, Fraction::MASKL(1)); // 1.0 |
392 | auto sum{squared.value.Add(one, rounding)}; // 1.0 + (y/x)**2 |
393 | inexact |= sum.flags.test(RealFlag::Inexact); |
394 | auto sqrt{sum.value.SQRT()}; |
395 | inexact |= sqrt.flags.test(RealFlag::Inexact); |
396 | result = sqrt.value.Multiply(ABS(), rounding); |
397 | if (inexact) { |
398 | result.flags.set(RealFlag::Inexact); |
399 | } |
400 | } |
401 | return result; |
402 | } |
403 | |
404 | // MOD(x,y) = x - AINT(x/y)*y in the standard; unfortunately, this definition |
405 | // can be pretty inaccurate when x is much larger than y in magnitude due to |
406 | // cancellation. Implement instead with (essentially) arbitrary precision |
407 | // long division, discarding the quotient and returning the remainder. |
408 | // See runtime/numeric.cpp for more details. |
409 | template <typename W, int P> |
410 | ValueWithRealFlags<Real<W, P>> Real<W, P>::MOD( |
411 | const Real &p, Rounding rounding) const { |
412 | ValueWithRealFlags<Real> result; |
413 | if (IsNotANumber() || p.IsNotANumber() || IsInfinite()) { |
414 | result.flags.set(RealFlag::InvalidArgument); |
415 | result.value = NotANumber(); |
416 | } else if (p.IsZero()) { |
417 | result.flags.set(RealFlag::DivideByZero); |
418 | result.value = NotANumber(); |
419 | } else if (p.IsInfinite()) { |
420 | result.value = *this; |
421 | } else { |
422 | result.value = ABS(); |
423 | auto pAbs{p.ABS()}; |
424 | Real half, adj; |
425 | half.Normalize(false, exponentBias - 1, Fraction::MASKL(1)); // 0.5 |
426 | for (adj.Normalize(false, Exponent(), pAbs.GetFraction()); |
427 | result.value.Compare(pAbs) != Relation::Less; |
428 | adj = adj.Multiply(half).value) { |
429 | if (result.value.Compare(adj) != Relation::Less) { |
430 | result.value = |
431 | result.value.Subtract(adj, rounding).AccumulateFlags(result.flags); |
432 | if (result.value.IsZero()) { |
433 | break; |
434 | } |
435 | } |
436 | } |
437 | if (IsNegative()) { |
438 | result.value = result.value.Negate(); |
439 | } |
440 | } |
441 | return result; |
442 | } |
443 | |
444 | // MODULO(x,y) = x - FLOOR(x/y)*y in the standard; here, it is defined |
445 | // in terms of MOD() with adjustment of the result. |
446 | template <typename W, int P> |
447 | ValueWithRealFlags<Real<W, P>> Real<W, P>::MODULO( |
448 | const Real &p, Rounding rounding) const { |
449 | ValueWithRealFlags<Real> result{MOD(p, rounding)}; |
450 | if (IsNegative() != p.IsNegative()) { |
451 | if (result.value.IsZero()) { |
452 | result.value = result.value.Negate(); |
453 | } else { |
454 | result.value = |
455 | result.value.Add(p, rounding).AccumulateFlags(result.flags); |
456 | } |
457 | } |
458 | return result; |
459 | } |
460 | |
461 | template <typename W, int P> |
462 | ValueWithRealFlags<Real<W, P>> Real<W, P>::DIM( |
463 | const Real &y, Rounding rounding) const { |
464 | ValueWithRealFlags<Real> result; |
465 | if (IsNotANumber() || y.IsNotANumber()) { |
466 | result.flags.set(RealFlag::InvalidArgument); |
467 | result.value = NotANumber(); |
468 | } else if (Compare(y) == Relation::Greater) { |
469 | result = Subtract(y, rounding); |
470 | } else { |
471 | // result is already zero |
472 | } |
473 | return result; |
474 | } |
475 | |
476 | template <typename W, int P> |
477 | ValueWithRealFlags<Real<W, P>> Real<W, P>::ToWholeNumber( |
478 | common::RoundingMode mode) const { |
479 | ValueWithRealFlags<Real> result{*this}; |
480 | if (IsNotANumber()) { |
481 | result.flags.set(RealFlag::InvalidArgument); |
482 | result.value = NotANumber(); |
483 | } else if (IsInfinite()) { |
484 | result.flags.set(RealFlag::Overflow); |
485 | } else { |
486 | constexpr int noClipExponent{exponentBias + binaryPrecision - 1}; |
487 | if (Exponent() < noClipExponent) { |
488 | Real adjust; // ABS(EPSILON(adjust)) == 0.5 |
489 | adjust.Normalize(IsSignBitSet(), noClipExponent, Fraction::MASKL(1)); |
490 | // Compute ival=(*this + adjust), losing any fractional bits; keep flags |
491 | result = Add(adjust, Rounding{mode}); |
492 | result.flags.reset(RealFlag::Inexact); // result *is* exact |
493 | // Return (ival-adjust) with original sign in case we've generated a zero. |
494 | result.value = |
495 | result.value.Subtract(adjust, Rounding{common::RoundingMode::ToZero}) |
496 | .value.SIGN(*this); |
497 | } |
498 | } |
499 | return result; |
500 | } |
501 | |
502 | template <typename W, int P> |
503 | RealFlags Real<W, P>::Normalize(bool negative, int exponent, |
504 | const Fraction &fraction, Rounding rounding, RoundingBits *roundingBits) { |
505 | int lshift{fraction.LEADZ()}; |
506 | if (lshift == fraction.bits /* fraction is zero */ && |
507 | (!roundingBits || roundingBits->empty())) { |
508 | // No fraction, no rounding bits -> +/-0.0 |
509 | exponent = lshift = 0; |
510 | } else if (lshift < exponent) { |
511 | exponent -= lshift; |
512 | } else if (exponent > 0) { |
513 | lshift = exponent - 1; |
514 | exponent = 0; |
515 | } else if (lshift == 0) { |
516 | exponent = 1; |
517 | } else { |
518 | lshift = 0; |
519 | } |
520 | if (exponent >= maxExponent) { |
521 | // Infinity or overflow |
522 | if (rounding.mode == common::RoundingMode::TiesToEven || |
523 | rounding.mode == common::RoundingMode::TiesAwayFromZero || |
524 | (rounding.mode == common::RoundingMode::Up && !negative) || |
525 | (rounding.mode == common::RoundingMode::Down && negative)) { |
526 | word_ = Word{maxExponent}.SHIFTL(significandBits); // Inf |
527 | } else { |
528 | // directed rounding: round to largest finite value rather than infinity |
529 | // (x86 does this, not sure whether it's standard behavior) |
530 | word_ = Word{word_.MASKR(word_.bits - 1)}.IBCLR(significandBits); |
531 | } |
532 | if (negative) { |
533 | word_ = word_.IBSET(bits - 1); |
534 | } |
535 | RealFlags flags{RealFlag::Overflow}; |
536 | if (!fraction.IsZero()) { |
537 | flags.set(RealFlag::Inexact); |
538 | } |
539 | return flags; |
540 | } |
541 | word_ = Word::ConvertUnsigned(fraction).value; |
542 | if (lshift > 0) { |
543 | word_ = word_.SHIFTL(lshift); |
544 | if (roundingBits) { |
545 | for (; lshift > 0; --lshift) { |
546 | if (roundingBits->ShiftLeft()) { |
547 | word_ = word_.IBSET(lshift - 1); |
548 | } |
549 | } |
550 | } |
551 | } |
552 | if constexpr (isImplicitMSB) { |
553 | word_ = word_.IBCLR(significandBits); |
554 | } |
555 | word_ = word_.IOR(Word{exponent}.SHIFTL(significandBits)); |
556 | if (negative) { |
557 | word_ = word_.IBSET(bits - 1); |
558 | } |
559 | return {}; |
560 | } |
561 | |
562 | template <typename W, int P> |
563 | RealFlags Real<W, P>::Round( |
564 | Rounding rounding, const RoundingBits &bits, bool multiply) { |
565 | int origExponent{Exponent()}; |
566 | RealFlags flags; |
567 | bool inexact{!bits.empty()}; |
568 | if (inexact) { |
569 | flags.set(RealFlag::Inexact); |
570 | } |
571 | if (origExponent < maxExponent && |
572 | bits.MustRound(rounding, IsNegative(), word_.BTEST(0) /* is odd */)) { |
573 | typename Fraction::ValueWithCarry sum{ |
574 | GetFraction().AddUnsigned(Fraction{}, true)}; |
575 | int newExponent{origExponent}; |
576 | if (sum.carry) { |
577 | // The fraction was all ones before rounding; sum.value is now zero |
578 | sum.value = sum.value.IBSET(binaryPrecision - 1); |
579 | if (++newExponent >= maxExponent) { |
580 | flags.set(RealFlag::Overflow); // rounded away to an infinity |
581 | } |
582 | } |
583 | flags |= Normalize(IsNegative(), newExponent, sum.value); |
584 | } |
585 | if (inexact && origExponent == 0) { |
586 | // inexact subnormal input: signal Underflow unless in an x86-specific |
587 | // edge case |
588 | if (rounding.x86CompatibleBehavior && Exponent() != 0 && multiply && |
589 | bits.sticky() && |
590 | (bits.guard() || |
591 | (rounding.mode != common::RoundingMode::Up && |
592 | rounding.mode != common::RoundingMode::Down))) { |
593 | // x86 edge case in which Underflow fails to signal when a subnormal |
594 | // inexact multiplication product rounds to a normal result when |
595 | // the guard bit is set or we're not using directed rounding |
596 | } else { |
597 | flags.set(RealFlag::Underflow); |
598 | } |
599 | } |
600 | return flags; |
601 | } |
602 | |
603 | template <typename W, int P> |
604 | void Real<W, P>::NormalizeAndRound(ValueWithRealFlags<Real> &result, |
605 | bool isNegative, int exponent, const Fraction &fraction, Rounding rounding, |
606 | RoundingBits roundingBits, bool multiply) { |
607 | result.flags |= result.value.Normalize( |
608 | isNegative, exponent, fraction, rounding, &roundingBits); |
609 | result.flags |= result.value.Round(rounding, roundingBits, multiply); |
610 | } |
611 | |
612 | inline enum decimal::FortranRounding MapRoundingMode( |
613 | common::RoundingMode rounding) { |
614 | switch (rounding) { |
615 | case common::RoundingMode::TiesToEven: |
616 | break; |
617 | case common::RoundingMode::ToZero: |
618 | return decimal::RoundToZero; |
619 | case common::RoundingMode::Down: |
620 | return decimal::RoundDown; |
621 | case common::RoundingMode::Up: |
622 | return decimal::RoundUp; |
623 | case common::RoundingMode::TiesAwayFromZero: |
624 | return decimal::RoundCompatible; |
625 | } |
626 | return decimal::RoundNearest; // dodge gcc warning about lack of result |
627 | } |
628 | |
629 | inline RealFlags MapFlags(decimal::ConversionResultFlags flags) { |
630 | RealFlags result; |
631 | if (flags & decimal::Overflow) { |
632 | result.set(RealFlag::Overflow); |
633 | } |
634 | if (flags & decimal::Inexact) { |
635 | result.set(RealFlag::Inexact); |
636 | } |
637 | if (flags & decimal::Invalid) { |
638 | result.set(RealFlag::InvalidArgument); |
639 | } |
640 | return result; |
641 | } |
642 | |
643 | template <typename W, int P> |
644 | ValueWithRealFlags<Real<W, P>> Real<W, P>::Read( |
645 | const char *&p, Rounding rounding) { |
646 | auto converted{ |
647 | decimal::ConvertToBinary<P>(p, MapRoundingMode(rounding.mode))}; |
648 | const auto *value{reinterpret_cast<Real<W, P> *>(&converted.binary)}; |
649 | return {*value, MapFlags(converted.flags)}; |
650 | } |
651 | |
652 | template <typename W, int P> std::string Real<W, P>::DumpHexadecimal() const { |
653 | if (IsNotANumber()) { |
654 | return "NaN0x"s + word_.Hexadecimal(); |
655 | } else if (IsNegative()) { |
656 | return "-"s + Negate().DumpHexadecimal(); |
657 | } else if (IsInfinite()) { |
658 | return "Inf"s ; |
659 | } else if (IsZero()) { |
660 | return "0.0"s ; |
661 | } else { |
662 | Fraction frac{GetFraction()}; |
663 | std::string result{"0x" }; |
664 | char intPart = '0' + frac.BTEST(frac.bits - 1); |
665 | result += intPart; |
666 | result += '.'; |
667 | int trailz{frac.TRAILZ()}; |
668 | if (trailz >= frac.bits - 1) { |
669 | result += '0'; |
670 | } else { |
671 | int remainingBits{frac.bits - 1 - trailz}; |
672 | int wholeNybbles{remainingBits / 4}; |
673 | int lostBits{remainingBits - 4 * wholeNybbles}; |
674 | if (wholeNybbles > 0) { |
675 | std::string fracHex{frac.SHIFTR(trailz + lostBits) |
676 | .IAND(frac.MASKR(4 * wholeNybbles)) |
677 | .Hexadecimal()}; |
678 | std::size_t field = wholeNybbles; |
679 | if (fracHex.size() < field) { |
680 | result += std::string(field - fracHex.size(), '0'); |
681 | } |
682 | result += fracHex; |
683 | } |
684 | if (lostBits > 0) { |
685 | result += frac.SHIFTR(trailz) |
686 | .IAND(frac.MASKR(lostBits)) |
687 | .SHIFTL(4 - lostBits) |
688 | .Hexadecimal(); |
689 | } |
690 | } |
691 | result += 'p'; |
692 | int exponent = Exponent() - exponentBias; |
693 | if (intPart == '0') { |
694 | exponent += 1; |
695 | } |
696 | result += Integer<32>{exponent}.SignedDecimal(); |
697 | return result; |
698 | } |
699 | } |
700 | |
701 | template <typename W, int P> |
702 | llvm::raw_ostream &Real<W, P>::AsFortran( |
703 | llvm::raw_ostream &o, int kind, bool minimal) const { |
704 | if (IsNotANumber()) { |
705 | o << "(0._" << kind << "/0.)" ; |
706 | } else if (IsInfinite()) { |
707 | if (IsNegative()) { |
708 | o << "(-1._" << kind << "/0.)" ; |
709 | } else { |
710 | o << "(1._" << kind << "/0.)" ; |
711 | } |
712 | } else { |
713 | using B = decimal::BinaryFloatingPointNumber<P>; |
714 | B value{word_.template ToUInt<typename B::RawType>()}; |
715 | char buffer[common::MaxDecimalConversionDigits(P) + |
716 | EXTRA_DECIMAL_CONVERSION_SPACE]; |
717 | decimal::DecimalConversionFlags flags{}; // default: exact representation |
718 | if (minimal) { |
719 | flags = decimal::Minimize; |
720 | } |
721 | auto result{decimal::ConvertToDecimal<P>(buffer, sizeof buffer, flags, |
722 | static_cast<int>(sizeof buffer), decimal::RoundNearest, value)}; |
723 | const char *p{result.str}; |
724 | if (DEREF(p) == '-' || *p == '+') { |
725 | o << *p++; |
726 | } |
727 | int expo{result.decimalExponent}; |
728 | if (*p != '0') { |
729 | --expo; |
730 | } |
731 | o << *p << '.' << (p + 1); |
732 | if (expo != 0) { |
733 | o << 'e' << expo; |
734 | } |
735 | o << '_' << kind; |
736 | } |
737 | return o; |
738 | } |
739 | |
740 | // 16.9.180 |
741 | template <typename W, int P> Real<W, P> Real<W, P>::RRSPACING() const { |
742 | if (IsNotANumber()) { |
743 | return *this; |
744 | } else if (IsInfinite()) { |
745 | return NotANumber(); |
746 | } else { |
747 | Real result; |
748 | result.Normalize(false, binaryPrecision + exponentBias - 1, GetFraction()); |
749 | return result; |
750 | } |
751 | } |
752 | |
753 | // 16.9.180 |
754 | template <typename W, int P> Real<W, P> Real<W, P>::SPACING() const { |
755 | if (IsNotANumber()) { |
756 | return *this; |
757 | } else if (IsInfinite()) { |
758 | return NotANumber(); |
759 | } else if (IsZero() || IsSubnormal()) { |
760 | return TINY(); // mandated by standard |
761 | } else { |
762 | Real result; |
763 | result.Normalize(false, Exponent(), Fraction::MASKR(1)); |
764 | return result.IsZero() ? TINY() : result; |
765 | } |
766 | } |
767 | |
768 | // 16.9.171 |
769 | template <typename W, int P> |
770 | Real<W, P> Real<W, P>::SET_EXPONENT(std::int64_t expo) const { |
771 | if (IsNotANumber()) { |
772 | return *this; |
773 | } else if (IsInfinite()) { |
774 | return NotANumber(); |
775 | } else if (IsZero()) { |
776 | return *this; |
777 | } else { |
778 | return SCALE(Integer<64>(expo - UnbiasedExponent() - 1)).value; |
779 | } |
780 | } |
781 | |
782 | // 16.9.171 |
783 | template <typename W, int P> Real<W, P> Real<W, P>::FRACTION() const { |
784 | return SET_EXPONENT(0); |
785 | } |
786 | |
787 | template class Real<Integer<16>, 11>; |
788 | template class Real<Integer<16>, 8>; |
789 | template class Real<Integer<32>, 24>; |
790 | template class Real<Integer<64>, 53>; |
791 | template class Real<X87IntegerContainer, 64>; |
792 | template class Real<Integer<128>, 113>; |
793 | } // namespace Fortran::evaluate::value |
794 | |