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