10 #if !defined(SG14_FIXED_POINT_ARITHMETIC_H) 11 #define SG14_FIXED_POINT_ARITHMETIC_H 1 15 #include "fixed_point_type.h" 25 namespace arithmetic {
38 using ::sg14::fixed_point;
43 template<
class LhsRep,
int LhsExponent,
class RhsRep,
int RhsExponent>
44 struct binary_pair_base {
45 using lhs_type = fixed_point<LhsRep, LhsExponent>;
46 using rhs_type = fixed_point<RhsRep, RhsExponent>;
49 template<
class Lhs,
class Rhs>
52 template<
class LhsRep,
int LhsExponent,
class RhsRep,
int RhsExponent>
53 struct binary_pair<fixed_point<LhsRep, LhsExponent>, fixed_point<RhsRep, RhsExponent>>
54 : binary_pair_base<LhsRep, LhsExponent, RhsRep, RhsExponent> {
57 template<
class LhsRep,
int LhsExponent,
class Rhs>
58 struct binary_pair<fixed_point<LhsRep, LhsExponent>, Rhs>
59 : binary_pair_base<LhsRep, LhsExponent, Rhs, 0> {
60 static_assert(std::numeric_limits<Rhs>::is_integer,
61 "named arithmetic functions take only fixed_point and integral types");
64 template<
class Lhs,
class RhsRep,
int RhsExponent>
65 struct binary_pair<Lhs, fixed_point<RhsRep, RhsExponent>>
66 : binary_pair_base<Lhs, 0, RhsRep, RhsExponent> {
67 static_assert(std::numeric_limits<Lhs>::is_integer,
68 "named arithmetic functions take only fixed_point and integral types");
74 template<
class OperationTag,
class ... Operands>
75 struct rep_op_exponent;
78 struct rep_op_exponent<_impl::plus_op, Rhs> :
public std::integral_constant<int, Rhs::exponent> {
82 struct rep_op_exponent<_impl::minus_op, Rhs> :
public std::integral_constant<int, Rhs::exponent> {
85 template<
class Lhs,
class Rhs>
86 struct rep_op_exponent<_impl::add_op, Lhs, Rhs> :
public std::integral_constant<int, _impl::min<int>(
91 template<
class Lhs,
class Rhs>
92 struct rep_op_exponent<_impl::subtract_op, Lhs, Rhs>
93 :
public std::integral_constant<int, _impl::min<int>(
98 template<
class Lhs,
class Rhs>
99 struct rep_op_exponent<_impl::multiply_op, Lhs, Rhs> :
public std::integral_constant<int,
100 Lhs::exponent+Rhs::exponent> {
103 template<
class Lhs,
class Rhs>
104 struct rep_op_exponent<_impl::divide_op, Lhs, Rhs> :
public std::integral_constant<int,
105 Lhs::exponent-Rhs::exponent> {
111 template<
class PolicyTag,
class OperationTag,
class Lhs,
class Rhs>
115 template<
class OperationTag,
class Lhs,
class Rhs>
116 struct result<raw_tag, OperationTag, Lhs, Rhs> {
117 using lhs_rep =
typename Lhs::rep;
118 using rhs_rep =
typename Rhs::rep;
119 using rep_op_result = _impl::op_result<OperationTag, lhs_rep, rhs_rep>;
121 static constexpr
int exponent = rep_op_exponent<OperationTag, Lhs, Rhs>::value;
123 using type = fixed_point<rep_op_result, exponent>;
127 template<
class OperationTag,
class Lhs,
class Rhs>
128 struct result<lean_tag, OperationTag, Lhs, Rhs> : result<raw_tag, OperationTag, Lhs, Rhs> {};
131 template<
class OperationTag,
class Lhs,
class Rhs>
132 struct result<wide_tag, OperationTag, Lhs, Rhs> {
133 using lhs_rep =
typename Lhs::rep;
134 using rhs_rep =
typename Rhs::rep;
135 using rep_op_result = _impl::op_result<OperationTag, lhs_rep, rhs_rep>;
138 static constexpr
int sufficient_sign_bits = std::is_signed<rep_op_result>::value;
139 static constexpr
int sufficient_integer_digits = _impl::max(Lhs::integer_digits,
140 Rhs::integer_digits);
141 static constexpr
int sufficient_fractional_digits = _impl::max(Lhs::fractional_digits,
142 Rhs::fractional_digits);
143 static constexpr _digits_type sufficient_digits = sufficient_integer_digits+sufficient_fractional_digits;
144 static constexpr
int result_digits = _impl::max(sufficient_digits, digits<rep_op_result>::value);
146 using rep_type = set_digits_t<rep_op_result, result_digits>;
147 using type = fixed_point<rep_type, -sufficient_fractional_digits>;
150 template<
class Lhs,
class Rhs>
151 struct result<wide_tag, _impl::multiply_op, Lhs, Rhs> {
152 using lhs_rep =
typename Lhs::rep;
153 using rhs_rep =
typename Rhs::rep;
154 using rep_op_result = _impl::op_result<_impl::multiply_op, lhs_rep, rhs_rep>;
156 static constexpr
int digits = Lhs::digits+Rhs::digits;
157 static constexpr
bool is_signed =
158 std::numeric_limits<lhs_rep>::is_signed || std::numeric_limits<rhs_rep>::is_signed;
160 using prewidened_result_rep = _impl::make_signed_t<rep_op_result, is_signed>;
161 using rep_type = set_digits_t<prewidened_result_rep, digits>;
163 static constexpr
int rep_exponent = rep_op_exponent<_impl::multiply_op, Lhs, Rhs>::value;
165 using type = fixed_point<rep_type, rep_exponent>;
168 template<
class Lhs,
class Rhs>
169 struct result<wide_tag, _impl::divide_op, Lhs, Rhs> {
170 using lhs_rep =
typename Lhs::rep;
171 using rhs_rep =
typename Rhs::rep;
172 using rep_op_result = _impl::op_result<_impl::multiply_op, lhs_rep, rhs_rep>;
174 static constexpr
int integer_digits = Lhs::integer_digits+Rhs::fractional_digits;
175 static constexpr
int fractional_digits = Lhs::fractional_digits+Rhs::integer_digits;
176 static constexpr
int necessary_digits = integer_digits+fractional_digits;
177 static constexpr
bool is_signed =
178 std::numeric_limits<lhs_rep>::is_signed || std::numeric_limits<rhs_rep>::is_signed;
180 static constexpr
int promotion_digits = digits<rep_op_result>::value;
181 static constexpr
int digits = _impl::max(necessary_digits, promotion_digits);
183 using prewidened_result_rep = _impl::make_signed_t<rep_op_result, is_signed>;
184 using rep_type = set_digits_t<prewidened_result_rep, digits>;
186 static constexpr
int rep_exponent = -fractional_digits;
188 using type = fixed_point<rep_type, rep_exponent>;
194 template<
class PolicyTag,
class OperationTag,
class Lhs,
class Rhs>
199 template<
class OperationTag,
class Lhs,
class Rhs>
200 struct intermediate<lean_tag, OperationTag, Lhs, Rhs> {
201 using _result = result<lean_tag, OperationTag, Lhs, Rhs>;
202 using lhs_type =
typename _result::type;
203 using rhs_type = lhs_type;
206 template<
class Lhs,
class Rhs>
207 struct intermediate<lean_tag, _impl::multiply_op, Lhs, Rhs> {
208 using lhs_type = Lhs;
209 using rhs_type = Rhs;
212 template<
class Lhs,
class Rhs>
213 struct intermediate<lean_tag, _impl::divide_op, Lhs, Rhs> {
214 using lhs_type = Lhs;
215 using rhs_type = Rhs;
221 template<
class OperationTag,
class Lhs,
class Rhs>
222 struct intermediate<wide_tag, OperationTag, Lhs, Rhs> {
223 using _result = result<wide_tag, OperationTag, Lhs, Rhs>;
224 using lhs_type =
typename _result::type;
225 using rhs_type = lhs_type;
228 template<
class Lhs,
class Rhs>
229 struct intermediate<wide_tag, _impl::multiply_op, Lhs, Rhs> {
230 using _result = result<wide_tag, _impl::multiply_op, Lhs, Rhs>;
231 using result_rep =
typename _result::rep_type;
232 using prewidened_result_rep =
typename _result::prewidened_result_rep;
237 using rep_type =
typename std::conditional<
238 digits<prewidened_result_rep>::value>=_result::digits,
239 typename Lhs::rep, result_rep>::type;
241 using lhs_type = fixed_point<rep_type, Lhs::exponent>;
242 using rhs_type = Rhs;
245 template<
class Lhs,
class Rhs>
246 struct intermediate<wide_tag, _impl::divide_op, Lhs, Rhs> {
247 using wide_result = result<wide_tag, _impl::divide_op, Lhs, Rhs>;
248 using rep_type =
typename wide_result::rep_type;
250 static constexpr
int exponent = Lhs::exponent-Rhs::digits;
252 using lhs_type = fixed_point<rep_type, exponent>;
253 using rhs_type = Rhs;
259 template<
class PolicyTag,
class OperationTag,
class Lhs,
class Rhs>
260 struct operate_params {
261 using _binary_pair = binary_pair<Lhs, Rhs>;
262 using lhs_type =
typename _binary_pair::lhs_type;
263 using rhs_type =
typename _binary_pair::rhs_type;
265 using _intermediate = intermediate<PolicyTag, OperationTag, lhs_type, rhs_type>;
266 using intermediate_lhs =
typename _intermediate::lhs_type;
267 using intermediate_rhs =
typename _intermediate::rhs_type;
269 using _result = result<PolicyTag, OperationTag, lhs_type, rhs_type>;
270 using result_type =
typename _result::type;
278 using arithmetic_operator_tag = arithmetic::lean_tag;
279 using division_arithmetic_operator_tag = arithmetic::wide_tag;
280 using named_function_tag = arithmetic::wide_tag;
281 using division_named_function_tag = arithmetic::lean_tag;
286 template<
class PolicyTag,
class Operation,
class Lhs,
class Rhs>
287 constexpr
auto operate(
const Lhs& lhs,
const Rhs& rhs, Operation)
288 ->
typename arithmetic::operate_params<PolicyTag, Operation, Lhs, Rhs>::result_type
290 using params = arithmetic::operate_params<PolicyTag, Operation, Lhs, Rhs>;
291 using intermediate_lhs =
typename params::intermediate_lhs;
292 using intermediate_rhs =
typename params::intermediate_rhs;
293 using result_type =
typename params::result_type;
294 using result_rep =
typename result_type::rep;
296 return result_type::from_data(
297 static_cast<result_rep>(
299 static_cast<intermediate_lhs>(lhs).data(),
300 static_cast<intermediate_rhs>(rhs).data())));
306 #endif // SG14_FIXED_POINT_ARITHMETIC_H study group 14 of the C++ working group
Definition: const_integer.h:22