CNL  2.0.2 (development)
Compositional Numeric Library
convert_operator.h
1 
2 // Copyright John McFarlane 2018.
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(CNL_IMPL_SCALED_INTEGER_TAGGED_CONVERT_OPERATOR_H)
8 #define CNL_IMPL_SCALED_INTEGER_TAGGED_CONVERT_OPERATOR_H
9 
10 #include "../../integer.h"
11 #include "../overflow/overflow_operator.h"
12 #include "../power_value.h"
13 #include "../rounding/native_rounding_tag.h"
14 #include "../rounding/nearest_rounding_tag.h"
15 #include "../rounding/neg_inf_rounding_tag.h"
16 #include "../rounding/tie_to_pos_inf_rounding_tag.h"
17 #include "../scaled/is_scaled_tag.h"
18 #include "definition.h"
19 #include "from_rep.h"
20 
21 #include <concepts>
22 
24 namespace cnl {
27 
28  template<typename Input, typename Result, int Radix>
30  _impl::convert_op,
31  op_value<Input, nearest_rounding_tag>,
32  op_value<Result, power<0, Radix>>>
34  _impl::convert_op,
35  op_value<Input, power<0, Radix>>,
36  op_value<Result, nearest_rounding_tag>> {
37  };
38 
40  // conversion between two scaled_integer types where rounding *is* an issue
41  template<
42  typename InputRep, int InputExponent,
43  typename ResultRep, int ResultExponent,
44  int Radix>
45  requires(!(ResultExponent <= InputExponent)) struct custom_operator<
46  _impl::convert_op,
47  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, power<0, Radix>>,
48  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, nearest_rounding_tag>> {
49  private:
52 
53  [[nodiscard]] static constexpr auto half()
54  {
55  return static_cast<input>(_impl::from_rep<result>(1)) / 2;
56  }
57 
58  public:
59  [[nodiscard]] constexpr auto operator()(input const& from) const
60  {
61  // TODO: unsigned specialization
62  return static_cast<result>(from + ((from >= 0) ? half() : -half()));
63  }
64  };
65 
66  // conversion between two scaled_integer types where rounding *isn't* an issue
67  template<
68  typename InputRep, int InputExponent,
69  typename ResultRep, int ResultExponent,
70  int Radix>
71  requires(ResultExponent <= InputExponent) struct custom_operator<
72  _impl::convert_op,
73  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, power<0, Radix>>,
74  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, nearest_rounding_tag>> {
75  };
77 
78  // conversion from float to scaled_integer
79  template<std::floating_point Input, typename ResultRep, int ResultExponent, int ResultRadix>
80  struct custom_operator<
81  _impl::convert_op,
82  op_value<Input, power<0, ResultRadix>>,
83  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, nearest_rounding_tag>> {
84  private:
85  using result = scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>;
86 
87  [[nodiscard]] static constexpr auto half()
88  {
89  return _impl::power_value<Input, ResultExponent - 1, ResultRadix>();
90  }
91 
92  public:
93  [[nodiscard]] constexpr auto operator()(Input const& from) const
94  {
95  // TODO: unsigned specialization
96  return static_cast<result>(from + ((from >= 0) ? half() : -half()));
97  }
98  };
99 
100  template<integer Input, typename ResultRep, int ResultExponent, int ResultRadix>
101  struct custom_operator<
102  _impl::convert_op,
103  op_value<Input, power<0, ResultRadix>>,
104  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, nearest_rounding_tag>>
105  : custom_operator<
106  _impl::convert_op,
107  op_value<scaled_integer<Input>, power<0, ResultRadix>>,
108  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, nearest_rounding_tag>> {
109  };
110 
111  template<typename InputRep, int InputExponent, int InputRadix, integer Result>
112  struct custom_operator<
113  _impl::convert_op,
114  op_value<scaled_integer<InputRep, power<InputExponent, InputRadix>>, power<0, InputRadix>>,
115  op_value<Result, nearest_rounding_tag>> {
116  private:
117  using input = scaled_integer<InputRep, power<InputExponent, InputRadix>>;
118 
119  public:
120  [[nodiscard]] constexpr auto operator()(input const& from) const
121  {
122  return _impl::to_rep(custom_operator<
123  _impl::convert_op,
124  op_value<input, power<0, InputRadix>>,
125  op_value<scaled_integer<Result>, nearest_rounding_tag>>{}(from));
126  }
127  };
128 
129  template<typename Input, typename ResultRep, int ResultExponent, int ResultRadix>
130  struct custom_operator<
131  _impl::convert_op,
132  op_value<Input, _impl::native_tag>,
133  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, nearest_rounding_tag>> {
134 
135  [[nodiscard]] constexpr auto
136  operator()(Input const& from) const
137  {
138  return custom_operator<
139  _impl::convert_op,
140  op_value<Input, power<0, ResultRadix>>,
141  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, nearest_rounding_tag>>{}(from);
142  }
143  };
144 
147 
148  // conversion between two scaled_integer types where rounding *isn't* an issue
150  template<
151  typename InputRep, int InputExponent,
152  typename ResultRep, int ResultExponent,
153  int Radix>
154  requires(ResultExponent <= InputExponent) struct custom_operator<
155  _impl::convert_op,
156  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
157  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, tie_to_pos_inf_rounding_tag>>
158  : custom_operator<
159  _impl::convert_op,
160  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
161  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, native_rounding_tag>> {
162  };
163 
164  // conversion between two scaled_integer types where rounding *is* an issue
165  template<
166  typename InputRep, int InputExponent,
167  typename ResultRep, int ResultExponent,
168  int Radix>
169  requires(!(ResultExponent <= InputExponent)) struct custom_operator<
170  _impl::convert_op,
171  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
172  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, tie_to_pos_inf_rounding_tag>> {
173  private:
174  using result = scaled_integer<ResultRep, power<ResultExponent, Radix>>;
175  using input = scaled_integer<InputRep, power<InputExponent, Radix>>;
176 
177  [[nodiscard]] static constexpr auto half()
178  {
179  return static_cast<input>(_impl::from_rep<result>(1)) / 2;
180  }
181 
182  public:
183  [[nodiscard]] constexpr auto operator()(input const& from) const -> result
184  {
185  // TODO: unsigned specialization
186  return _impl::from_rep<result>(
187  _impl::to_rep(from + half()) >> (ResultExponent - InputExponent));
188  }
189  };
191 
192  // conversion from float to scaled_integer
193  template<
194  std::floating_point Input,
195  typename ResultRep, int ResultExponent, int ResultRadix>
197  _impl::convert_op,
198  op_value<Input, _impl::native_tag>,
199  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, tie_to_pos_inf_rounding_tag>> {
200  private:
202 
203  [[nodiscard]] static constexpr auto half()
204  {
205  return _impl::power_value<Input, ResultExponent - 1, ResultRadix>();
206  }
207 
208  public:
209  [[nodiscard]] constexpr auto operator()(Input const& from) const
210  {
211  // TODO: unsigned specialization
212  return static_cast<result>(from + half());
213  }
214  };
215 
216  template<integer Input, integer ResultRep, scaled_tag ResultScale>
217  struct custom_operator<
218  _impl::convert_op,
219  op_value<Input, _impl::native_tag>,
220  op_value<scaled_integer<ResultRep, ResultScale>, tie_to_pos_inf_rounding_tag>>
221  : custom_operator<
222  _impl::convert_op,
223  op_value<scaled_integer<Input>, _impl::native_tag>,
224  op_value<scaled_integer<ResultRep, ResultScale>, tie_to_pos_inf_rounding_tag>> {
225  };
226 
227  template<integer InputRep, scaled_tag InputScale, integer Result>
228  struct custom_operator<
229  _impl::convert_op,
230  op_value<scaled_integer<InputRep, InputScale>, _impl::native_tag>,
231  op_value<Result, tie_to_pos_inf_rounding_tag>> {
232  private:
233  using input = scaled_integer<InputRep, InputScale>;
234 
235  public:
236  [[nodiscard]] constexpr auto operator()(input const& from) const
237  {
238  return _impl::to_rep(custom_operator<
239  _impl::convert_op,
240  op_value<input, _impl::native_tag>,
241  op_value<scaled_integer<Result>, tie_to_pos_inf_rounding_tag>>{}(from));
242  }
243  };
244 
247 
248  // conversion between two scaled_integer types where rounding *isn't* an issue
250  template<
251  typename InputRep, int InputExponent,
252  typename ResultRep, int ResultExponent,
253  int Radix>
254  requires(ResultExponent <= InputExponent) struct custom_operator<
255  _impl::convert_op,
256  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
257  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, neg_inf_rounding_tag>>
258  : custom_operator<
259  _impl::convert_op,
260  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
261  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, native_rounding_tag>> {
262  };
263 
264  // conversion between two scaled_integer types where rounding *is* an issue
265  template<
266  typename InputRep, int InputExponent,
267  typename ResultRep, int ResultExponent,
268  int Radix>
269  requires(!(ResultExponent <= InputExponent)) struct custom_operator<
270  _impl::convert_op,
271  op_value<scaled_integer<InputRep, power<InputExponent, Radix>>, _impl::native_tag>,
272  op_value<scaled_integer<ResultRep, power<ResultExponent, Radix>>, neg_inf_rounding_tag>> {
273  private:
274  using result = scaled_integer<ResultRep, power<ResultExponent, Radix>>;
275  using input = scaled_integer<InputRep, power<InputExponent, Radix>>;
276 
277  public:
278  [[nodiscard]] constexpr auto operator()(input const& from) const
279  {
280  // TODO: unsigned specialization
281  return _impl::from_rep<result>(
282  _impl::to_rep(from) >> (ResultExponent - InputExponent));
283  }
284  };
286 
287  // conversion from float to scaled_integer
288  template<
289  std::floating_point Input,
290  typename ResultRep, int ResultExponent, int ResultRadix>
292  _impl::convert_op,
293  op_value<Input, _impl::native_tag>,
294  op_value<scaled_integer<ResultRep, power<ResultExponent, ResultRadix>>, neg_inf_rounding_tag>> {
295  private:
297 
298  public:
299  [[nodiscard]] constexpr auto operator()(Input const& from) const
300  {
301  // TODO: unsigned specialization
302  return static_cast<result>(from);
303  }
304  };
305 
306  template<integer Input, integer ResultRep, scaled_tag ResultScale>
307  struct custom_operator<
308  _impl::convert_op,
309  op_value<Input, _impl::native_tag>,
310  op_value<scaled_integer<ResultRep, ResultScale>, neg_inf_rounding_tag>>
311  : custom_operator<
312  _impl::convert_op,
313  op_value<scaled_integer<Input>, _impl::native_tag>,
314  op_value<scaled_integer<ResultRep, ResultScale>, neg_inf_rounding_tag>> {
315  };
316 
317  template<integer InputRep, scaled_tag InputScale, integer Result>
318  struct custom_operator<
319  _impl::convert_op,
320  op_value<scaled_integer<InputRep, InputScale>, _impl::native_tag>,
321  op_value<Result, neg_inf_rounding_tag>> {
322  private:
323  using input = scaled_integer<InputRep, InputScale>;
324 
325  public:
326  [[nodiscard]] constexpr auto operator()(input const& from) const -> Result
327  {
328  return _impl::to_rep(custom_operator<
329  _impl::convert_op,
330  op_value<input, _impl::native_tag>,
331  op_value<scaled_integer<Result>, neg_inf_rounding_tag>>{}(from));
332  }
333  };
334 }
335 
336 #endif // CNL_IMPL_SCALED_INTEGER_TAGGED_CONVERT_OPERATOR_H
cnl::op_value
operand or result of operation;used as Operands parameter of custom_operator
Definition: definition.h:40
cnl
compositional numeric library
Definition: abort.h:15
cnl::scaled_integer
_impl::wrapper< Rep, Scale > scaled_integer
literal real number approximation that uses fixed-point arithmetic
Definition: definition.h:52
cnl::custom_operator
customization point for operator overloads
Definition: definition.h:59