FloatingPointControl_t.cc
Go to the documentation of this file.
1 #include "catch2/catch.hpp"
2 
7 
8 #include <sstream>
9 #include <string>
10 
11 #include <type_traits>
12 
13 using namespace std::string_literals;
14 using namespace art::fp_detail;
15 
16 namespace {
18  class Hexable {
19  public:
20  Hexable(T const t) : t_(t) {}
21  operator T() const { return t_; }
22 
23  private:
24  T t_;
25  };
26 
27  template <typename T>
28  inline Hexable<T>
29  hexit(T const t)
30  {
31  return Hexable<T>(t);
32  }
33 
34  inline void
35  compare_fpcw(art::FloatingPointControl& fpc,
36  fpcw_t const right,
37  std::string msg = "Checking current FP state against expected"s)
38  {
39  INFO(msg);
40  CHECK(hexit(getFPCW()) == hexit(right));
41  CHECK(hexit(static_cast<unsigned short int>(fpc.getPrecision())) ==
42  hexit(right & fpControl_ALL_PREC));
43  CHECK(hexit(fpc.getMask()) == hexit(right & FE_ALL_EXCEPT));
44  }
45 
46  void
47  verify_report(std::ostringstream const& os, fpcw_t mask)
48  {
49  auto test_string = os.str();
50  auto const pos = test_string.rfind("DivByZero exception is ");
51  if (pos != std::string::npos) {
52  std::string const ref(
53  "DivByZero exception is"s + on_or_off((~mask) & FE_DIVBYZERO) +
54  "\tInvalid exception is" + on_or_off((~mask) & FE_INVALID) +
55  "\tOverFlow exception is" + on_or_off((~mask) & FE_OVERFLOW) +
56  "\tUnderFlow exception is" + on_or_off((~mask) & FE_UNDERFLOW) + '\n');
57  CHECK(test_string.substr(pos) == ref);
58  } else {
59  CHECK(false);
60  }
61  }
62 
63  void
64  verify_report(std::ostringstream const& os)
65  {
66  verify_report(os, 0);
67  }
68 
69 } // namespace
70 
71 namespace Catch {
72  template <typename T>
73  struct StringMaker<Hexable<T>> {
74  static std::string
75  convert(T const t)
76  {
78  std::ostringstream out;
79  out << std::showbase << std::hex << t;
80  result = out.str();
81  return result;
82  }
83  };
84 } // namespace Catch
85 
86 SCENARIO("We wish to affect the floating point control on our system")
87 {
88  GIVEN("An empty activity registry and simple parameter set")
89  {
91 
93  ps.put("reportSettings", true);
94 
95  // Note config above sends output to stream we can capture:
96  auto& tstream = mf::getStringStream("TSTREAM_1");
97  tstream.str("");
98 
99  auto const fpcw_def = getFPCW();
100  auto const fpcw_ref = fpcw_def;
101  auto const fpcw_ref_dp =
102  (fpcw_ref & ~fpControl_ALL_PREC) | fpControl_DOUBLE_PREC;
103 
104  static auto verify_cleanup = [fpcw_def, &reg](auto& fpc) {
105  reg.sPostEndJob.invoke();
106  compare_fpcw(fpc, fpcw_def, "Checking final FP state against default"s);
107  };
108 
109  WHEN("We want the basic configuration")
110  {
111  art::FloatingPointControl fpc(ps, reg);
112  THEN("The configuration is unchanged except for double precision math.")
113  {
114  compare_fpcw(fpc, fpcw_ref_dp);
115  verify_report(tstream);
116  verify_cleanup(fpc);
117  }
118  }
119 
120  WHEN("We want to suppress divide-by-zero exceptions")
121  {
122  ps.put("enableDivByZeroEx", true);
123  art::FloatingPointControl fpc(ps, reg);
124  THEN("The configuration shows suppressed divide-by-zero exceptions")
125  {
126  compare_fpcw(fpc, fpcw_ref_dp & ~FE_DIVBYZERO);
127  verify_report(tstream, FE_DIVBYZERO);
128  verify_cleanup(fpc);
129  }
130  }
131 
132  WHEN("We want to suppress \"invalid\" exceptions")
133  {
134  ps.put("enableInvalidEx", true);
135  art::FloatingPointControl fpc(ps, reg);
136  THEN("The configuration shows suppressed \"invalid\" exceptions")
137  {
138  compare_fpcw(fpc, fpcw_ref_dp & ~FE_INVALID);
139  verify_report(tstream, FE_INVALID);
140  verify_cleanup(fpc);
141  }
142  }
143 
144  WHEN("We want to suppress overflow exceptions")
145  {
146  ps.put("enableOverFlowEx", true);
147  art::FloatingPointControl fpc(ps, reg);
148  THEN("The configuration shows suppressed overflow exceptions")
149  {
150  compare_fpcw(fpc, fpcw_ref_dp & ~FE_OVERFLOW);
151  verify_report(tstream, FE_OVERFLOW);
152  verify_cleanup(fpc);
153  }
154  }
155 
156  WHEN("We want to suppress underflow exceptions")
157  {
158  ps.put("enableUnderFlowEx", true);
159  art::FloatingPointControl fpc(ps, reg);
160  THEN("The configuration shows suppressed underflow exceptions")
161  {
162  compare_fpcw(fpc, fpcw_ref_dp & ~FE_UNDERFLOW);
163  verify_report(tstream, FE_UNDERFLOW);
164  verify_cleanup(fpc);
165  }
166  }
167 
168  WHEN("We want default precision")
169  {
170  ps.put("setPrecisionDouble", false);
171  art::FloatingPointControl fpc(ps, reg);
172  THEN("The configuration shows default precision")
173  {
174  compare_fpcw(fpc, fpcw_ref);
175  verify_report(tstream);
176  verify_cleanup(fpc);
177  }
178  }
179  }
180 }
static QCString result
void msg(const char *fmt,...)
Definition: message.cpp:107
std::string string
Definition: nybbler.cc:12
GlobalSignal< detail::SignalResponseType::LIFO, void()> sPostEndJob
QTextStream & hex(QTextStream &s)
std::ostringstream & getStringStream(std::string const &psetName)
Definition: stringstream.cc:15
precision_t getPrecision() const
char const * on_or_off(bool const b)
Definition: fpControl.h:154
static std::string convert(T const t)
static constexpr double ps
Definition: Units.h:99
fpcw_t getFPCW()
Definition: fpControl.cc:28
cet::registry_via_id< success_t, val > reg
static QCString * s
Definition: config.cpp:1042
typedef fpcw_t
Definition: fpControl.h:99
void put(std::string const &key)
SCENARIO("We wish to affect the floating point control on our system")