ChimeraTK-DeviceAccess  03.18.00
FixedPointConverter.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 #include "FixedPointConverter.h"
5 
6 #include "Exception.h"
7 
8 #include <utility>
9 
10 namespace ChimeraTK {
11 
12  const int FixedPointConverter::zero = 0;
13 
15  std::string variableName, unsigned int nBits, int fractionalBits, bool isSignedFlag)
16  : _variableName(std::move(variableName)), _nBits(nBits), _fractionalBits(fractionalBits), _isSigned(isSignedFlag),
17  _fractionalBitsCoefficient(pow(2., -fractionalBits)), _inverseFractionalBitsCoefficient(pow(2., fractionalBits)) {
18  reconfigure(nBits, fractionalBits, isSignedFlag);
19  }
20 
21  /********************************************************************************************************************/
22 
23  void FixedPointConverter::reconfigure(unsigned int nBits, int fractionalBits, bool isSignedFlag) {
24  _nBits = nBits;
25  _fractionalBits = fractionalBits;
26  _isSigned = isSignedFlag;
27  _fractionalBitsCoefficient = pow(2., -fractionalBits);
28  _inverseFractionalBitsCoefficient = pow(2., fractionalBits);
29 
30  _bitShiftMaskSigned = 0; // Fixme unused variable.
31  // some sanity checks
32  if(nBits > 32) {
33  std::stringstream errorMessage;
34  errorMessage << "The number of bits must be <= 32, but is " << nBits;
35  throw ChimeraTK::logic_error(errorMessage.str());
36  }
37 
38  // For floating-point types: check if number of fractional bits are complying
39  // with the dynamic range Note: positive fractional bits give us smaller
40  // numbers and thus correspond to negative exponents!
41  if((fractionalBits > -std::numeric_limits<double>::min_exponent - static_cast<int>(nBits)) ||
42  (fractionalBits < -std::numeric_limits<double>::max_exponent + static_cast<int>(nBits))) {
43  std::stringstream errorMessage;
44  errorMessage << "The number of fractional bits exceeds the dynamic"
45  << " range of a double.";
46  throw ChimeraTK::logic_error(errorMessage.str());
47  }
48 
49  // compute mask for the signed bit
50  // keep the mask at 0 if unsigned to simplify further calculations
51  if(nBits > 0) {
52  // NOLINTNEXTLINE(hicpp-signed-bitwise)
53  _signBitMask = (_isSigned ? 1 << (nBits - 1) : 0x0); // the highest valid bit is the sign
54  }
55  else {
56  _signBitMask = 0;
57  }
58 
59  // compute masks of used and unused bits
60  // by using 1L (64 bit) this also works for 32 bits, which needs 33 bits during the calculation
61  // NOLINTNEXTLINE(hicpp-signed-bitwise)
62  _usedBitsMask = static_cast<int32_t>((1L << nBits) - 1L);
63  // NOLINTNEXTLINE(hicpp-signed-bitwise)
64  _unusedBitsMask = ~_usedBitsMask;
65 
66  // compute bit shift mask, used to test if bit shifting for fractional bits
67  // leads to an overflow
68  // NOLINTNEXTLINE(hicpp-signed-bitwise)
69  _bitShiftMask = static_cast<int32_t>(~(0xFFFFFFFF >> abs(_fractionalBits)));
70 
71  // compute minimum and maximum value in raw representation
72  // NOLINTNEXTLINE(hicpp-signed-bitwise)
73  _maxRawValue = _usedBitsMask ^ _signBitMask; // bitwise xor: first bit is 0 if signed
74  // NOLINTNEXTLINE(hicpp-signed-bitwise)
75  _minRawValue = _signBitMask; // if only the sign bit is on, it is the smallest
76  // possible value
77  // (0 if unsigned)
78 
79  // fill all user type depending values: min and max cooked values and
80  // fractional bit coefficients note: we loop over one of the maps only, but
81  // initCoefficients() will fill all maps!
82  boost::fusion::for_each(_minCookedValues, initCoefficients(this));
83  }
84 
85  /********************************************************************************************************************/
86 
87  template<>
88  // sorry, linter. We can't change the signature here. This is a template specialisation for std::string.
89  // NOLINTNEXTLINE(performance-unnecessary-value-param)
90  uint32_t FixedPointConverter::toRaw<std::string>(std::string cookedValue) const {
91  if(_fractionalBits == 0) { // use integer conversion
92  if(_isSigned) {
93  return toRaw(std::stoi(cookedValue));
94  }
95  return toRaw(static_cast<uint32_t>(std::stoul(cookedValue))); // on some compilers, long might be a
96  // different type than int...
97  }
98  return toRaw(std::stod(cookedValue));
99  }
100 
101  template<>
102  uint32_t FixedPointConverter::toRaw<Boolean>(Boolean cookedValue) const {
103  if((bool)cookedValue) { // use integer conversion
104  return 1.0;
105  }
106  return 0.0;
107  }
108 
109  template<>
110  uint32_t FixedPointConverter::toRaw<Void>(__attribute__((unused)) Void cookedValue) const {
111  return 0.0;
112  }
113 
114 } // namespace ChimeraTK
ChimeraTK::Void
Wrapper Class for void.
Definition: SupportedUserTypes.h:71
FixedPointConverter.h
ChimeraTK::FixedPointConverter::reconfigure
void reconfigure(unsigned int nBits=32, int fractionalBits=0, bool isSignedFlag=true)
Reconfigure the fixed point converter with new type information.
Definition: FixedPointConverter.cc:23
ChimeraTK::FixedPointConverter::FixedPointConverter
FixedPointConverter(std::string variableName, unsigned int nBits=32, int fractionalBits=0, bool isSignedFlag=true)
The constructor defines the conversion factor.
Definition: FixedPointConverter.cc:14
ChimeraTK::for_each
void for_each(MAPTYPE &map, const LAMBDATYPE &lambda)
Variant of boost::fusion::for_each() to iterate a boost::fusion::map, which accepts a lambda instead ...
Definition: SupportedUserTypes.h:888
Exception.h
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::Boolean
Wrapper Class to avoid vector<bool> problems.
Definition: SupportedUserTypes.h:21
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51