FLANG
real.h
1//===-- include/flang/Evaluate/real.h ---------------------------*- C++ -*-===//
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#ifndef FORTRAN_EVALUATE_REAL_H_
10#define FORTRAN_EVALUATE_REAL_H_
11
12#include "formatting.h"
13#include "integer.h"
14#include "rounding-bits.h"
15#include "flang/Common/real.h"
16#include "flang/Evaluate/target.h"
17#include <cinttypes>
18#include <limits>
19#include <string>
20
21// Some environments, viz. glibc 2.17 and *BSD, allow the macro HUGE
22// to leak out of <math.h>.
23#undef HUGE
24
25namespace llvm {
26class raw_ostream;
27}
28namespace Fortran::evaluate::value {
29
30// LOG10(2.)*1E12
31static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
32
33// Ignore error about requesting a large alignment not being ABI compatible
34// with older AIX systems.
35#if defined(_AIX)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Waix-compat"
38#endif
39// Models IEEE binary floating-point numbers (IEEE 754-2008,
40// ISO/IEC/IEEE 60559.2011). The first argument to this
41// class template must be (or look like) an instance of Integer<>;
42// the second specifies the number of effective bits (binary precision)
43// in the fraction.
44template <typename WORD, int PREC> class Real {
45public:
46 using Word = WORD;
47 static constexpr int binaryPrecision{PREC};
48 static constexpr common::RealCharacteristics realChars{PREC};
49 static constexpr int exponentBias{realChars.exponentBias};
50 static constexpr int exponentBits{realChars.exponentBits};
51 static constexpr int isImplicitMSB{realChars.isImplicitMSB};
52 static constexpr int maxExponent{realChars.maxExponent};
53 static constexpr int significandBits{realChars.significandBits};
54
55 static constexpr int bits{Word::bits};
56 static_assert(bits >= realChars.bits);
57 using Fraction = Integer<binaryPrecision>; // all bits made explicit
58
59 template <typename W, int P> friend class Real;
60
61 constexpr Real() {} // +0.0
62 constexpr Real(const Real &) = default;
63 constexpr Real(Real &&) = default;
64 constexpr Real(const Word &bits) : word_{bits} {}
65 constexpr Real &operator=(const Real &) = default;
66 constexpr Real &operator=(Real &&) = default;
67
68 constexpr bool operator==(const Real &that) const {
69 return word_ == that.word_;
70 }
71
72 constexpr bool IsSignBitSet() const { return word_.BTEST(bits - 1); }
73 constexpr bool IsNegative() const {
74 return !IsNotANumber() && IsSignBitSet();
75 }
76 constexpr bool IsNotANumber() const {
77 auto expo{Exponent()};
78 auto sig{GetSignificand()};
79 if constexpr (bits == 80) { // x87
80 // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later.
81 if (expo == maxExponent) {
82 return sig != Significand{}.IBSET(63);
83 } else {
84 return expo != 0 && !sig.BTEST(63);
85 }
86 } else {
87 return expo == maxExponent && !sig.IsZero();
88 }
89 }
90 constexpr bool IsQuietNaN() const {
91 auto expo{Exponent()};
92 auto sig{GetSignificand()};
93 if constexpr (bits == 80) { // x87
94 if (expo == maxExponent) {
95 return sig.IBITS(62, 2) == 3;
96 } else {
97 return expo != 0 && !sig.BTEST(63);
98 }
99 } else {
100 return expo == maxExponent && sig.BTEST(significandBits - 1);
101 }
102 }
103 constexpr bool IsSignalingNaN() const {
104 auto expo{Exponent()};
105 auto sig{GetSignificand()};
106 if constexpr (bits == 80) { // x87
107 return expo == maxExponent && sig != Significand{}.IBSET(63) &&
108 sig.IBITS(62, 2) != 3;
109 } else {
110 return expo == maxExponent && !sig.IsZero() &&
111 !sig.BTEST(significandBits - 1);
112 }
113 }
114 constexpr bool IsInfinite() const {
115 if constexpr (bits == 80) { // x87
116 // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later.
117 return Exponent() == maxExponent &&
118 GetSignificand() == Significand{}.IBSET(63);
119 } else {
120 return Exponent() == maxExponent && GetSignificand().IsZero();
121 }
122 }
123 constexpr bool IsFinite() const {
124 auto expo{Exponent()};
125 if constexpr (bits == 80) { // x87
126 return expo != maxExponent && (expo == 0 || GetSignificand().BTEST(63));
127 } else {
128 return expo != maxExponent;
129 }
130 }
131 constexpr bool IsZero() const {
132 return Exponent() == 0 && GetSignificand().IsZero();
133 }
134 constexpr bool IsSubnormal() const {
135 return Exponent() == 0 && !GetSignificand().IsZero();
136 }
137 constexpr bool IsNormal() const {
138 return !(IsInfinite() || IsNotANumber() || IsSubnormal());
139 }
140
141 constexpr Real ABS() const { // non-arithmetic, no flags returned
142 return {word_.IBCLR(bits - 1)};
143 }
144 constexpr Real SetSign(bool toNegative) const { // non-arithmetic
145 if (toNegative) {
146 return {word_.IBSET(bits - 1)};
147 } else {
148 return ABS();
149 }
150 }
151 constexpr Real SIGN(const Real &x) const { return SetSign(x.IsSignBitSet()); }
152
153 constexpr Real Negate() const { return {word_.IEOR(word_.MASKL(1))}; }
154
155 Relation Compare(const Real &) const;
156 ValueWithRealFlags<Real> Add(const Real &,
157 Rounding rounding = TargetCharacteristics::defaultRounding) const;
158 ValueWithRealFlags<Real> Subtract(const Real &y,
159 Rounding rounding = TargetCharacteristics::defaultRounding) const {
160 return Add(y.Negate(), rounding);
161 }
162 ValueWithRealFlags<Real> Multiply(const Real &,
163 Rounding rounding = TargetCharacteristics::defaultRounding) const;
164 ValueWithRealFlags<Real> Divide(const Real &,
165 Rounding rounding = TargetCharacteristics::defaultRounding) const;
166
168 Rounding rounding = TargetCharacteristics::defaultRounding) const;
169 // NEAREST(), IEEE_NEXT_AFTER(), IEEE_NEXT_UP(), and IEEE_NEXT_DOWN()
170 ValueWithRealFlags<Real> NEAREST(bool upward) const;
171 // HYPOT(x,y)=SQRT(x**2 + y**2) computed so as to avoid spurious
172 // intermediate overflows.
173 ValueWithRealFlags<Real> HYPOT(const Real &,
174 Rounding rounding = TargetCharacteristics::defaultRounding) const;
175 // DIM(X,Y) = MAX(X-Y, 0)
176 ValueWithRealFlags<Real> DIM(const Real &,
177 Rounding rounding = TargetCharacteristics::defaultRounding) const;
178 // MOD(x,y) = x - AINT(x/y)*y (in the standard)
179 // MODULO(x,y) = x - FLOOR(x/y)*y (in the standard)
180 ValueWithRealFlags<Real> MOD(const Real &,
181 Rounding rounding = TargetCharacteristics::defaultRounding) const;
182 ValueWithRealFlags<Real> MODULO(const Real &,
183 Rounding rounding = TargetCharacteristics::defaultRounding) const;
184 ValueWithRealFlags<Real> KahanSummation(const Real &, Real &correction,
185 Rounding rounding = TargetCharacteristics::defaultRounding) const;
186
187 template <typename INT> constexpr INT EXPONENT() const {
188 if (Exponent() == maxExponent) {
189 return INT::HUGE();
190 } else if (IsZero()) {
191 return {0};
192 } else {
193 return {UnbiasedExponent() + 1};
194 }
195 }
196
197 static constexpr Real EPSILON() {
198 Real epsilon;
199 epsilon.Normalize(
200 false, exponentBias + 1 - binaryPrecision, Fraction::MASKL(1));
201 return epsilon;
202 }
203 static constexpr Real HUGE() {
204 Real huge;
205 huge.Normalize(false, maxExponent - 1, Fraction::MASKR(binaryPrecision));
206 return huge;
207 }
208 static constexpr Real TINY() {
209 Real tiny;
210 tiny.Normalize(false, 1, Fraction::MASKL(1)); // minimum *normal* number
211 return tiny;
212 }
213
214 static constexpr int DIGITS{binaryPrecision};
215 static constexpr int PRECISION{realChars.decimalPrecision};
216 static constexpr int RANGE{realChars.decimalRange};
217 static constexpr int MAXEXPONENT{maxExponent - exponentBias};
218 static constexpr int MINEXPONENT{2 - exponentBias};
219 Real RRSPACING() const;
220 Real SPACING() const;
221 Real SET_EXPONENT(std::int64_t) const;
222 Real FRACTION() const;
223
224 // SCALE(); also known as IEEE_SCALB and (in IEEE-754 '08) ScaleB.
225 template <typename INT>
226 ValueWithRealFlags<Real> SCALE(const INT &by,
227 Rounding rounding = TargetCharacteristics::defaultRounding) const {
228 // Normalize a fraction with just its LSB set and then multiply.
229 // (Set the LSB, not the MSB, in case the scale factor needs to
230 // be subnormal.)
231 constexpr auto adjust{exponentBias + binaryPrecision - 1};
232 constexpr auto maxCoeffExpo{maxExponent + binaryPrecision - 1};
233 auto expo{adjust + by.ToInt64()};
234 RealFlags flags;
235 int rMask{1};
236 if (IsZero()) {
237 expo = exponentBias; // ignore by, don't overflow
238 } else if (expo > maxCoeffExpo) {
239 if (Exponent() < exponentBias) {
240 // Must implement with two multiplications
241 return SCALE(INT{exponentBias})
242 .value.SCALE(by.SubtractSigned(INT{exponentBias}).value, rounding);
243 } else { // overflow
244 expo = maxCoeffExpo;
245 }
246 } else if (expo < 0) {
247 if (Exponent() > exponentBias) {
248 // Must implement with two multiplications
249 return SCALE(INT{-exponentBias})
250 .value.SCALE(by.AddSigned(INT{exponentBias}).value, rounding);
251 } else { // underflow to zero
252 expo = 0;
253 rMask = 0;
254 flags.set(RealFlag::Underflow);
255 }
256 }
257 Real twoPow;
258 flags |=
259 twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(rMask));
260 ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
261 result.flags |= flags;
262 return result;
263 }
264
265 constexpr Real FlushSubnormalToZero() const {
266 if (IsSubnormal()) {
267 return Real{};
268 }
269 return *this;
270 }
271
272 // TODO: Configurable NotANumber representations
273 static constexpr Real NotANumber() {
274 return {Word{maxExponent}
275 .SHIFTL(significandBits)
276 .IBSET(significandBits - 1)
277 .IBSET(significandBits - 2)};
278 }
279
280 static constexpr Real PositiveZero() { return Real{}; }
281
282 static constexpr Real NegativeZero() { return {Word{}.MASKL(1)}; }
283
284 static constexpr Real Infinity(bool negative) {
285 Word infinity{maxExponent};
286 infinity = infinity.SHIFTL(significandBits);
287 if (negative) {
288 infinity = infinity.IBSET(infinity.bits - 1);
289 }
290 if constexpr (bits == 80) { // x87
291 // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later.
292 infinity = infinity.IBSET(63);
293 }
294 return {infinity};
295 }
296
297 template <typename INT>
298 static ValueWithRealFlags<Real> FromInteger(const INT &n,
299 bool isUnsigned = false,
300 Rounding rounding = TargetCharacteristics::defaultRounding) {
301 bool isNegative{!isUnsigned && n.IsNegative()};
302 INT absN{n};
303 if (isNegative) {
304 absN = n.Negate().value; // overflow is safe to ignore
305 }
306 int leadz{absN.LEADZ()};
307 if (leadz >= absN.bits) {
308 return {}; // all bits zero -> +0.0
309 }
311 int exponent{exponentBias + absN.bits - leadz - 1};
312 int bitsNeeded{absN.bits - (leadz + isImplicitMSB)};
313 int bitsLost{bitsNeeded - significandBits};
314 if (bitsLost <= 0) {
315 Fraction fraction{Fraction::ConvertUnsigned(absN).value};
316 result.flags |= result.value.Normalize(
317 isNegative, exponent, fraction.SHIFTL(-bitsLost));
318 } else {
319 Fraction fraction{Fraction::ConvertUnsigned(absN.SHIFTR(bitsLost)).value};
320 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
321 RoundingBits roundingBits{absN, bitsLost};
322 result.flags |= result.value.Round(rounding, roundingBits);
323 }
324 return result;
325 }
326
327 // Conversion to integer in the same real format (AINT(), ANINT())
328 ValueWithRealFlags<Real> ToWholeNumber(
329 common::RoundingMode = common::RoundingMode::ToZero) const;
330
331 // Conversion to an integer (INT(), NINT(), FLOOR(), CEILING())
332 template <typename INT>
333 constexpr ValueWithRealFlags<INT> ToInteger(
334 common::RoundingMode mode = common::RoundingMode::ToZero) const {
336 if (IsNotANumber()) {
337 result.flags.set(RealFlag::InvalidArgument);
338 result.value = result.value.HUGE();
339 return result;
340 }
341 ValueWithRealFlags<Real> intPart{ToWholeNumber(mode)};
342 result.flags |= intPart.flags;
343 int exponent{intPart.value.Exponent()};
344 // shift positive -> left shift, negative -> right shift
345 int shift{exponent - exponentBias - binaryPrecision + 1};
346 // Apply any right shift before moving to the result type
347 auto rshifted{intPart.value.GetFraction().SHIFTR(-shift)};
348 auto converted{result.value.ConvertUnsigned(rshifted)};
349 if (converted.overflow) {
350 result.flags.set(RealFlag::Overflow);
351 }
352 result.value = converted.value.SHIFTL(shift);
353 if (converted.value.CompareUnsigned(result.value.SHIFTR(shift)) !=
354 Ordering::Equal) {
355 result.flags.set(RealFlag::Overflow);
356 }
357 if (IsSignBitSet()) {
358 result.value = result.value.Negate().value;
359 }
360 if (!result.value.IsZero()) {
361 if (IsSignBitSet() != result.value.IsNegative()) {
362 result.flags.set(RealFlag::Overflow);
363 }
364 }
365 if (result.flags.test(RealFlag::Overflow)) {
366 result.value =
367 IsSignBitSet() ? result.value.MASKL(1) : result.value.HUGE();
368 }
369 return result;
370 }
371
372 template <typename A>
373 static ValueWithRealFlags<Real> Convert(
374 const A &x, Rounding rounding = TargetCharacteristics::defaultRounding) {
376 if (x.IsNotANumber()) {
377 result.flags.set(RealFlag::InvalidArgument);
378 result.value = NotANumber();
379 return result;
380 }
381 bool isNegative{x.IsNegative()};
382 if (x.IsInfinite()) {
383 result.value = Infinity(isNegative);
384 return result;
385 }
386 A absX{x};
387 if (isNegative) {
388 absX = x.Negate();
389 }
390 int exponent{exponentBias + x.UnbiasedExponent()};
391 int bitsLost{A::binaryPrecision - binaryPrecision};
392 if (exponent < 1) {
393 bitsLost += 1 - exponent;
394 exponent = 1;
395 }
396 typename A::Fraction xFraction{x.GetFraction()};
397 if (bitsLost <= 0) {
398 Fraction fraction{
399 Fraction::ConvertUnsigned(xFraction).value.SHIFTL(-bitsLost)};
400 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
401 } else {
402 Fraction fraction{
403 Fraction::ConvertUnsigned(xFraction.SHIFTR(bitsLost)).value};
404 result.flags |= result.value.Normalize(isNegative, exponent, fraction);
405 RoundingBits roundingBits{xFraction, bitsLost};
406 result.flags |= result.value.Round(rounding, roundingBits);
407 }
408 return result;
409 }
410
411 constexpr Word RawBits() const { return word_; }
412
413 // Extracts "raw" biased exponent field.
414 constexpr int Exponent() const {
415 return word_.IBITS(significandBits, exponentBits).ToUInt64();
416 }
417
418 // Extracts the fraction; any implied bit is made explicit.
419 constexpr Fraction GetFraction() const {
420 Fraction result{Fraction::ConvertUnsigned(word_).value};
421 if constexpr (!isImplicitMSB) {
422 return result;
423 } else {
424 int exponent{Exponent()};
425 if (exponent > 0 && exponent < maxExponent) {
426 return result.IBSET(significandBits);
427 } else {
428 return result.IBCLR(significandBits);
429 }
430 }
431 }
432
433 // Extracts unbiased exponent value.
434 // Corrects the exponent value of a subnormal number.
435 // Note that the result is one less than the EXPONENT intrinsic;
436 // UnbiasedExponent(1.0) is 0, not 1.
437 constexpr int UnbiasedExponent() const {
438 int exponent{Exponent() - exponentBias};
439 if (IsSubnormal()) {
440 ++exponent;
441 }
442 return exponent;
443 }
444
445 static ValueWithRealFlags<Real> Read(const char *&,
446 Rounding rounding = TargetCharacteristics::defaultRounding);
447 std::string DumpHexadecimal() const;
448
449 // Emits a character representation for an equivalent Fortran constant
450 // or parenthesized constant expression that produces this value.
451 llvm::raw_ostream &AsFortran(
452 llvm::raw_ostream &, int kind, bool minimal = false) const;
453 std::string AsFortran(int kind, bool minimal = false) const;
454
455private:
456 using Significand = Integer<significandBits>; // no implicit bit
457
458 constexpr Significand GetSignificand() const {
459 return Significand::ConvertUnsigned(word_).value;
460 }
461
462 constexpr int CombineExponents(const Real &y, bool forDivide) const {
463 int exponent = Exponent(), yExponent = y.Exponent();
464 // A zero exponent field value has the same weight as 1.
465 exponent += !exponent;
466 yExponent += !yExponent;
467 if (forDivide) {
468 exponent += exponentBias - yExponent;
469 } else {
470 exponent += yExponent - exponentBias + 1;
471 }
472 return exponent;
473 }
474
475 static constexpr bool NextQuotientBit(
476 Fraction &top, bool &msb, const Fraction &divisor) {
477 bool greaterOrEqual{msb || top.CompareUnsigned(divisor) != Ordering::Less};
478 if (greaterOrEqual) {
479 top = top.SubtractSigned(divisor).value;
480 }
481 auto doubled{top.AddUnsigned(top)};
482 top = doubled.value;
483 msb = doubled.carry;
484 return greaterOrEqual;
485 }
486
487 // Normalizes and marshals the fields of a floating-point number in place.
488 // The value is a number, and a zero fraction means a zero value (i.e.,
489 // a maximal exponent and zero fraction doesn't signify infinity, although
490 // this member function will detect overflow and encode infinities).
491 RealFlags Normalize(bool negative, int exponent, const Fraction &fraction,
492 Rounding rounding = TargetCharacteristics::defaultRounding,
493 RoundingBits *roundingBits = nullptr);
494
495 // Rounds a result, if necessary, in place.
496 RealFlags Round(Rounding, const RoundingBits &, bool multiply = false);
497
498 static void NormalizeAndRound(ValueWithRealFlags<Real> &result,
499 bool isNegative, int exponent, const Fraction &, Rounding, RoundingBits,
500 bool multiply = false);
501
502 // Require alignment, in case code generation on x86_64 decides that our
503 // Real object is suitable for SSE2 instructions and then gets surprised
504 // by unaligned address.
505 alignas(Word::alignment / 8) Word word_{}; // an Integer<>
506};
507#if defined(_AIX)
508#pragma GCC diagnostic pop
509#endif
510
511extern template class Real<Integer<16>, 11>; // IEEE half format
512extern template class Real<Integer<16>, 8>; // the "other" half format
513extern template class Real<Integer<32>, 24>; // IEEE single
514extern template class Real<Integer<64>, 53>; // IEEE double
515extern template class Real<X87IntegerContainer, 64>; // 80387 extended precision
516extern template class Real<Integer<128>, 113>; // IEEE quad
517// N.B. No "double-double" support.
518} // namespace Fortran::evaluate::value
519#endif // FORTRAN_EVALUATE_REAL_H_
Definition integer.h:65
Definition real.h:44
Definition rounding-bits.h:20
Definition target-rounding.h:18