Interface Documentation
Version: invalid
uint128.hh
Go to the documentation of this file.
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
18 #if !defined(__clang__)
19 #include <algorithm>
20 #include <cstdint>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <exception>
24 #include <new>
25 
26 namespace flecsi {
27 namespace util {
29 class uint128;
30 
31 inline bool operator<(const uint128 & a, const uint128 & b) noexcept;
32 inline bool operator==(const uint128 & a, const uint128 & b) noexcept;
33 inline bool operator||(const uint128 & a, const uint128 & b) noexcept;
34 inline bool operator&&(const uint128 & a, const uint128 & b) noexcept;
35 
36 // GLOBAL OPERATOR INLINES
37 
38 inline uint128 operator+(const uint128 & a, const uint128 & b) noexcept;
39 inline uint128 operator-(const uint128 & a, const uint128 & b) noexcept;
40 inline uint128 operator*(const uint128 & a, const uint128 & b) noexcept;
41 inline uint128 operator/(const uint128 & a, const uint128 & b) noexcept;
42 inline uint128 operator%(const uint128 & a, const uint128 & b) noexcept;
43 
44 inline uint128 operator>>(const uint128 & a, unsigned int n) noexcept;
45 inline uint128 operator<<(const uint128 & a, unsigned int n) noexcept;
46 
47 inline uint128 operator&(const uint128 & a, const uint128 & b) noexcept;
48 inline uint128 operator|(const uint128 & a, const uint128 & b) noexcept;
49 inline uint128 operator^(const uint128 & a, const uint128 & b) noexcept;
50 
51 inline bool operator>(const uint128 & a, const uint128 & b) noexcept;
52 inline bool operator<=(const uint128 & a, const uint128 & b) noexcept;
53 inline bool operator>=(const uint128 & a, const uint128 & b) noexcept;
54 inline bool operator!=(const uint128 & a, const uint128 & b) noexcept;
55 
57 class uint128
58 {
59 private:
60  // Binary correct representation of unsigned 128bit integer
61  std::uint64_t lo;
62  std::uint64_t hi;
63 
64 protected:
65  // Some global operator functions must be friends
66  friend bool operator<(const uint128 &, const uint128 &) noexcept;
67  friend bool operator==(const uint128 &, const uint128 &) noexcept;
68  friend bool operator||(const uint128 &, const uint128 &) noexcept;
69  friend bool operator&&(const uint128 &, const uint128 &) noexcept;
70 
71 public:
72  // Constructors
73  inline uint128() noexcept : lo(0ull), hi(0ull) {}
74 
75  inline uint128(int a) noexcept : lo(a), hi(0ull) {}
76  inline uint128(unsigned int a) noexcept : lo(a), hi(0ull) {}
77  inline uint128(std::uint64_t a) noexcept : lo(a), hi(0ull) {}
78 
79  uint128(float a) noexcept
80  : lo((std::uint64_t)fmodf(a, 18446744073709551616.0f)),
81  hi((std::uint64_t)(a / 18446744073709551616.0f)) {}
82  uint128(double a) noexcept
83  : lo((std::uint64_t)fmod(a, 18446744073709551616.0)),
84  hi((std::uint64_t)(a / 18446744073709551616.0)) {}
85  uint128(long double a) noexcept
86  : lo((std::uint64_t)fmodl(a, 18446744073709551616.0l)),
87  hi((std::uint64_t)(a / 18446744073709551616.0l)) {}
88 
89  uint128(const char * sz) noexcept : lo(0u), hi(0u) {
90  if(!sz)
91  return;
92  if(!sz[0])
93  return;
94 
95  unsigned int radix = 10;
96  std::size_t i = 0;
97  bool minus = false;
98 
99  if(sz[i] == '-') {
100  ++i;
101  minus = true;
102  };
103 
104  if(sz[i] == '0') {
105  radix = 8;
106  ++i;
107  if(sz[i] == 'x') {
108  radix = 16;
109  ++i;
110  };
111  };
112 
113  std::size_t len = strlen(sz);
114  for(; i < len; ++i) {
115  unsigned int n = 0;
116  if(sz[i] >= '0' && sz[i] <= (std::min)(('0' + (int)radix), (int)'9'))
117  n = sz[i] - '0';
118  else if(sz[i] >= 'a' && sz[i] <= 'a' + (int)radix - 10)
119  n = sz[i] - 'a' + 10;
120  else if(sz[i] >= 'A' && sz[i] <= 'A' + (int)radix - 10)
121  n = sz[i] - 'A' + 10;
122  else
123  break;
124 
125  (*this) *= radix;
126  (*this) += n;
127  };
128 
129  if(minus)
130  *this = 0u - *this;
131  }
132 
133  // TODO: Consider creation of operator= to eliminate
134  // the need of intermediate objects during assignments.
135 
136 private:
137  // Special internal constructors
138  uint128(const std::uint64_t & a, const std::uint64_t & b) noexcept
139  : lo(a), hi(b) {}
140 
141 public:
142  // Operators
143  bool operator!() const noexcept {
144  return !(this->hi || this->lo);
145  }
146 
147  uint128 operator-() const noexcept {
148  if(!this->hi && !this->lo)
149  // number is 0, just return 0
150  return *this;
151 
152 #pragma warning(push)
153 #pragma warning(disable : 4146)
154  // non 0 number
155  return uint128(-this->lo, ~this->hi);
156 #pragma warning(pop)
157  }
158  uint128 operator~() const noexcept {
159  return uint128(~this->lo, ~this->hi);
160  }
161 
162  uint128 & operator++() {
163  ++this->lo;
164  if(!this->lo)
165  ++this->hi;
166 
167  return *this;
168  }
169  uint128 & operator--() {
170  if(!this->lo)
171  --this->hi;
172  --this->lo;
173 
174  return *this;
175  }
176  uint128 operator++(int) {
177  uint128 b = *this;
178  ++*this;
179 
180  return b;
181  }
182  uint128 operator--(int) {
183  uint128 b = *this;
184  --*this;
185 
186  return b;
187  }
188 
189  uint128 & operator+=(const uint128 & b) noexcept {
190  std::uint64_t old_lo = this->lo;
191 
192  this->lo += b.lo;
193  this->hi += b.hi + (this->lo < old_lo);
194 
195  return *this;
196  }
197  uint128 & operator*=(const uint128 & b) noexcept {
198  if(!b)
199  return *this = 0u;
200  if(b == 1u)
201  return *this;
202 
203  uint128 a = *this;
204  uint128 t = b;
205 
206  this->lo = 0ull;
207  this->hi = 0ull;
208 
209  for(unsigned int i = 0; i < 128; ++i) {
210  if(t.lo & 1)
211  *this += a << i;
212 
213  t >>= 1;
214  };
215 
216  return *this;
217  }
218 
219  uint128 & operator>>=(unsigned int n) noexcept {
220  n &= 0x7F;
221 
222  if(n > 63) {
223  n -= 64;
224  this->lo = this->hi;
225  this->hi = 0ull;
226  };
227 
228  if(n) {
229  // shift low qword
230  this->lo >>= n;
231 
232  // get lower N bits of high qword
233  std::uint64_t mask = 0ull;
234  for(unsigned int i = 0; i < n; ++i)
235  mask |= (1ll << i);
236 
237  // and add them to low qword
238  this->lo |= (this->hi & mask) << (64 - n);
239 
240  // and finally shift also high qword
241  this->hi >>= n;
242  };
243 
244  return *this;
245  }
246  uint128 & operator<<=(unsigned int n) noexcept {
247  n &= 0x7F;
248 
249  if(n > 63) {
250  n -= 64;
251  this->hi = this->lo;
252  this->lo = 0ull;
253  };
254 
255  if(n) {
256  // shift high qword
257  this->hi <<= n;
258 
259  // get higher N bits of low qword
260  std::uint64_t mask = 0ull;
261  for(unsigned int i = 0; i < n; ++i)
262  mask |= (1ll << (63 - i));
263 
264  // and add them to high qword
265  this->hi |= (this->lo & mask) >> (64 - n);
266 
267  // and finally shift also low qword
268  this->lo <<= n;
269  };
270 
271  return *this;
272  }
273 
274  uint128 & operator|=(const uint128 & b) noexcept {
275  this->hi |= b.hi;
276  this->lo |= b.lo;
277 
278  return *this;
279  }
280  uint128 & operator&=(const uint128 & b) noexcept {
281  this->hi &= b.hi;
282  this->lo &= b.lo;
283 
284  return *this;
285  }
286  uint128 & operator^=(const uint128 & b) noexcept {
287  this->hi ^= b.hi;
288  this->lo ^= b.lo;
289 
290  return *this;
291  }
292 
293  explicit operator bool() const noexcept {
294  return lo || hi;
295  }
296 
297  // Inline simple operators
298  inline const uint128 & operator+() const noexcept {
299  return *this;
300  };
301 
302  // Rest of inline operators
303  inline uint128 & operator-=(const uint128 & b) noexcept {
304  return *this += (-b);
305  };
306  inline uint128 & operator/=(const uint128 & b) noexcept {
307  uint128 dummy;
308  *this = this->div(b, dummy);
309  return *this;
310  };
311  inline uint128 & operator%=(const uint128 & b) noexcept {
312  this->div(b, *this);
313  return *this;
314  };
315 
316  explicit operator std::uint64_t() const noexcept {
317  return lo;
318  }
319 
320  // Common methods
321  unsigned int toUint() const noexcept {
322  return (unsigned int)this->lo;
323  };
324  std::uint64_t toUint64() const noexcept {
325  return (std::uint64_t)this->lo;
326  };
327  const char * toString(unsigned int radix = 10) const noexcept {
328  if(!*this)
329  return "0";
330  if(radix < 2 || radix > 37)
331  return "(invalid radix)";
332 
333  static char sz[256];
334  std::memset(sz, 0, 256);
335 
336  uint128 r;
337  uint128 ii = *this;
338  int i = 255;
339 
340  while(!!ii && i) {
341  ii = ii.div(radix, r);
342  sz[--i] = r.toUint() + ((r.toUint() > 9) ? 'A' - 10 : '0');
343  };
344 
345  return &sz[i];
346  }
347  float toFloat() const noexcept {
348  return (float)this->hi * 18446744073709551616.0f + (float)this->lo;
349  }
350  double toDouble() const noexcept {
351  return (double)this->hi * 18446744073709551616.0 + (double)this->lo;
352  }
353  long double toLongDouble() const noexcept {
354  return (long double)this->hi * 18446744073709551616.0l +
355  (long double)this->lo;
356  }
357 
358  // Arithmetic methods
359  uint128 div(const uint128 & ds, uint128 & remainder) const noexcept {
360  if(!ds)
361  return 1u / (unsigned int)ds.lo;
362 
363  uint128 dd = *this;
364 
365  // only remainder
366  if(ds > dd) {
367  remainder = *this;
368  return std::uint64_t(0ull);
369  };
370 
371  uint128 r = std::uint64_t(0ull);
372  uint128 q = std::uint64_t(0ull);
373  // while (dd >= ds) { dd -= ds; q += 1; }; // extreme slow version
374 
375  unsigned int b = 127;
376  while(r < ds) {
377  r <<= 1;
378  if(dd.bit(b--))
379  r.lo |= 1;
380  };
381  ++b;
382 
383  while(true)
384  if(r < ds) {
385  if(!(b--))
386  break;
387 
388  r <<= 1;
389  if(dd.bit(b))
390  r.lo |= 1;
391  }
392  else {
393  r -= ds;
394  q.bit(b, true);
395  };
396 
397  remainder = r;
398  return q;
399  }
400 
401  // Bit operations
402  bool bit(unsigned int n) const noexcept {
403  n &= 0x7F;
404 
405  if(n < 64)
406  return (this->lo & (1ull << n)) ? true : false;
407 
408  return (this->hi & (1ull << (n - 64))) ? true : false;
409  }
410  void bit(unsigned int n, bool val) noexcept {
411  n &= 0x7F;
412 
413  if(val) {
414  if(n < 64)
415  this->lo |= (1ull << n);
416  else
417  this->hi |= (1ull << (n - 64));
418  }
419  else {
420  if(n < 64)
421  this->lo &= ~(1ull << n);
422  else
423  this->hi &= ~(1ull << (n - 64));
424  };
425  }
426 }
427 #ifdef __GNUC__
428 __attribute__((__aligned__(16), __packed__))
429 #endif
430 ;
431 
432 // GLOBAL OPERATORS
433 
434 inline bool
435 operator<(const uint128 & a, const uint128 & b) noexcept {
436  return (a.hi == b.hi) ? (a.lo < b.lo) : (a.hi < b.hi);
437 }
438 inline bool
439 operator==(const uint128 & a, const uint128 & b) noexcept {
440  return a.hi == b.hi && a.lo == b.lo;
441 }
442 inline bool
443 operator||(const uint128 & a, const uint128 & b) noexcept {
444  return (a.hi || a.lo) && (b.hi || b.lo);
445 }
446 inline bool
447 operator&&(const uint128 & a, const uint128 & b) noexcept {
448  return (a.hi || a.lo) || (b.hi || b.lo);
449 }
450 
451 // GLOBAL OPERATOR INLINES
452 
453 inline uint128
454 operator+(const uint128 & a, const uint128 & b) noexcept {
455  return uint128(a) += b;
456 };
457 inline uint128
458 operator-(const uint128 & a, const uint128 & b) noexcept {
459  return uint128(a) -= b;
460 };
461 inline uint128 operator*(const uint128 & a, const uint128 & b) noexcept {
462  return uint128(a) *= b;
463 };
464 inline uint128
465 operator/(const uint128 & a, const uint128 & b) noexcept {
466  return uint128(a) /= b;
467 };
468 inline uint128
469 operator%(const uint128 & a, const uint128 & b) noexcept {
470  return uint128(a) %= b;
471 };
472 
473 inline uint128
474 operator>>(const uint128 & a, unsigned int n) noexcept {
475  return uint128(a) >>= n;
476 };
477 inline uint128
478 operator<<(const uint128 & a, unsigned int n) noexcept {
479  return uint128(a) <<= n;
480 };
481 
482 inline uint128 operator&(const uint128 & a, const uint128 & b) noexcept {
483  return uint128(a) &= b;
484 };
485 inline uint128
486 operator|(const uint128 & a, const uint128 & b) noexcept {
487  return uint128(a) |= b;
488 };
489 inline uint128
490 operator^(const uint128 & a, const uint128 & b) noexcept {
491  return uint128(a) ^= b;
492 };
493 
494 inline bool
495 operator>(const uint128 & a, const uint128 & b) noexcept {
496  return b < a;
497 };
498 inline bool
499 operator<=(const uint128 & a, const uint128 & b) noexcept {
500  return !(b < a);
501 };
502 inline bool
503 operator>=(const uint128 & a, const uint128 & b) noexcept {
504  return !(a < b);
505 };
506 inline bool
507 operator!=(const uint128 & a, const uint128 & b) noexcept {
508  return !(a == b);
509 };
510 } // namespace util
511 } // namespace flecsi
512 
514 #endif
Definition: uint128.hh:57
constexpr dimensioned_array< TYPE, DIMENSION, NAMESPACE > operator+(const dimensioned_array< TYPE, DIMENSION, NAMESPACE > &lhs, const dimensioned_array< TYPE, DIMENSION, NAMESPACE > &rhs)
Definition: dimensioned_array.hh:261
std::ostream & operator<<(std::ostream &ostr, const filling_curve< D, T, DER > &k)
output for filling_curve using output_ function defined in the class
Definition: filling_curve.hh:206
constexpr point< TYPE, DIMENSION > operator*(TYPE const val, point< TYPE, DIMENSION > const &p)
Definition: point.hh:52
constexpr dimensioned_array< TYPE, DIMENSION, NAMESPACE > operator-(const dimensioned_array< TYPE, DIMENSION, NAMESPACE > &lhs, const dimensioned_array< TYPE, DIMENSION, NAMESPACE > &rhs)
Definition: dimensioned_array.hh:281
Definition: control.hh:31