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 // IWYU pragma: private
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 namespace internal {
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 
25 
26  template <typename T>
29  eigen_assert(v == n);
30  }
31 };
32 
33 template <typename HIGH = uint64_t, typename LOW = uint64_t>
34 struct TensorUInt128 {
35  HIGH high;
36  LOW low;
37 
38  template <typename OTHER_HIGH, typename OTHER_LOW>
40  : high(other.high), low(other.low) {
41  EIGEN_STATIC_ASSERT(sizeof(OTHER_HIGH) <= sizeof(HIGH), YOU_MADE_A_PROGRAMMING_MISTAKE);
42  EIGEN_STATIC_ASSERT(sizeof(OTHER_LOW) <= sizeof(LOW), YOU_MADE_A_PROGRAMMING_MISTAKE);
43  }
44 
45  template <typename OTHER_HIGH, typename OTHER_LOW>
47  EIGEN_STATIC_ASSERT(sizeof(OTHER_HIGH) <= sizeof(HIGH), YOU_MADE_A_PROGRAMMING_MISTAKE);
48  EIGEN_STATIC_ASSERT(sizeof(OTHER_LOW) <= sizeof(LOW), YOU_MADE_A_PROGRAMMING_MISTAKE);
49  high = other.high;
50  low = other.low;
51  return *this;
52  }
53 
54  template <typename T>
57  (static_cast<std::conditional_t<sizeof(T) == 8, uint64_t, uint32_t>>(x) <= NumTraits<uint64_t>::highest()));
58  eigen_assert(x >= 0);
59  }
60 
62 
63  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE operator LOW() const { return low; }
66 };
67 
68 template <typename HL, typename LL, typename HR, typename LR>
70  const TensorUInt128<HR, LR>& rhs) {
71  return (lhs.high == rhs.high) && (lhs.low == rhs.low);
72 }
73 
74 template <typename HL, typename LL, typename HR, typename LR>
76  const TensorUInt128<HR, LR>& rhs) {
77  return (lhs.high != rhs.high) || (lhs.low != rhs.low);
78 }
79 
80 template <typename HL, typename LL, typename HR, typename LR>
82  const TensorUInt128<HR, LR>& rhs) {
83  if (lhs.high != rhs.high) {
84  return lhs.high > rhs.high;
85  }
86  return lhs.low >= rhs.low;
87 }
88 
89 template <typename HL, typename LL, typename HR, typename LR>
91  const TensorUInt128<HR, LR>& rhs) {
92  if (lhs.high != rhs.high) {
93  return lhs.high < rhs.high;
94  }
95  return lhs.low < rhs.low;
96 }
97 
98 template <typename HL, typename LL, typename HR, typename LR>
100  const TensorUInt128<HR, LR>& rhs) {
101  TensorUInt128<uint64_t, uint64_t> result(lhs.high + rhs.high, lhs.low + rhs.low);
102  if (result.low < rhs.low) {
103  result.high += 1;
104  }
105  return result;
106 }
107 
108 template <typename HL, typename LL, typename HR, typename LR>
110  const TensorUInt128<HR, LR>& rhs) {
111  TensorUInt128<uint64_t, uint64_t> result(lhs.high - rhs.high, lhs.low - rhs.low);
112  if (result.low > lhs.low) {
113  result.high -= 1;
114  }
115  return result;
116 }
117 
118 template <typename HL, typename LL, typename HR, typename LR>
120  const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs) {
121  // Split each 128-bit integer into 4 32-bit integers, and then do the
122  // multiplications by hand as follow:
123  // lhs a b c d
124  // rhs e f g h
125  // -----------
126  // ah bh ch dh
127  // bg cg dg
128  // cf df
129  // de
130  // The result is stored in 2 64bit integers, high and low.
131 
132  const uint64_t LOW = 0x00000000FFFFFFFFLL;
133  const uint64_t HIGH = 0xFFFFFFFF00000000LL;
134 
135  uint64_t d = lhs.low & LOW;
136  uint64_t c = (lhs.low & HIGH) >> 32LL;
137  uint64_t b = lhs.high & LOW;
138  uint64_t a = (lhs.high & HIGH) >> 32LL;
139 
140  uint64_t h = rhs.low & LOW;
141  uint64_t g = (rhs.low & HIGH) >> 32LL;
142  uint64_t f = rhs.high & LOW;
143  uint64_t e = (rhs.high & HIGH) >> 32LL;
144 
145  // Compute the low 32 bits of low
146  uint64_t acc = d * h;
147  uint64_t low = acc & LOW;
148  // Compute the high 32 bits of low. Add a carry every time we wrap around
149  acc >>= 32LL;
150  uint64_t carry = 0;
151  uint64_t acc2 = acc + c * h;
152  if (acc2 < acc) {
153  carry++;
154  }
155  acc = acc2 + d * g;
156  if (acc < acc2) {
157  carry++;
158  }
159  low |= (acc << 32LL);
160 
161  // Carry forward the high bits of acc to initiate the computation of the
162  // low 32 bits of high
163  acc2 = (acc >> 32LL) | (carry << 32LL);
164  carry = 0;
165 
166  acc = acc2 + b * h;
167  if (acc < acc2) {
168  carry++;
169  }
170  acc2 = acc + c * g;
171  if (acc2 < acc) {
172  carry++;
173  }
174  acc = acc2 + d * f;
175  if (acc < acc2) {
176  carry++;
177  }
178  uint64_t high = acc & LOW;
179 
180  // Start to compute the high 32 bits of high.
181  acc2 = (acc >> 32LL) | (carry << 32LL);
182 
183  acc = acc2 + a * h;
184  acc2 = acc + b * g;
185  acc = acc2 + c * f;
186  acc2 = acc + d * e;
187  high |= (acc2 << 32LL);
188 
189  return TensorUInt128<uint64_t, uint64_t>(high, low);
190 }
191 
192 template <typename HL, typename LL, typename HR, typename LR>
194  const TensorUInt128<HL, LL>& lhs, const TensorUInt128<HR, LR>& rhs) {
195  if (rhs == TensorUInt128<static_val<0>, static_val<1>>(1)) {
196  return TensorUInt128<uint64_t, uint64_t>(lhs.high, lhs.low);
197  } else if (lhs < rhs) {
199  } else {
200  // calculate the biggest power of 2 times rhs that's less than or equal to lhs
204  while (lhs >= d) {
205  tmp = tmp - d;
206  d = d + d;
207  power2 = power2 + power2;
208  }
209 
212  while (power2 != TensorUInt128<static_val<0>, static_val<0>>(0)) {
213  if (tmp >= d) {
214  tmp = tmp - d;
215  result = result + power2;
216  }
217  // Shift right
218  power2 = TensorUInt128<uint64_t, uint64_t>(power2.high >> 1, (power2.low >> 1) | (power2.high << 63));
219  d = TensorUInt128<uint64_t, uint64_t>(d.high >> 1, (d.low >> 1) | (d.high << 63));
220  }
221 
222  return result;
223  }
224 }
225 
226 } // namespace internal
227 } // namespace Eigen
228 
229 #endif // EIGEN_CXX11_TENSOR_TENSOR_UINT128_H
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Array< double, 1, 3 > e(1./3., 0.5, 2.)
#define EIGEN_ALWAYS_INLINE
Definition: Macros.h:845
#define EIGEN_UNUSED_VARIABLE(var)
Definition: Macros.h:966
#define EIGEN_DEVICE_FUNC
Definition: Macros.h:892
#define eigen_assert(x)
Definition: Macros.h:910
#define EIGEN_STRONG_INLINE
Definition: Macros.h:834
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
Scalar * b
Definition: benchVecAdd.cpp:17
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
const Scalar * a
Definition: level2_cplx_impl.h:32
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator/(const T &numerator, const TensorIntDivisor< T, div_gt_one > &divisor)
Definition: TensorIntDiv.h:254
const Scalar & y
Definition: RandomImpl.h:36
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool operator<(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:90
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128< uint64_t, uint64_t > operator-(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:109
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool operator!=(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:75
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool operator>=(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:81
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorUInt128< uint64_t, uint64_t > operator*(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:119
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool operator==(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:69
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128< uint64_t, uint64_t > operator+(const TensorUInt128< HL, LL > &lhs, const TensorUInt128< HR, LR > &rhs)
Definition: TensorUInt128.h:99
std::uint32_t uint32_t
Definition: Meta.h:40
std::uint64_t uint64_t
Definition: Meta.h:42
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
int c
Definition: calibrate.py:100
Definition: Eigen_Colamd.h:49
list x
Definition: plotDoE.py:28
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:217
Definition: TensorUInt128.h:34
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE HIGH upper() const
Definition: TensorUInt128.h:65
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128(const TensorUInt128< OTHER_HIGH, OTHER_LOW > &other)
Definition: TensorUInt128.h:39
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128 & operator=(const TensorUInt128< OTHER_HIGH, OTHER_LOW > &other)
Definition: TensorUInt128.h:46
HIGH high
Definition: TensorUInt128.h:35
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128(HIGH y, LOW x)
Definition: TensorUInt128.h:61
LOW low
Definition: TensorUInt128.h:36
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TensorUInt128(const T &x)
Definition: TensorUInt128.h:55
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LOW lower() const
Definition: TensorUInt128.h:64
Definition: TensorUInt128.h:20
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static_val(const T &v)
Definition: TensorUInt128.h:27
static const uint64_t value
Definition: TensorUInt128.h:21
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static_val()
Definition: TensorUInt128.h:24