fixed_point (deprecated)  rev.2
Binary Fixed-Point Arithmetic Library in C++
number_base.h
1 
2 // Copyright John McFarlane 2015 - 2017.
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 
7 #if !defined(SG14_number_base_H)
8 #define SG14_number_base_H 1
9 
10 #include <sg14/auxiliary/const_integer.h>
11 #include <sg14/bits/common.h>
12 #include <sg14/num_traits.h>
13 
14 #include <limits>
15 #include <type_traits>
16 
17 namespace sg14 {
18  namespace _impl {
19  template<class Derived, class Rep>
20  class number_base {
21  public:
22  using rep = Rep;
23  using _derived = Derived;
24 
25  number_base() = default;
26 
27  constexpr number_base(const rep& r)
28  : _rep(r) { }
29 
30  template<class T>
31  number_base& operator=(const T& r) {
32  _rep = r;
33  return static_cast<Derived&>(*this);
34  }
35 
36  explicit constexpr operator bool() const
37  {
38  return static_cast<bool>(_rep);
39  }
40 
41  constexpr const rep& data() const
42  {
43  return _rep;
44  }
45 
46 #if (__cplusplus >= 201402L)
47  constexpr rep& data()
48  {
49  return _rep;
50  }
51 #endif
52 
53  static constexpr Derived from_data(const rep& r)
54  {
55  return Derived(r);
56  }
57 
58  private:
59  rep _rep;
60  };
61 
63  // sg14::_impl::is_class_derived_from_number_base
64 
65  // true iff T's base class is sg14::_impl::number_base;
66  // T must be a class;
67  // used by sg14::_impl::is_derived_from_number_base
68  template<class Derived, class Enable = void>
69  struct is_class_derived_from_number_base : std::false_type {};
70 
71  template<class Derived>
72  struct is_class_derived_from_number_base<
73  Derived,
74  enable_if_t<std::is_base_of<number_base<Derived, typename Derived::rep>, Derived>::value>>
75  : std::true_type {};
76 
78  // sg14::_impl::is_derived_from_number_base
79 
80  // true if T is the Derived parameter of a number_base type
81  template<class T, class Enable = void>
82  struct is_derived_from_number_base : std::false_type {};
83 
84  template<class Derived>
85  struct is_derived_from_number_base<Derived, enable_if_t<std::is_class<Derived>::value>>
86  : is_class_derived_from_number_base<Derived> { };
87 
89  // sg14::_impl::enable_if_precedes
90 
91  template<class Former, class Latter>
92  struct precedes {
93  static constexpr bool value =
94  (std::is_floating_point<Former>::value && !std::is_floating_point<Latter>::value)
95  || (is_derived_from_number_base<Former>::value &&
96  !(is_derived_from_number_base<Latter>::value
97  || std::is_floating_point<Latter>::value));
98  };
99 
101  // sg14::_impl::operate
102 
103  // higher OP number_base<>
104  template<
105  class Operator, class Lhs, class RhsDerived, class RhsRep,
106  enable_if_t <precedes<Lhs, RhsDerived>::value, std::nullptr_t> = nullptr>
107  constexpr auto operate(const Lhs& lhs, const number_base<RhsDerived, RhsRep>& rhs, Operator op)
108  -> decltype(op(lhs, static_cast<Lhs>(static_cast<const RhsDerived&>(rhs))))
109  {
110  return op(lhs, static_cast<Lhs>(static_cast<const RhsDerived&>(rhs)));
111  }
112 
113  // number_base<> OP higher
114  template<
115  class Operator, class LhsDerived, class LhsRep, class Rhs,
116  enable_if_t <precedes<Rhs, LhsDerived>::value, std::nullptr_t> = nullptr>
117  constexpr auto operate(const number_base<LhsDerived, LhsRep>& lhs, const Rhs& rhs, Operator op)
118  -> decltype(op(static_cast<Rhs>(static_cast<const LhsDerived&>(lhs)), rhs))
119  {
120  return op(static_cast<Rhs>(static_cast<const LhsDerived&>(lhs)), rhs);
121  }
122 
123  // lower OP number_base<>
124  template<
125  class Operator, class Lhs, class RhsDerived, class RhsRep,
126  enable_if_t <precedes<RhsDerived, Lhs>::value, std::nullptr_t> = nullptr>
127  constexpr auto operate(const Lhs& lhs, const number_base<RhsDerived, RhsRep>& rhs, Operator op)
128  -> decltype(op(_impl::from_value<RhsDerived>(lhs), static_cast<const RhsDerived&>(rhs))) {
129  return op(from_value<RhsDerived>(lhs), static_cast<const RhsDerived&>(rhs));
130  }
131 
132  // number_base<> OP lower
133  template<
134  class Operator, class LhsDerived, class LhsRep, class Rhs,
135  enable_if_t <precedes<LhsDerived, Rhs>::value, std::nullptr_t> = nullptr>
136  constexpr auto operate(const number_base<LhsDerived, LhsRep>& lhs, const Rhs& rhs, Operator op)
137  -> decltype(op(static_cast<const LhsDerived &>(lhs), from_value<LhsDerived>(rhs)))
138  {
139  return op(static_cast<const LhsDerived &>(lhs), from_value<LhsDerived>(rhs));
140  }
141 
142  // unary operate
143  template<class Operator, class RhsDerived, class RhsRep>
144  constexpr auto operate(const number_base<RhsDerived, RhsRep>& rhs, Operator op)
145  -> decltype(op(rhs.data()))
146  {
147  return op(rhs.data());
148  }
149 
151  // sg14::_impl::number_base operators
152 
153  // compound assignment
154 
155  template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
156  auto operator+=(Lhs& lhs, const Rhs& rhs)
157  -> decltype(lhs = lhs + rhs)
158  {
159  return lhs = lhs + rhs;
160  }
161 
162  template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
163  auto operator-=(Lhs& lhs, const Rhs& rhs)
164  -> decltype(lhs = lhs - rhs)
165  {
166  return lhs = lhs - rhs;
167  }
168 
169  template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
170  auto operator*=(Lhs& lhs, const Rhs& rhs)
171  -> decltype(lhs = lhs * rhs)
172  {
173  return lhs = lhs * rhs;
174  }
175 
176  template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
177  auto operator/=(Lhs& lhs, const Rhs& rhs)
178  -> decltype(lhs = lhs / rhs)
179  {
180  return lhs = lhs / rhs;
181  }
182 
183  // unary operators
184 
185  template<class RhsDerived, class RhsRep>
186  constexpr auto operator+(const number_base<RhsDerived, RhsRep>& rhs)
187  -> decltype(operate(rhs, plus_tag))
188  {
189  return operate(rhs, plus_tag);
190  }
191 
192  template<class RhsDerived, class RhsRep>
193  constexpr auto operator-(const number_base<RhsDerived, RhsRep>& rhs)
194  -> decltype(operate(rhs, minus_tag))
195  {
196  return operate(rhs, minus_tag);
197  }
198 
199  // binary arithmetic operators
200 
201  template<class Lhs, class Rhs>
202  constexpr auto operator+(const Lhs& lhs, const Rhs& rhs)
203  -> decltype(operate(lhs, rhs, add_tag))
204  {
205  return operate(lhs, rhs, add_tag);
206  }
207 
208  template<class Lhs, class Rhs>
209  constexpr auto operator-(const Lhs& lhs, const Rhs& rhs)
210  -> decltype(operate(lhs, rhs, subtract_tag))
211  {
212  return operate(lhs, rhs, subtract_tag);
213  }
214 
215  template<class Lhs, class Rhs>
216  constexpr auto operator*(const Lhs& lhs, const Rhs& rhs)
217  -> decltype(operate(lhs, rhs, multiply_tag))
218  {
219  return operate(lhs, rhs, multiply_tag);
220  }
221 
222  template<class Lhs, class Rhs>
223  constexpr auto operator/(const Lhs& lhs, const Rhs& rhs)
224  -> decltype(operate(lhs, rhs, divide_tag))
225  {
226  return operate(lhs, rhs, divide_tag);
227  }
228 
229  // binary bitwise logic operators
230 
231  template<class Lhs, class Rhs>
232  constexpr auto operator|(const Lhs& lhs, const Rhs& rhs)
233  -> decltype(operate(lhs, rhs, bitwise_or_tag))
234  {
235  return operate(lhs, rhs, bitwise_or_tag);
236  }
237 
238  template<class Lhs, class Rhs>
239  constexpr auto operator&(const Lhs& lhs, const Rhs& rhs)
240  -> decltype(operate(lhs, rhs, bitwise_and_tag))
241  {
242  return operate(lhs, rhs, bitwise_and_tag);
243  }
244 
245  template<class Lhs, class Rhs>
246  constexpr auto operator^(const Lhs& lhs, const Rhs& rhs)
247  -> decltype(operate(lhs, rhs, bitwise_xor_tag))
248  {
249  return operate(lhs, rhs, bitwise_xor_tag);
250  }
251 
252  // comparison operator
253 
254  template<class Lhs, class Rhs>
255  constexpr auto operator==(const Lhs& lhs, const Rhs& rhs)
256  -> decltype(operate(lhs, rhs, equal_tag))
257  {
258  return operate(lhs, rhs, equal_tag);
259  }
260 
261  template<class Lhs, class Rhs>
262  constexpr auto operator!=(const Lhs& lhs, const Rhs& rhs)
263  -> decltype(operate(lhs, rhs, not_equal_tag))
264  {
265  return operate(lhs, rhs, not_equal_tag);
266  }
267 
268  template<class Lhs, class Rhs>
269  constexpr auto operator<(const Lhs& lhs, const Rhs& rhs)
270  -> decltype(operate(lhs, rhs, less_than_tag))
271  {
272  return operate(lhs, rhs, less_than_tag);
273  }
274 
275  template<class Lhs, class Rhs>
276  constexpr auto operator>(const Lhs& lhs, const Rhs& rhs)
277  -> decltype(operate(lhs, rhs, greater_than_tag))
278  {
279  return operate(lhs, rhs, greater_than_tag);
280  }
281 
282  template<class Lhs, class Rhs>
283  constexpr auto operator<=(const Lhs& lhs, const Rhs& rhs)
284  -> decltype(operate(lhs, rhs, less_than_or_equal_tag))
285  {
286  return operate(lhs, rhs, less_than_or_equal_tag);
287  }
288 
289  template<class Lhs, class Rhs>
290  constexpr auto operator>=(const Lhs& lhs, const Rhs& rhs)
291  -> decltype(operate(lhs, rhs, greater_than_or_equal_tag))
292  {
293  return operate(lhs, rhs, greater_than_or_equal_tag);
294  }
295  }
296 
298  // _impl::number_base<> numeric traits
299 
300  template<class Number>
301  struct is_composite<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> : std::true_type {
302  };
303 
304  namespace _impl {
305  template<class Number>
306  struct get_rep;
307 
308  template<class Number>
309  using get_rep_t = typename get_rep<Number>::type;
310 
311  // given a Number type and an alternative Rep type, make a new Number type
312  // e.g. set_rep_t<fixed_point<int64_t, 42>, uint8_t> --> fixed_point<uint8_t, 42>
313  template<class Number, class NewRep, class Enable = void>
314  struct set_rep;
315 
316  template<class Number, class NewRep>
317  using set_rep_t = typename set_rep<Number, NewRep>::type;
318  }
319 
320  template<class Number>
321  struct make_signed<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
322  using type = _impl::set_rep_t<Number, make_signed_t<_impl::get_rep_t<Number>>>;
323  };
324 
325  template<class Number>
326  struct make_unsigned<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
327  using type = _impl::set_rep_t<Number, make_unsigned_t<_impl::get_rep_t<Number>>>;
328  };
329 
330  template<class Number>
331  struct from_rep<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
332  template<class Rep>
333  constexpr auto operator()(const Rep &rep) const -> Number {
334  return Number::from_data(static_cast<typename Number::rep>(rep));
335  }
336  };
337 
338  template<class Number>
339  struct to_rep<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
340  constexpr auto operator()(const typename Number::_derived& number) const
341  -> decltype(number.data()){
342  return number.data();
343  }
344  };
345 
346  template<class Derived, class Rep>
347  struct scale<_impl::number_base<Derived, Rep>> {
348  template<class Input>
349  constexpr Rep operator()(const Input &i, int base, int exp) const {
350  return (exp < 0)
351  ? _impl::to_rep(i) / _num_traits_impl::pow<Rep>(base, -exp)
352  : _impl::to_rep(i) * _num_traits_impl::pow<Rep>(base, exp);
353  }
354  };
355 }
356 
357 namespace std {
359  // std::numeric_limits for sg14::_impl::numeric_limits
360 
361  template<class Derived, class Rep>
362  struct numeric_limits<sg14::_impl::number_base<Derived, Rep>>
363  : numeric_limits<Rep> {
364  // fixed-point-specific helpers
365  using _value_type = Derived;
366  using _rep = typename _value_type::rep;
367  using _rep_numeric_limits = numeric_limits<_rep>;
368 
369  // standard members
370 
371  static constexpr _value_type min() noexcept
372  {
373  return _value_type::from_data(_rep_numeric_limits::min());
374  }
375 
376  static constexpr _value_type max() noexcept
377  {
378  return _value_type::from_data(_rep_numeric_limits::max());
379  }
380 
381  static constexpr _value_type lowest() noexcept
382  {
383  return _value_type::from_data(_rep_numeric_limits::lowest());
384  }
385 
386  static constexpr _value_type epsilon() noexcept
387  {
388  return _value_type::from_data(_rep_numeric_limits::round_error());
389  }
390 
391  static constexpr _value_type round_error() noexcept
392  {
393  return static_cast<_value_type>(_rep_numeric_limits::round_error());
394  }
395 
396  static constexpr _value_type infinity() noexcept
397  {
398  return static_cast<_value_type>(_rep_numeric_limits::infinity());
399  }
400 
401  static constexpr _value_type quiet_NaN() noexcept
402  {
403  return static_cast<_value_type>(_rep_numeric_limits::quiet_NaN());
404  }
405 
406  static constexpr _value_type signaling_NaN() noexcept
407  {
408  return static_cast<_value_type>(_rep_numeric_limits::signaling_NaN());
409  }
410 
411  static constexpr _value_type denorm_min() noexcept
412  {
413  return static_cast<_value_type>(_rep_numeric_limits::denorm_min());
414  }
415  };
416 }
417 
418 #endif // SG14_NUMBER_BASE_H
STL namespace.
study group 14 of the C++ working group
Definition: const_integer.h:22