1 //===-- lib/Evaluate/real.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
17 namespace Fortran::evaluate::value
{
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()) {
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
;
29 } else { // +/-Inf vs finite
30 return IsNegative() ? Relation::Less
: Relation::Greater
;
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
40 return isNegative
? Relation::Less
: Relation::Greater
;
44 Ordering order
{evaluate::Compare(Exponent(), y
.Exponent())};
45 if (order
== Ordering::Equal
) {
46 order
= GetSignificand().CompareUnsigned(y
.GetSignificand());
49 order
= Reverse(order
);
51 return RelationFromOrdering(order
);
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
);
67 bool isNegative
{IsNegative()};
68 bool yIsNegative
{y
.IsNegative()};
71 if (isNegative
== yIsNegative
) {
72 result
.value
= *this; // +/-Inf + +/-Inf -> +/-Inf
74 result
.value
= NotANumber(); // +/-Inf + -/+Inf -> NaN
75 result
.flags
.set(RealFlag::InvalidArgument
);
78 result
.value
= *this; // +/-Inf + x -> +/-Inf
83 result
.value
= y
; // x + +/-Inf -> +/-Inf
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
);
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
);
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();
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
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
115 RoundingBits roundingBits
{yFraction
, rshift
};
116 yFraction
= yFraction
.SHIFTR(rshift
);
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();
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);
132 result
, isNegative
, exponent
, fraction
, rounding
, roundingBits
);
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
);
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
);
152 result
.value
= Infinity(isNegative
);
155 auto product
{GetFraction().MultiplyUnsigned(y
.GetFraction())};
156 std::int64_t exponent
{CombineExponents(y
, false)};
158 int rshift
= 1 - exponent
;
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() ||
166 .IAND(product
.upper
.MASKR(rshift
- product
.lower
.bits
))
169 sticky
= !product
.lower
.IAND(product
.lower
.MASKR(rshift
)).IsZero();
171 product
.lower
= product
.lower
.SHIFTRWithFill(product
.upper
, rshift
);
172 product
.upper
= product
.upper
.SHIFTR(rshift
);
174 product
.lower
= product
.lower
.IBSET(0);
177 int leadz
{product
.upper
.LEADZ()};
178 if (leadz
>= product
.upper
.bits
) {
179 leadz
+= product
.lower
.LEADZ();
182 if (lshift
> exponent
- 1) {
183 lshift
= exponent
- 1;
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*/);
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
);
206 bool isNegative
{IsNegative() != y
.IsNegative()};
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
);
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
);
222 } else if (IsZero() || y
.IsInfinite()) { // 0/x, x/Inf -> 0
224 result
.value
= NegativeZero();
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)};
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
;
240 for (int j
{1}; j
<= quotient
.bits
; ++j
) {
241 if (NextQuotientBit(top
, msb
, divisor
)) {
242 quotient
= quotient
.IBSET(quotient
.bits
- j
);
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
};
250 std::int64_t rshift
{1 - exponent
};
251 for (; rshift
> 0; --rshift
) {
252 roundingBits
.ShiftRight(quotient
.BTEST(0));
253 quotient
= quotient
.SHIFTR(1);
258 result
, isNegative
, exponent
, quotient
, rounding
, roundingBits
);
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
);
272 } else if (IsNegative()) {
274 // SQRT(-0) == -0 in IEEE-754.
275 result
.value
= NegativeZero();
277 result
.flags
.set(RealFlag::InvalidArgument
);
278 result
.value
= NotANumber();
280 } else if (IsInfinite()) {
281 // SQRT(+Inf) == +Inf
282 result
.value
= Infinity(false);
283 } else if (IsZero()) {
284 result
.value
= PositiveZero();
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)
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());
301 // (-1) <= expo <= 1; use it as a shift to set the desired square.
302 using Extended
= typename
value::Integer
<(binaryPrecision
+ 2)>;
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
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
) {
316 } else if (cmp
== Ordering::Equal
&& squared
.lower
.IsZero()) {
319 break; // exact result
322 RoundingBits roundingBits
{extFrac
.BTEST(1), extFrac
.BTEST(0), sticky
};
323 NormalizeAndRound(result
, false, exponentBias
,
324 Fraction::ConvertUnsigned(extFrac
.SHIFTR(2)).value
, rounding
,
330 template <typename W
, int P
>
331 ValueWithRealFlags
<Real
<W
, P
>> Real
<W
, P
>::NEAREST(bool upward
) const {
332 ValueWithRealFlags
<Real
> result
;
334 Fraction fraction
{GetFraction()};
335 int expo
{Exponent()};
338 bool isNegative
{IsNegative()};
339 if (upward
!= isNegative
) { // upward in magnitude
340 auto next
{fraction
.AddUnsigned(one
)};
343 nearest
= Fraction::Least(); // MSB only
345 nearest
= next
.value
;
347 } else { // downward in magnitude
349 nearest
= 1; // smallest magnitude negative subnormal
350 isNegative
= !isNegative
;
352 auto sub1
{fraction
.SubtractSigned(one
)};
353 if (sub1
.overflow
&& expo
> 1) {
354 nearest
= Fraction
{0}.NOT();
357 nearest
= sub1
.value
;
361 result
.flags
= result
.value
.Normalize(isNegative
, expo
, nearest
);
363 result
.flags
.set(RealFlag::InvalidArgument
);
364 result
.value
= *this;
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
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
);
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
);
398 result
.flags
.set(RealFlag::Inexact
);
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;
422 result
.value
= ABS();
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
) {
431 result
.value
.Subtract(adj
, rounding
).AccumulateFlags(result
.flags
);
432 if (result
.value
.IsZero()) {
438 result
.value
= result
.value
.Negate();
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();
455 result
.value
.Add(p
, rounding
).AccumulateFlags(result
.flags
);
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
);
471 // result is already zero
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
);
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.
495 result
.value
.Subtract(adjust
, Rounding
{common::RoundingMode::ToZero
})
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
) {
512 } else if (exponent
> 0) {
513 lshift
= exponent
- 1;
515 } else if (lshift
== 0) {
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
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
);
533 word_
= word_
.IBSET(bits
- 1);
535 RealFlags flags
{RealFlag::Overflow
};
536 if (!fraction
.IsZero()) {
537 flags
.set(RealFlag::Inexact
);
541 word_
= Word::ConvertUnsigned(fraction
).value
;
543 word_
= word_
.SHIFTL(lshift
);
545 for (; lshift
> 0; --lshift
) {
546 if (roundingBits
->ShiftLeft()) {
547 word_
= word_
.IBSET(lshift
- 1);
552 if constexpr (isImplicitMSB
) {
553 word_
= word_
.IBCLR(significandBits
);
555 word_
= word_
.IOR(Word
{exponent
}.SHIFTL(significandBits
));
557 word_
= word_
.IBSET(bits
- 1);
562 template <typename W
, int P
>
563 RealFlags Real
<W
, P
>::Round(
564 Rounding rounding
, const RoundingBits
&bits
, bool multiply
) {
565 int origExponent
{Exponent()};
567 bool inexact
{!bits
.empty()};
569 flags
.set(RealFlag::Inexact
);
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
};
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
583 flags
|= Normalize(IsNegative(), newExponent
, sum
.value
);
585 if (inexact
&& origExponent
== 0) {
586 // inexact subnormal input: signal Underflow unless in an x86-specific
588 if (rounding
.x86CompatibleBehavior
&& Exponent() != 0 && multiply
&&
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
597 flags
.set(RealFlag::Underflow
);
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
);
612 inline enum decimal::FortranRounding
MapRoundingMode(
613 common::RoundingMode rounding
) {
615 case common::RoundingMode::TiesToEven
:
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
;
626 return decimal::RoundNearest
; // dodge gcc warning about lack of result
629 inline RealFlags
MapFlags(decimal::ConversionResultFlags flags
) {
631 if (flags
& decimal::Overflow
) {
632 result
.set(RealFlag::Overflow
);
634 if (flags
& decimal::Inexact
) {
635 result
.set(RealFlag::Inexact
);
637 if (flags
& decimal::Invalid
) {
638 result
.set(RealFlag::InvalidArgument
);
643 template <typename W
, int P
>
644 ValueWithRealFlags
<Real
<W
, P
>> Real
<W
, P
>::Read(
645 const char *&p
, Rounding rounding
) {
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
)};
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()) {
659 } else if (IsZero()) {
662 Fraction frac
{GetFraction()};
663 std::string result
{"0x"};
664 char intPart
= '0' + frac
.BTEST(frac
.bits
- 1);
667 int trailz
{frac
.TRAILZ()};
668 if (trailz
>= frac
.bits
- 1) {
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
))
678 std::size_t field
= wholeNybbles
;
679 if (fracHex
.size() < field
) {
680 result
+= std::string(field
- fracHex
.size(), '0');
685 result
+= frac
.SHIFTR(trailz
)
686 .IAND(frac
.MASKR(lostBits
))
687 .SHIFTL(4 - lostBits
)
692 int exponent
= Exponent() - exponentBias
;
693 if (intPart
== '0') {
696 result
+= Integer
<32>{exponent
}.SignedDecimal();
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()) {
708 o
<< "(-1._" << kind
<< "/0.)";
710 o
<< "(1._" << kind
<< "/0.)";
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
719 flags
= decimal::Minimize
;
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
== '+') {
727 int expo
{result
.decimalExponent
};
731 o
<< *p
<< '.' << (p
+ 1);
741 template <typename W
, int P
> Real
<W
, P
> Real
<W
, P
>::RRSPACING() const {
742 if (IsNotANumber()) {
744 } else if (IsInfinite()) {
748 result
.Normalize(false, binaryPrecision
+ exponentBias
- 1, GetFraction());
754 template <typename W
, int P
> Real
<W
, P
> Real
<W
, P
>::SPACING() const {
755 if (IsNotANumber()) {
757 } else if (IsInfinite()) {
759 } else if (IsZero() || IsSubnormal()) {
760 return TINY(); // mandated by standard
763 result
.Normalize(false, Exponent(), Fraction::MASKR(1));
764 return result
.IsZero() ? TINY() : result
;
769 template <typename W
, int P
>
770 Real
<W
, P
> Real
<W
, P
>::SET_EXPONENT(std::int64_t expo
) const {
771 if (IsNotANumber()) {
773 } else if (IsInfinite()) {
775 } else if (IsZero()) {
778 return SCALE(Integer
<64>(expo
- UnbiasedExponent() - 1)).value
;
783 template <typename W
, int P
> Real
<W
, P
> Real
<W
, P
>::FRACTION() const {
784 return SET_EXPONENT(0);
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
<Integer
<80>, 64>;
792 template class Real
<Integer
<128>, 113>;
793 } // namespace Fortran::evaluate::value