FLANG

rounding-bits.h
1 //===-- include/flang/Evaluate/rounding-bits.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_ROUNDING_BITS_H_
10 #define FORTRAN_EVALUATE_ROUNDING_BITS_H_
11
12 // A helper class used by Real<> to determine rounding of rational results
13 // to floating-point values. Bits lost from intermediate computations by
14 // being shifted rightward are accumulated in instances of this class.
15
16 namespace Fortran::evaluate::value {
17
18 class RoundingBits {
19 public:
20 constexpr RoundingBits(
21 bool guard = false, bool round = false, bool sticky = false)
22 : guard_{guard}, round_{round}, sticky_{sticky} {}
23
24 template <typename FRACTION>
25 constexpr RoundingBits(const FRACTION &fraction, int rshift) {
26 if (rshift > 0 && rshift < fraction.bits + 1) {
27 guard_ = fraction.BTEST(rshift - 1);
28 }
29 if (rshift > 1 && rshift < fraction.bits + 2) {
30 round_ = fraction.BTEST(rshift - 2);
31 }
32 if (rshift > 2) {
33 if (rshift >= fraction.bits + 2) {
34 sticky_ = !fraction.IsZero();
35 } else {
36 auto mask{fraction.MASKR(rshift - 2)};
37 sticky_ = !fraction.IAND(mask).IsZero();
38 }
39 }
40 }
41
42 constexpr bool guard() const { return guard_; }
43 constexpr bool round() const { return round_; }
44 constexpr bool sticky() const { return sticky_; }
45 constexpr bool empty() const { return !(guard_ | round_ | sticky_); }
46
47 constexpr bool Negate() {
48 bool carry{!sticky_};
49 if (carry) {
50 carry = !round_;
51 } else {
52 round_ = !round_;
53 }
54 if (carry) {
55 carry = !guard_;
56 } else {
57 guard_ = !guard_;
58 }
59 return carry;
60 }
61
62 constexpr bool ShiftLeft() {
63 bool oldGuard{guard_};
64 guard_ = round_;
65 round_ = sticky_;
66 return oldGuard;
67 }
68
69 constexpr void ShiftRight(bool newGuard) {
70 sticky_ |= round_;
71 round_ = guard_;
72 guard_ = newGuard;
73 }
74
75 // Determines whether a value should be rounded by increasing its
76 // fraction, given a rounding mode and a summary of the lost bits.
77 constexpr bool MustRound(
78 Rounding rounding, bool isNegative, bool isOdd) const {
79 bool round{false}; // to dodge bogus g++ warning about missing return
80 switch (rounding.mode) {
81 case common::RoundingMode::TiesToEven:
82 round = guard_ && (round_ | sticky_ | isOdd);
83 break;
84 case common::RoundingMode::ToZero:
85 break;
86 case common::RoundingMode::Down:
87 round = isNegative && !empty();
88 break;
89 case common::RoundingMode::Up:
90 round = !isNegative && !empty();
91 break;
92 case common::RoundingMode::TiesAwayFromZero:
93 round = guard_;
94 break;
95 }
96 return round;
97 }
98
99 private:
100 bool guard_{false}; // 0.5 * ulp (unit in lowest place)
101 bool round_{false}; // 0.25 * ulp
102 bool sticky_{false}; // true if any lesser-valued bit would be set
103 };
104 } // namespace Fortran::evaluate::value
105 #endif // FORTRAN_EVALUATE_ROUNDING_BITS_H_
Fortran::evaluate::value::RoundingBits
Definition: rounding-bits.h:18
Fortran::evaluate::Rounding
Definition: common.h:122
Fortran::evaluate::Negate
Definition: expression.h:229