TensorUInt128.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2015 Benoit Steiner <benoit.steiner.goog@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_UINT128_H
11 #define EIGEN_CXX11_TENSOR_TENSOR_UINT128_H
12 
13 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 namespace internal {
17 
18 
19 template <uint64_t n>
20 struct static_val {
21  static const uint64_t value = n;
22  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE operator uint64_t() const { return n; }
23 
24  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static_val() { }
25 
26  template <typename T>
27  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static_val(const T& v) {
29  eigen_assert(v == n);
30  }
31 };
32 
33 
34 template <typename HIGH = uint64_t, typename LOW = uint64_t>
35 struct TensorUInt128
36 {
37  HIGH high;
38  LOW low;
39 
40  template<typename OTHER_HIGH, typename OTHER_LOW>
42  TensorUInt128(const TensorUInt128<OTHER_HIGH, OTHER_LOW>& other) : high(other.high), low(other.low) {
43  EIGEN_STATIC_ASSERT(sizeof(OTHER_HIGH) <= sizeof(HIGH), YOU_MADE_A_PROGRAMMING_MISTAKE);
44  EIGEN_STATIC_ASSERT(sizeof(OTHER_LOW) <= sizeof(LOW), YOU_MADE_A_PROGRAMMING_MISTAKE);
45  }
46 
47  template<typename OTHER_HIGH, typename OTHER_LOW>
49  TensorUInt128& operator = (const TensorUInt128<OTHER_HIGH, OTHER_LOW>& other) {
50  EIGEN_STATIC_ASSERT(sizeof(OTHER_HIGH) <= sizeof(HIGH), YOU_MADE_A_PROGRAMMING_MISTAKE);
51  EIGEN_STATIC_ASSERT(sizeof(OTHER_LOW) <= sizeof(LOW), YOU_MADE_A_PROGRAMMING_MISTAKE);
52  high = other.high;
53  low = other.low;
54  return *this;
55  }
56 
57  template<typename T>
59  explicit TensorUInt128(const T& x) : high(0), low(x) {
60  eigen_assert((static_cast<std::conditional_t<sizeof(T) == 8, uint64_t, uint32_t>>(x) <= NumTraits<uint64_t>::highest()));
61  eigen_assert(x >= 0);
62  }
63 
65  TensorUInt128(HIGH y, LOW x) : high(y), low(x) { }
66 
67  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE operator LOW() const {
68  return low;
69  }
70  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LOW lower() const {
71  return low;
72  }
73  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE HIGH upper() const {
74  return high;
75  }
76 };
77 
78 
79 template <typename HL, typename LL, typename HR, typename LR>
81 bool operator == (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
82 {
83  return (lhs.high == rhs.high) && (lhs.low == rhs.low);
84 }
85 
86 template <typename HL, typename LL, typename HR, typename LR>
88 bool operator != (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
89 {
90  return (lhs.high != rhs.high) || (lhs.low != rhs.low);
91 }
92 
93 template <typename HL, typename LL, typename HR, typename LR>
95 bool operator >= (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
96 {
97  if (lhs.high != rhs.high) {
98  return lhs.high > rhs.high;
99  }
100  return lhs.low >= rhs.low;
101 }
102 
103 template <typename HL, typename LL, typename HR, typename LR>
105 bool operator < (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
106 {
107  if (lhs.high != rhs.high) {
108  return lhs.high < rhs.high;
109  }
110  return lhs.low < rhs.low;
111 }
112 
113 template <typename HL, typename LL, typename HR, typename LR>
115 TensorUInt128<uint64_t, uint64_t> operator + (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
116 {
117  TensorUInt128<uint64_t, uint64_t> result(lhs.high + rhs.high, lhs.low + rhs.low);
118  if (result.low < rhs.low) {
119  result.high += 1;
120  }
121  return result;
122 }
123 
124 template <typename HL, typename LL, typename HR, typename LR>
126 TensorUInt128<uint64_t, uint64_t> operator - (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
127 {
128  TensorUInt128<uint64_t, uint64_t> result(lhs.high - rhs.high, lhs.low - rhs.low);
129  if (result.low > lhs.low) {
130  result.high -= 1;
131  }
132  return result;
133 }
134 
135 
136 template <typename HL, typename LL, typename HR, typename LR>
137 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
138 TensorUInt128<uint64_t, uint64_t> operator * (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
139 {
140  // Split each 128-bit integer into 4 32-bit integers, and then do the
141  // multiplications by hand as follow:
142  // lhs a b c d
143  // rhs e f g h
144  // -----------
145  // ah bh ch dh
146  // bg cg dg
147  // cf df
148  // de
149  // The result is stored in 2 64bit integers, high and low.
150 
151  const uint64_t LOW = 0x00000000FFFFFFFFLL;
152  const uint64_t HIGH = 0xFFFFFFFF00000000LL;
153 
154  uint64_t d = lhs.low & LOW;
155  uint64_t c = (lhs.low & HIGH) >> 32LL;
156  uint64_t b = lhs.high & LOW;
157  uint64_t a = (lhs.high & HIGH) >> 32LL;
158 
159  uint64_t h = rhs.low & LOW;
160  uint64_t g = (rhs.low & HIGH) >> 32LL;
161  uint64_t f = rhs.high & LOW;
162  uint64_t e = (rhs.high & HIGH) >> 32LL;
163 
164  // Compute the low 32 bits of low
165  uint64_t acc = d * h;
166  uint64_t low = acc & LOW;
167  // Compute the high 32 bits of low. Add a carry every time we wrap around
168  acc >>= 32LL;
169  uint64_t carry = 0;
170  uint64_t acc2 = acc + c * h;
171  if (acc2 < acc) {
172  carry++;
173  }
174  acc = acc2 + d * g;
175  if (acc < acc2) {
176  carry++;
177  }
178  low |= (acc << 32LL);
179 
180  // Carry forward the high bits of acc to initiate the computation of the
181  // low 32 bits of high
182  acc2 = (acc >> 32LL) | (carry << 32LL);
183  carry = 0;
184 
185  acc = acc2 + b * h;
186  if (acc < acc2) {
187  carry++;
188  }
189  acc2 = acc + c * g;
190  if (acc2 < acc) {
191  carry++;
192  }
193  acc = acc2 + d * f;
194  if (acc < acc2) {
195  carry++;
196  }
197  uint64_t high = acc & LOW;
198 
199  // Start to compute the high 32 bits of high.
200  acc2 = (acc >> 32LL) | (carry << 32LL);
201 
202  acc = acc2 + a * h;
203  acc2 = acc + b * g;
204  acc = acc2 + c * f;
205  acc2 = acc + d * e;
206  high |= (acc2 << 32LL);
207 
208  return TensorUInt128<uint64_t, uint64_t>(high, low);
209 }
210 
211 template <typename HL, typename LL, typename HR, typename LR>
212 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
213 TensorUInt128<uint64_t, uint64_t> operator / (const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs)
214 {
215  if (rhs == TensorUInt128<static_val<0>, static_val<1> >(1)) {
216  return TensorUInt128<uint64_t, uint64_t>(lhs.high, lhs.low);
217  } else if (lhs < rhs) {
218  return TensorUInt128<uint64_t, uint64_t>(0);
219  } else {
220  // calculate the biggest power of 2 times rhs that's less than or equal to lhs
221  TensorUInt128<uint64_t, uint64_t> power2(1);
222  TensorUInt128<uint64_t, uint64_t> d(rhs);
223  TensorUInt128<uint64_t, uint64_t> tmp(lhs - d);
224  while (lhs >= d) {
225  tmp = tmp - d;
226  d = d + d;
227  power2 = power2 + power2;
228  }
229 
230  tmp = TensorUInt128<uint64_t, uint64_t>(lhs.high, lhs.low);
231  TensorUInt128<uint64_t, uint64_t> result(0);
232  while (power2 != TensorUInt128<static_val<0>, static_val<0> >(0)) {
233  if (tmp >= d) {
234  tmp = tmp - d;
235  result = result + power2;
236  }
237  // Shift right
238  power2 = TensorUInt128<uint64_t, uint64_t>(power2.high >> 1, (power2.low >> 1) | (power2.high << 63));
239  d = TensorUInt128<uint64_t, uint64_t>(d.high >> 1, (d.low >> 1) | (d.high << 63));
240  }
241 
242  return result;
243  }
244 }
245 
246 
247 } // namespace internal
248 } // namespace Eigen
249 
250 
251 #endif // EIGEN_CXX11_TENSOR_TENSOR_UINT128_H
ArrayXXi a
int n
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Array33i c
#define EIGEN_ALWAYS_INLINE
#define EIGEN_UNUSED_VARIABLE(var)
#define EIGEN_DEVICE_FUNC
#define eigen_assert(x)
#define EIGEN_STATIC_ASSERT(X, MSG)
EIGEN_ALWAYS_INLINE bool operator!=(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:88
T operator/(const T &numerator, const TensorIntDivisor< T, div_gt_one > &divisor)
Definition: TensorIntDiv.h:253
EIGEN_ALWAYS_INLINE TensorUInt128< uint64_t, uint64_t > operator-(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
const Scalar & y
EIGEN_ALWAYS_INLINE TensorUInt128< uint64_t, uint64_t > operator+(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
static TensorUInt128< uint64_t, uint64_t > operator*(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
EIGEN_ALWAYS_INLINE bool operator<(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
EIGEN_ALWAYS_INLINE bool operator==(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:81
EIGEN_ALWAYS_INLINE bool operator>=(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:95
std::uint32_t uint32_t
std::uint64_t uint64_t
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend