fixed_point (deprecated)  rev.2
Binary Fixed-Point Arithmetic Library in C++
fixed_point_operators.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_OPERATORS_H)
11 #define SG14_FIXED_POINT_OPERATORS_H 1
12 
13 #include "fixed_point_arithmetic.h"
14 
16 namespace sg14 {
17 
19  // (fixed_point @ fixed_point) arithmetic operators
20 
21  // negate
22  template<class RhsRep, int RhsExponent>
23  constexpr auto operator-(const fixed_point<RhsRep, RhsExponent>& rhs)
24  -> fixed_point<decltype(-rhs.data()), RhsExponent>
25  {
26  using result_type = fixed_point<decltype(-rhs.data()), RhsExponent>;
27  return result_type::from_data(-rhs.data());
28  }
29 
30  // add
31  template<
32  class LhsRep, int LhsExponent,
33  class RhsRep, int RhsExponent>
34  constexpr auto operator+(
35  const fixed_point<LhsRep, LhsExponent>& lhs,
36  const fixed_point<RhsRep, RhsExponent>& rhs)
37  -> decltype(_impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::add_tag))
38  {
39  return _impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::add_tag);
40  }
41 
42  // subtract
43  template<
44  class LhsRep, int LhsExponent,
45  class RhsRep, int RhsExponent>
46  constexpr auto operator-(
47  const fixed_point<LhsRep, LhsExponent>& lhs,
48  const fixed_point<RhsRep, RhsExponent>& rhs)
49  -> decltype(_impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::subtract_tag))
50  {
51  return _impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::subtract_tag);
52  }
53 
54  // multiply
55  template<
56  class LhsRep, int LhsExponent,
57  class RhsRep, int RhsExponent>
58  constexpr auto operator*(
59  const fixed_point<LhsRep, LhsExponent>& lhs,
60  const fixed_point<RhsRep, RhsExponent>& rhs)
61  -> decltype(_impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::multiply_tag))
62  {
63  return _impl::fp::operate<_impl::fp::arithmetic_operator_tag>(lhs, rhs, _impl::multiply_tag);
64  }
65 
66  // divide
67  template<class LhsRep, int LhsExponent, class RhsRep, int RhsExponent>
68  constexpr auto operator/(
69  const fixed_point<LhsRep, LhsExponent>& lhs,
70  const fixed_point<RhsRep, RhsExponent>& rhs)
71  -> decltype(_impl::fp::operate<_impl::fp::division_arithmetic_operator_tag>(lhs, rhs, _impl::divide_tag))
72  {
73  return _impl::fp::operate<_impl::fp::division_arithmetic_operator_tag>(lhs, rhs, _impl::divide_tag);
74  }
75 
77  // heterogeneous operator overloads
78  //
79  // compare two objects of different fixed_point specializations
80 
81  namespace _fixed_point_operators_impl {
82  template<class Lhs, class Rhs>
83  constexpr bool is_heterogeneous() {
84  return (!std::is_same<Lhs, Rhs>::value) &&
85  (_impl::is_fixed_point<Lhs>::value || _impl::is_fixed_point<Rhs>::value);
86  }
87  }
88 
89  namespace _impl {
90  template<
91  class Operator, class Lhs, class Rhs,
92  class = _impl::enable_if_t<Operator::is_comparison && sg14::_fixed_point_operators_impl::is_heterogeneous<Lhs, Rhs>()>>
93  constexpr auto operate(const Lhs& lhs, const Rhs& rhs, Operator op)
94  -> decltype(op(static_cast<_impl::common_type_t<Lhs, Rhs>>(lhs), static_cast<_impl::common_type_t<Lhs, Rhs>>(rhs)))
95  {
96  return op(static_cast<_impl::common_type_t<Lhs, Rhs>>(lhs), static_cast<_impl::common_type_t<Lhs, Rhs>>(rhs));
97  };
98 
99  template<class Operator, class Rep, int Exponent, class = _impl::enable_if_t<Operator::is_comparison>>
100  constexpr auto operate(const fixed_point<Rep, Exponent>& lhs, const fixed_point<Rep, Exponent>& rhs, Operator op)
101  -> decltype(op(lhs.data(), rhs.data()))
102  {
103  return op(lhs.data(), rhs.data());
104  };
105  }
106 
108  // (fixed_point @ non-fixed_point) arithmetic operators
109 
110  // fixed-point, integer -> fixed-point
111  template<
112  class LhsRep, int LhsExponent,
113  class RhsInteger,
114  typename = _impl::enable_if_t<std::numeric_limits<RhsInteger>::is_integer>>
115  constexpr auto operator+(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsInteger& rhs)
116  -> decltype(lhs + fixed_point<RhsInteger, 0>{rhs})
117  {
118  return lhs + fixed_point<RhsInteger, 0>{rhs};
119  }
120 
121  template<
122  class LhsRep, int LhsExponent,
123  class RhsInteger,
124  typename = _impl::enable_if_t<std::numeric_limits<RhsInteger>::is_integer>>
125  constexpr auto operator-(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsInteger& rhs)
126  -> decltype(lhs - fixed_point<RhsInteger, 0>{rhs})
127  {
128  return lhs - fixed_point<RhsInteger, 0>{rhs};
129  }
130 
131  template<
132  class LhsRep, int LhsExponent,
133  class RhsInteger,
134  typename = _impl::enable_if_t<std::numeric_limits<RhsInteger>::is_integer>>
135  constexpr auto operator*(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsInteger& rhs)
136  -> decltype(lhs*fixed_point<RhsInteger>(rhs))
137  {
138  return lhs*fixed_point<RhsInteger>(rhs);
139  }
140 
141  template<
142  class LhsRep, int LhsExponent,
143  class RhsInteger,
144  typename = _impl::enable_if_t<std::numeric_limits<RhsInteger>::is_integer>>
145  constexpr auto operator/(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsInteger& rhs)
146  -> decltype(lhs/fixed_point<RhsInteger>{rhs})
147  {
148  return lhs/fixed_point<RhsInteger>{rhs};
149  }
150 
151  // integer. fixed-point -> fixed-point
152  template<
153  class LhsInteger,
154  class RhsRep, int RhsExponent,
155  typename = _impl::enable_if_t<std::numeric_limits<LhsInteger>::is_integer>>
156  constexpr auto operator+(const LhsInteger& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)
157  -> decltype(fixed_point<LhsInteger, 0>{lhs} + rhs)
158  {
159  return fixed_point<LhsInteger, 0>{lhs} + rhs;
160  }
161 
162  template<
163  class LhsInteger,
164  class RhsRep, int RhsExponent,
165  typename = _impl::enable_if_t<std::numeric_limits<LhsInteger>::is_integer>>
166  constexpr auto operator-(const LhsInteger& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)
167  -> decltype(fixed_point<LhsInteger>{lhs}-rhs)
168  {
169  return fixed_point<LhsInteger>{lhs}-rhs;
170  }
171 
172  template<
173  class LhsInteger,
174  class RhsRep, int RhsExponent,
175  typename = _impl::enable_if_t<std::numeric_limits<LhsInteger>::is_integer>>
176  constexpr auto operator*(const LhsInteger& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)
177  -> decltype(fixed_point<LhsInteger>{lhs}*rhs)
178  {
179  return fixed_point<LhsInteger>{lhs}*rhs;
180  }
181 
182  template<
183  class LhsInteger,
184  class RhsRep, int RhsExponent,
185  typename = _impl::enable_if_t<std::numeric_limits<LhsInteger>::is_integer>>
186  constexpr auto operator/(const LhsInteger& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)
187  -> decltype(fixed_point<LhsInteger>{lhs}/rhs)
188  {
189  return fixed_point<LhsInteger>{lhs}/rhs;
190  }
191 
192  // fixed-point, floating-point -> floating-point
193  template<class LhsRep, int LhsExponent, class RhsFloat, typename = _impl::enable_if_t<std::is_floating_point<RhsFloat>::value>>
194  constexpr auto operator+(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsFloat& rhs)-> _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>
195  {
196  using result_type = _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>;
197  return static_cast<result_type>(lhs)+static_cast<result_type>(rhs);
198  }
199 
200  template<class LhsRep, int LhsExponent, class RhsFloat, typename = _impl::enable_if_t <std::is_floating_point<RhsFloat>::value>>
201  constexpr auto operator-(const fixed_point<LhsRep, LhsExponent>& lhs, const RhsFloat& rhs)-> _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>
202  {
203  using result_type = _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>;
204  return static_cast<result_type>(lhs)-static_cast<result_type>(rhs);
205  }
206 
207  template<class LhsRep, int LhsExponent, class RhsFloat>
208  constexpr auto operator*(
209  const fixed_point<LhsRep, LhsExponent>& lhs,
210  const RhsFloat& rhs)
211  -> _impl::common_type_t<
212  fixed_point<LhsRep, LhsExponent>,
213  _impl::enable_if_t<std::is_floating_point<RhsFloat>::value, RhsFloat>>
214  {
215  using result_type = _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>;
216  return static_cast<result_type>(lhs)*rhs;
217  }
218 
219  template<class LhsRep, int LhsExponent, class RhsFloat>
220  constexpr auto operator/(
221  const fixed_point<LhsRep, LhsExponent>& lhs,
222  const RhsFloat& rhs)
223  -> _impl::common_type_t<
224  fixed_point<LhsRep, LhsExponent>,
225  _impl::enable_if_t<std::is_floating_point<RhsFloat>::value, RhsFloat>>
226  {
227  using result_type = _impl::common_type_t<fixed_point<LhsRep, LhsExponent>, RhsFloat>;
228  return static_cast<result_type>(lhs)/rhs;
229  }
230 
231  // floating-point, fixed-point -> floating-point
232  template<class LhsFloat, class RhsRep, int RhsExponent, typename = _impl::enable_if_t <std::is_floating_point<LhsFloat>::value>>
233  constexpr auto operator+(const LhsFloat& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)-> _impl::common_type_t<LhsFloat, fixed_point<RhsRep, RhsExponent>>
234  {
235  using result_type = _impl::common_type_t<LhsFloat, fixed_point<RhsRep, RhsExponent>>;
236  return static_cast<result_type>(lhs)+static_cast<result_type>(rhs);
237  }
238 
239  template<class LhsFloat, class RhsRep, int RhsExponent, typename = _impl::enable_if_t <std::is_floating_point<LhsFloat>::value>>
240  constexpr auto operator-(const LhsFloat& lhs, const fixed_point<RhsRep, RhsExponent>& rhs)-> _impl::common_type_t<LhsFloat, fixed_point<RhsRep, RhsExponent>>
241  {
242  using result_type = _impl::common_type_t<LhsFloat, fixed_point<RhsRep, RhsExponent>>;
243  return static_cast<result_type>(lhs)-static_cast<result_type>(rhs);
244  }
245 
246  template<class LhsFloat, class RhsRep, int RhsExponent>
247  constexpr auto operator*(
248  const LhsFloat& lhs,
249  const fixed_point<RhsRep, RhsExponent>& rhs)
250  -> _impl::common_type_t <_impl::enable_if_t<std::is_floating_point<LhsFloat>::value, LhsFloat>, fixed_point<RhsRep, RhsExponent>>
251  {
252  using result_type = _impl::common_type_t<fixed_point<RhsRep, RhsExponent>, LhsFloat>;
253  return lhs*static_cast<result_type>(rhs);
254  }
255 
256  template<class LhsFloat, class RhsRep, int RhsExponent>
257  constexpr auto operator/(
258  const LhsFloat& lhs,
259  const fixed_point<RhsRep, RhsExponent>& rhs)
260  -> _impl::common_type_t <_impl::enable_if_t<std::is_floating_point<LhsFloat>::value, LhsFloat>, fixed_point<RhsRep, RhsExponent>>
261  {
262  using result_type = _impl::common_type_t<fixed_point<RhsRep, RhsExponent>, LhsFloat>;
263  return lhs/
264  static_cast<result_type>(rhs);
265  }
266 
268  // shift operators
269 
270  // fixed_point, dynamic
271  template<class LhsRep, int LhsExponent, class Rhs>
272  constexpr auto operator<<(const fixed_point<LhsRep, LhsExponent>& lhs, const Rhs& rhs)
273  -> decltype(_impl::from_rep<fixed_point<decltype(lhs.data() << rhs), LhsExponent>>(lhs.data() << rhs))
274  {
275  return _impl::from_rep<fixed_point<decltype(lhs.data() << rhs), LhsExponent>>(lhs.data() << rhs);
276  }
277 
278  template<class LhsRep, int LhsExponent, class Rhs>
279  constexpr auto operator>>(const fixed_point<LhsRep, LhsExponent>& lhs, const Rhs& rhs)
280  -> decltype(_impl::from_rep<fixed_point<decltype(lhs.data() >> rhs), LhsExponent>>(lhs.data() >> rhs))
281  {
282  return _impl::from_rep<fixed_point<decltype(lhs.data() >> rhs), LhsExponent>>(lhs.data() >> rhs);
283  }
284 
285  // fixed_point, const_integer
286  template<class LhsRep, int LhsExponent, class RhsIntegral, RhsIntegral RhsValue>
287  constexpr fixed_point<LhsRep, LhsExponent+RhsValue>
288  operator<<(const fixed_point<LhsRep, LhsExponent>& lhs, const_integer<RhsIntegral, RhsValue>)
289  {
291  }
292 
293  template<class LhsRep, int LhsExponent, class RhsIntegral, RhsIntegral RhsValue>
294  constexpr fixed_point<LhsRep, LhsExponent-RhsValue>
295  operator>>(const fixed_point<LhsRep, LhsExponent>& lhs, const_integer<RhsIntegral, RhsValue>)
296  {
298  }
299 
300  // fixed_point, const_integer
301  template<class LhsRep, int LhsExponent, class RhsIntegral, RhsIntegral RhsValue>
302  constexpr fixed_point<LhsRep, LhsExponent+RhsValue>
303  operator<<(const fixed_point<LhsRep, LhsExponent>& lhs, std::integral_constant<RhsIntegral, RhsValue>)
304  {
306  }
307 
308  template<class LhsRep, int LhsExponent, class RhsIntegral, RhsIntegral RhsValue>
309  constexpr fixed_point<LhsRep, LhsExponent-RhsValue>
310  operator>>(const fixed_point<LhsRep, LhsExponent>& lhs, std::integral_constant<RhsIntegral, RhsValue>)
311  {
313  }
314 }
315 
316 #endif // SG14_FIXED_POINT_OPERATORS_H
static constexpr fixed_point from_data(rep const &r)
creates an instance given the underlying representation value
Definition: fixed_point_type.h:190
study group 14 of the C++ working group
Definition: const_integer.h:22