fixed_point (deprecated)  rev.2
Binary Fixed-Point Arithmetic Library in C++
fixed_point_type.h
1 
2 // Copyright John McFarlane 2015 - 2016.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file ../LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
9 
10 #if !defined(SG14_FIXED_POINT_DEF_H)
11 #define SG14_FIXED_POINT_DEF_H 1
12 
13 #include <sg14/auxiliary/const_integer.h>
14 #include <sg14/bits/number_base.h>
15 
17 namespace sg14 {
18  // forward declaration
19  template<class Rep = int, int Exponent = 0>
20  class fixed_point;
21 
23  // implementation-specific definitions
24 
25  namespace _impl {
26  namespace fp {
28  // sg14::_impl::float_of_size
29 
30  template<int NumBits, class Enable = void>
31  struct float_of_size;
32 
33  template<int NumBits>
34  struct float_of_size<NumBits, enable_if_t<NumBits <= sizeof(float)*CHAR_BIT>> {
35  using type = float;
36  };
37 
38  template<int NumBits>
39  struct float_of_size<NumBits, enable_if_t<sizeof(float)*CHAR_BIT < NumBits && NumBits <= sizeof(double)*CHAR_BIT>> {
40  using type = double;
41  };
42 
43  template<int NumBits>
44  struct float_of_size<NumBits, enable_if_t<sizeof(double)*CHAR_BIT < NumBits && NumBits <= sizeof(long double)*CHAR_BIT>> {
45  using type = long double;
46  };
47 
49  // sg14::_impl::float_of_same_size
50 
51  template<class T>
52  using float_of_same_size = typename float_of_size<digits<T>::value + is_signed<T>::value>::type;
53  }
54  }
55 
66 
67  template<class Rep, int Exponent>
68  class fixed_point
69  : public _impl::number_base<fixed_point<Rep, Exponent>, Rep> {
70  using _base = _impl::number_base<fixed_point<Rep, Exponent>, Rep>;
71  public:
73  // types
74 
76  using rep = Rep;
77 
79  // constants
80 
82  constexpr static int exponent = Exponent;
83 
86  constexpr static int digits = std::numeric_limits<Rep>::digits;
87 
90  constexpr static int integer_digits = digits+exponent;
91 
94  constexpr static int fractional_digits = -exponent;
95 
97  // functions
98 
99  private:
100  // constructor taking representation explicitly using operator++(int)-style trick
101  constexpr fixed_point(rep r, int)
102  :_base(r)
103  {
104  }
105 
106  public:
108  constexpr fixed_point() : _base() { }
109 
111  template<class FromRep, int FromExponent>
113  : _base(fixed_point_to_rep(rhs))
114  {
115  }
116 
118  template<class Integral, Integral Constant>
119  constexpr fixed_point(const std::integral_constant<Integral, Constant>&)
120  : fixed_point(fixed_point<Integral, 0>::from_data(Constant))
121  {
122  }
123 
125  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_integer, int> Dummy = 0>
126  constexpr fixed_point(const S& s)
127  : fixed_point(fixed_point<S, 0>::from_data(s))
128  {
129  }
130 
132  template<class Integral, Integral Value, int Digits>
134  : _base(ci << Exponent)
135  {
136  }
137 
139  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_iec559, int> Dummy = 0>
140  constexpr fixed_point(S s)
141  :_base(floating_point_to_rep(s))
142  {
143  }
144 
146  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_integer, int> Dummy = 0>
148  {
149  return operator=(fixed_point<S, 0>::from_data(s));
150  }
151 
153  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_iec559, int> Dummy = 0>
155  {
156  _base::operator=(floating_point_to_rep(s));
157  return *this;
158  }
159 
161  template<class FromRep, int FromExponent>
163  {
164  _base::operator=(fixed_point_to_rep(rhs));
165  return *this;
166  }
167 
169  template<typename R = Rep>
170  constexpr operator typename std::enable_if<std::is_convertible<Rep, bool>::value, bool>() const
171  {
172  return static_cast<bool>(_base::data());
173  }
174 
176  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_integer, int> Dummy = 0>
177  constexpr operator S() const
178  {
179  return rep_to_integral<S>(_base::data());
180  }
181 
183  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_iec559, int> Dummy = 0>
184  explicit constexpr operator S() const
185  {
186  return rep_to_floating_point<S>(_base::data());
187  }
188 
190  static constexpr fixed_point from_data(rep const & r)
191  {
192  return fixed_point(r, 0);
193  }
194 
195  private:
196  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_iec559, int> Dummy = 0>
197  static constexpr S one();
198 
199  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_integer, int> Dummy = 0>
200  static constexpr S one();
201 
202  template<class S>
203  static constexpr S inverse_one();
204 
205  template<class S>
206  static constexpr S rep_to_integral(rep r);
207 
208  template<class S>
209  static constexpr rep floating_point_to_rep(S s);
210 
211  template<class S>
212  static constexpr S rep_to_floating_point(rep r);
213 
214  template<class FromRep, int FromExponent>
215  static constexpr rep fixed_point_to_rep(const fixed_point<FromRep, FromExponent>& rhs);
216  };
217 
219  template<class Rep, int Exponent>
221 
224  template<class Rep, int Exponent>
226 
229  template<class Rep, int Exponent>
231 
234  template<class Rep, int Exponent>
236 
238  // general-purpose implementation-specific definitions
239 
240  namespace _impl {
241 
243  // sg14::_impl::is_fixed_point
244 
245  template<class T>
246  struct is_fixed_point
247  : public std::false_type {
248  };
249 
250  template<class Rep, int Exponent>
251  struct is_fixed_point<fixed_point<Rep, Exponent>>
252  : public std::true_type {
253  };
254 
256  // sg14::_impl::shift_left
257 
258  // performs a shift operation by a fixed number of bits avoiding two pitfalls:
259  // 1) shifting by a negative amount causes undefined behavior
260  // 2) converting between integer types of different sizes can lose significant bits during shift right
261 
262  // Exponent == 0
263  template<int exp, class Output, class Input>
264  constexpr Output shift_left(Input i)
265  {
266  using larger = typename std::conditional<
267  digits<Input>::value<=digits<Output>::value,
268  Output, Input>::type;
269 
270  return (exp>-std::numeric_limits<larger>::digits)
271  ? static_cast<Output>(_impl::scale<larger>(static_cast<larger>(i), 2, exp))
272  : Output{0};
273  }
274 
276  // file-local implementation-specific definitions
277 
278  namespace fp {
279  namespace type {
281  // sg14::_impl::fp::type::pow2
282 
283  // returns given power of 2
284  template<class S, int Exponent, enable_if_t<Exponent==0, int> Dummy = 0>
285  constexpr S pow2()
286  {
287  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
288  return S{1.};
289  }
290 
291  template<class S, int Exponent,
292  enable_if_t<!(Exponent<=0) && (Exponent<8), int> Dummy = 0>
293  constexpr S pow2()
294  {
295  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
296  return pow2<S, Exponent-1>()*S(2);
297  }
298 
299  template<class S, int Exponent, enable_if_t<(Exponent>=8), int> Dummy = 0>
300  constexpr S pow2()
301  {
302  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
303  return pow2<S, Exponent-8>()*S(256);
304  }
305 
306  template<class S, int Exponent,
307  enable_if_t<!(Exponent>=0) && (Exponent>-8), int> Dummy = 0>
308  constexpr S pow2()
309  {
310  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
311  return pow2<S, Exponent+1>()*S(.5);
312  }
313 
314  template<class S, int Exponent, enable_if_t<(Exponent<=-8), int> Dummy = 0>
315  constexpr S pow2()
316  {
317  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
318  return pow2<S, Exponent+8>()*S(.003906250);
319  }
320  }
321  }
322  }
323 
325  // sg14::fixed_point<> member definitions
326 
327  template<class Rep, int Exponent>
328  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_iec559, int> Dummy>
329  constexpr S fixed_point<Rep, Exponent>::one()
330  {
331  return _impl::fp::type::pow2<S, -exponent>();
332  }
333 
334  template<class Rep, int Exponent>
335  template<class S, _impl::enable_if_t<std::numeric_limits<S>::is_integer, int> Dummy>
336  constexpr S fixed_point<Rep, Exponent>::one()
337  {
339  }
340 
341  template<class Rep, int Exponent>
342  template<class S>
344  {
345  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
346  return _impl::fp::type::pow2<S, exponent>();
347  }
348 
349  template<class Rep, int Exponent>
350  template<class S>
352  {
353  static_assert(std::numeric_limits<S>::is_integer, "S must be integral type");
354 
355  return _impl::shift_left<exponent, S>(r);
356  }
357 
358  template<class Rep, int Exponent>
359  template<class S>
361  {
362  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
363  return static_cast<rep>(s*one<S>());
364  }
365 
366  template<class Rep, int Exponent>
367  template<class S>
369  {
370  static_assert(std::numeric_limits<S>::is_iec559, "S must be floating-point type");
371  return S(r)*inverse_one<S>();
372  }
373 
374  template<class Rep, int Exponent>
375  template<class FromRep, int FromExponent>
377  {
378  return _impl::shift_left<FromExponent-exponent, rep>(rhs.data());
379  }
380 }
381 
382 #endif // SG14_FIXED_POINT_DEF_H
constexpr fixed_point(const_integer< Integral, Value, Digits, Exponent > ci)
constructor taking an integral_constant type
Definition: fixed_point_type.h:133
constexpr fixed_point(S s)
constructor taking a floating-point type
Definition: fixed_point_type.h:140
fixed_point & operator=(const fixed_point< FromRep, FromExponent > &rhs)
copy assignement operator taking a fixed-point type
Definition: fixed_point_type.h:162
static constexpr fixed_point from_data(rep const &r)
creates an instance given the underlying representation value
Definition: fixed_point_type.h:190
constexpr fixed_point()
default constructor
Definition: fixed_point_type.h:108
constexpr fixed_point(const S &s)
constructor taking an integer type
Definition: fixed_point_type.h:126
constexpr fixed_point(const fixed_point< FromRep, FromExponent > &rhs)
constructor taking a fixed-point type
Definition: fixed_point_type.h:112
a compile-time-only integer type like a std::integral_constant with arithmetic support ...
Definition: const_integer.h:98
fixed_point & operator=(S s)
copy assignment operator taking an integer type
Definition: fixed_point_type.h:147
Rep rep
alias to template parameter, Rep
Definition: fixed_point_type.h:76
literal real number approximation that uses fixed-point arithmetic
Definition: fixed_point_type.h:20
constexpr fixed_point(const std::integral_constant< Integral, Constant > &)
constructor taking an integral_constant type
Definition: fixed_point_type.h:119
study group 14 of the C++ working group
Definition: const_integer.h:22