CNL  2.0.2 (development)
Compositional Numeric Library
multiply.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_DUPLEX_INTEGER_MULTIPLY_H)
8 #define CNL_IMPL_DUPLEX_INTEGER_MULTIPLY_H
9 
10 #include "../custom_operator/definition.h"
11 #include "../custom_operator/op.h"
12 #include "../num_traits/width.h"
13 #include "../type_traits/conditional3.h"
14 #include "definition.h"
15 #include "digits.h"
16 #include "numeric_limits.h"
17 #include "set_width.h"
18 
20 namespace cnl {
21  namespace _impl {
22  template<typename Lhs, typename Rhs>
23  struct heterogeneous_duplex_multiply_operator {
24  using common_type = conditional3_t<
25  width<Lhs> - width<Rhs>, Lhs,
26  conditional3_t<(numbers::signedness_v<Lhs> - numbers::signedness_v<Rhs>), Lhs, void, Rhs>,
27  Rhs>;
28 
29  [[nodiscard]] constexpr auto operator()(Lhs const& lhs, Rhs const& rhs) const
30  {
31  return static_cast<common_type>(lhs) * static_cast<common_type>(rhs);
32  }
33  };
34 
35  // long_multiply - T should be same width as operands
36  template<typename T>
37  struct long_multiply;
38 
39  // std::int64_t
40  template<typename Word>
41  struct long_multiply {
42  template<typename Lhs, typename Rhs>
43  using result_type = set_width_t<Word, width<Lhs> + width<Rhs>>;
44 
45  template<typename Lhs, typename Rhs>
46  [[nodiscard]] constexpr auto operator()(Lhs const& lhs, Rhs const& rhs) const
47  -> result_type<Lhs, Rhs>
48  {
49  using product_type = result_type<Lhs, Rhs>;
50  return static_cast<product_type>(lhs) * static_cast<product_type>(rhs);
51  }
52  };
53 
54  // duplex_integer<std::int64_t, std::int64_t>
55  template<typename Upper, typename Lower>
56  struct long_multiply<duplex_integer<Upper, Lower>> {
57  private:
58  using operand = duplex_integer<Upper, Lower>;
59  using result_type =
60  duplex_integer<operand, duplex_integer<Lower, Lower>>;
61 
62  public:
63  template<typename LhsUpper, typename LhsLower, typename RhsUpper, typename RhsLower>
64  [[nodiscard]] constexpr auto operator()(
65  duplex_integer<LhsUpper, LhsLower> const& lhs,
66  duplex_integer<RhsUpper, RhsLower> const& rhs) const -> result_type
67  {
68  return multiply_components(lhs.upper(), lhs.lower(), rhs.upper(), rhs.lower());
69  }
70 
71  template<typename Lhs, typename RhsUpper, typename RhsLower>
72  [[nodiscard]] constexpr auto operator()(
73  Lhs const& lhs, duplex_integer<RhsUpper, RhsLower> const& rhs) const
74  -> result_type
75  {
76  return multiply_components(0, lhs, rhs.upper(), rhs.lower());
77  }
78 
79  template<typename LhsUpper, typename LhsLower, typename Rhs>
80  [[nodiscard]] constexpr auto operator()(
81  duplex_integer<LhsUpper, LhsLower> const& lhs, Rhs const& rhs) const
82  -> result_type
83  {
84  return multiply_components(lhs.upper(), lhs.lower(), 0, rhs);
85  }
86 
87  template<typename LhsUpper, typename LhsLower, typename RhsUpper, typename RhsLower>
88  [[nodiscard]] static constexpr auto multiply_components(
89  LhsUpper const& lhs_upper, LhsLower const& lhs_lower, RhsUpper const& rhs_upper,
90  RhsLower const& rhs_lower) -> result_type
91  {
92  auto const upper_upper{_impl::long_multiply<Upper>{}(lhs_upper, rhs_upper)};
93  auto const upper_lower{_impl::long_multiply<Upper>{}(lhs_upper, rhs_lower)};
94  auto const lower_upper{_impl::long_multiply<Upper>{}(lhs_lower, rhs_upper)};
95  auto const lower_lower{_impl::long_multiply<Lower>{}(lhs_lower, rhs_lower)};
96  auto const upper{_impl::sensible_left_shift<result_type>(
97  upper_upper,
98  digits_v<LhsLower> + digits_v<RhsLower>)};
99  auto const mid{
100  (result_type{upper_lower} << digits_v<LhsLower>)+(result_type{lower_upper} << digits_v<RhsLower>)};
101  auto const lower{lower_lower};
102  return upper + mid + lower;
103  }
104  };
105  }
106 
107  // duplex_integer<> * duplex_integer<>>
108  template<typename Upper, typename Lower>
109  struct custom_operator<
110  _impl::multiply_op,
111  op_value<_impl::duplex_integer<Upper, Lower>>,
112  op_value<_impl::duplex_integer<Upper, Lower>>> {
113  private:
114  using operand = _impl::duplex_integer<Upper, Lower>;
115 
116  public:
117  [[nodiscard]] constexpr auto operator()(
118  operand const& lhs, operand const& rhs) const -> operand
119  {
120  return multiply_components(lhs.upper(), lhs.lower(), rhs.upper(), rhs.lower());
121  }
122 
123  [[nodiscard]] static constexpr auto multiply_components(
124  Upper const& lhs_upper, Lower const& lhs_lower, Upper const& rhs_upper,
125  Lower const& rhs_lower) -> operand
126  {
127  auto const upper_upper{_impl::long_multiply<Upper>{}(lhs_upper, rhs_upper)};
128  auto const upper_lower{_impl::long_multiply<Upper>{}(lhs_upper, rhs_lower)};
129  auto const lower_upper{_impl::long_multiply<Upper>{}(lhs_lower, rhs_upper)};
130  auto const lower_lower{_impl::long_multiply<Lower>{}(lhs_lower, rhs_lower)};
131  auto const upper{_impl::sensible_left_shift<operand>(upper_upper, digits_v<Lower> * 2)};
132  auto const mid{(upper_lower + lower_upper) << digits_v<Lower>};
133  auto const lower{lower_lower};
134  return upper + mid + lower;
135  }
136  };
137 
138  template<typename LhsUpper, typename LhsLower, typename RhsUpper, typename RhsLower>
139  struct custom_operator<
140  _impl::multiply_op,
141  op_value<_impl::duplex_integer<LhsUpper, LhsLower>>,
142  op_value<_impl::duplex_integer<RhsUpper, RhsLower>>>
143  : _impl::heterogeneous_duplex_multiply_operator<
144  _impl::duplex_integer<LhsUpper, LhsLower>,
145  _impl::duplex_integer<RhsUpper, RhsLower>> {
146  };
147 
148  template<typename LhsUpper, typename LhsLower, typename Rhs>
149  struct custom_operator<
150  _impl::multiply_op,
151  op_value<_impl::duplex_integer<LhsUpper, LhsLower>>,
152  op_value<Rhs>>
153  : _impl::heterogeneous_duplex_multiply_operator<
154  _impl::duplex_integer<LhsUpper, LhsLower>, Rhs> {
155  };
156 
157  template<typename Lhs, typename RhsUpper, typename RhsLower>
158  struct custom_operator<
159  _impl::multiply_op,
160  op_value<Lhs>,
161  op_value<_impl::duplex_integer<RhsUpper, RhsLower>>>
162  : _impl::heterogeneous_duplex_multiply_operator<
163  Lhs, _impl::duplex_integer<RhsUpper, RhsLower>> {
164  };
165 }
166 
167 #endif // CNL_IMPL_DUPLEX_INTEGER_MULTIPLY_H
cnl
compositional numeric library
Definition: abort.h:15