dune-common  2.11
bigunsignedint.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 
6 #ifndef DUNE_BIGUNSIGNEDINT_HH
7 #define DUNE_BIGUNSIGNEDINT_HH
8 
9 #include <algorithm>
10 #include <bit>
11 #include <iostream>
12 #include <limits>
13 #include <cstdint>
14 #include <cstdlib>
15 #include <type_traits>
17 #include <dune/common/hash.hh>
18 
25 namespace Dune
26 {
27 #if HAVE_MPI
28  template<class K>
29  struct MPITraits;
30 #endif
31 
37  namespace Impl {
38 
39  // numeric_limits_helper provides std::numeric_limits access to the internals
40  // of bigunsignedint. Previously, the correct specialization of std::numeric_limits
41  // was a friend of bigunsignedint, but that creates problems on recent versions
42  // of clang with the alternative libc++ library, because that library declares the
43  // base template of std::numeric_limits as a class and clang subsequently complains
44  // if the friend declaration uses 'struct'. Unfortunately, libstdc++ uses a struct,
45  // making it impossible to keep clang happy for both standard libraries.
46  // So we move the access helper functionality into a custom struct and simply let
47  // the numeric_limits specialization inherit from the helper.
48 
49  template<typename T>
50  struct numeric_limits_helper
51  {
52 
53  protected:
54 
55  static std::uint16_t& digit(T& big_unsigned_int, std::size_t i)
56  {
57  return big_unsigned_int.digit[i];
58  }
59 
60  };
61 
62  }
63 
73  template<int k>
75  public:
76 
77  // unsigned short is 16 bits wide, n is the number of digits needed
78  constexpr static int bits = std::numeric_limits<std::uint16_t>::digits;
79  constexpr static int n = k/bits+(k%bits!=0);
80  constexpr static int hexdigits = 4;
81  constexpr static int bitmask = 0xFFFF;
82  constexpr static int compbitmask = 0xFFFF0000;
83  constexpr static int overflowmask = 0x1;
84 
86  bigunsignedint ();
87 
89  template<typename Signed>
90  bigunsignedint (Signed x, typename std::enable_if<std::is_integral<Signed>::value && std::is_signed<Signed>::value>::type* = 0);
91 
93  bigunsignedint (std::uintmax_t x);
94 
96  void print (std::ostream& s) const ;
97 
101 
105 
109 
112 
118 
124 
128 
132 
136 
139 
140 
142  bigunsignedint<k> operator<< (int i) const;
143 
145  bigunsignedint<k> operator>> (int i) const;
146 
147 
149  bool operator< (const bigunsignedint<k>& x) const;
150 
152  bool operator<= (const bigunsignedint<k>& x) const;
153 
155  bool operator> (const bigunsignedint<k>& x) const;
156 
158  bool operator>= (const bigunsignedint<k>& x) const;
159 
161  bool operator== (const bigunsignedint<k>& x) const;
162 
164  bool operator!= (const bigunsignedint<k>& x) const;
165 
166 
168  // operator unsigned int () const;
169  std::uint_least32_t touint() const;
175  double todouble() const;
176 
177  friend class bigunsignedint<k/2>;
178  friend struct Impl::numeric_limits_helper< bigunsignedint<k> >;
179 
184  friend int bit_width(const bigunsignedint& arg)
185  {
186  int width = bits * std::size(arg.digit);
187  auto it = std::rbegin(arg.digit);
188  do {
189  width -= (bits - std::bit_width(*it));
190  } while ((*it == 0) and ((++it) != std::rend(arg.digit)));
191  return width;
192  }
193 
198  friend int countl_zero(const bigunsignedint& arg)
199  {
200  return bits*n - bit_width(arg);
201  }
202 
203  inline friend std::size_t hash_value(const bigunsignedint& arg)
204  {
205  return hash_range(arg.digit,arg.digit + arg.n);
206  }
207 
208  private:
209  std::uint16_t digit[n];
210 #if HAVE_MPI
211  friend struct MPITraits<bigunsignedint<k> >;
212 #endif
213  inline void assign(std::uintmax_t x);
214 
215 
216  } ;
217 
218  // Constructors
219  template<int k>
221  {
222  assign(0u);
223  }
224 
225  template<int k>
226  template<typename Signed>
227  bigunsignedint<k>::bigunsignedint (Signed y, typename std::enable_if<std::is_integral<Signed>::value && std::is_signed<Signed>::value>::type*)
228  {
229  if (y < 0)
230  DUNE_THROW(Dune::Exception, "Trying to construct a Dune::bigunsignedint from a negative integer: " << y);
231  assign(y);
232  }
233 
234  template<int k>
236  {
237  assign(x);
238  }
239  template<int k>
240  void bigunsignedint<k>::assign(std::uintmax_t x)
241  {
242  static const int no=std::min<int>(n, std::numeric_limits<std::uintmax_t>::digits/bits);
243 
244  for(int i=0; i<no; ++i) {
245  digit[i] = (x&bitmask);
246  x=x>>bits;
247  }
248  for (unsigned int i=no; i<n; i++) digit[i]=0;
249  }
250 
251  // export
252  template<int k>
253  inline std::uint_least32_t bigunsignedint<k>::touint () const
254  {
255  return (digit[1]<<bits)+digit[0];
256  }
257 
258  template<int k>
259  inline double bigunsignedint<k>::todouble() const
260  {
261  int firstInZeroRange=n;
262  for(int i=n-1; i>=0; --i)
263  if(digit[i]!=0)
264  break;
265  else
266  --firstInZeroRange;
267  int representableDigits=std::numeric_limits<double>::digits/bits;
268  int lastInRepresentableRange=0;
269  if(representableDigits<firstInZeroRange)
270  lastInRepresentableRange=firstInZeroRange-representableDigits;
271  double val=0;
272  for(int i=firstInZeroRange-1; i>=lastInRepresentableRange; --i)
273  val =val*(1<<bits)+digit[i];
274  return val*(1<<(bits*lastInRepresentableRange));
275  }
276  // print
277  template<int k>
278  inline void bigunsignedint<k>::print (std::ostream& s) const
279  {
280  bool leading=false;
281 
282  // print from left to right
283  for (int i=n-1; i>=0; i--)
284  for (int d=hexdigits-1; d>=0; d--)
285  {
286  // extract one hex digit
287  int current = (digit[i]>>(d*4))&0xF;
288  if (current!=0)
289  {
290  // s.setf(std::ios::noshowbase);
291  s << std::hex << current;
292  leading = false;
293  }
294  else if (!leading) s << std::hex << current;
295  }
296  if (leading) s << "0";
297  s << std::dec;
298  }
299 
300  template <int k>
301  inline std::ostream& operator<< (std::ostream& s, const bigunsignedint<k>& x)
302  {
303  x.print(s);
304  return s;
305  }
306 
307  #define DUNE_BINOP(OP) \
308  template <int k> \
309  inline bigunsignedint<k> bigunsignedint<k>::operator OP (const bigunsignedint<k> &x) const \
310  { \
311  auto temp = *this; \
312  temp OP##= x; \
313  return temp; \
314  }
315 
316  DUNE_BINOP(+)
317  DUNE_BINOP(-)
318  DUNE_BINOP(*)
319  DUNE_BINOP(/)
320  DUNE_BINOP(%)
321  DUNE_BINOP(&)
322  DUNE_BINOP(^)
323  DUNE_BINOP(|)
324 
325  #undef DUNE_BINOP
326 
327  template <int k>
329  {
330  std::uint_fast32_t overflow=0;
331 
332  for (unsigned int i=0; i<n; i++)
333  {
334  std::uint_fast32_t sum = static_cast<std::uint_fast32_t>(digit[i]) + static_cast<std::uint_fast32_t>(x.digit[i]) + overflow;
335  digit[i] = sum&bitmask;
336  overflow = (sum>>bits)&overflowmask;
337  }
338  return *this;
339  }
340 
341  template <int k>
343  {
344  std::int_fast32_t overflow=0;
345 
346  for (unsigned int i=0; i<n; i++)
347  {
348  std::int_fast32_t diff = static_cast<std::int_fast32_t>(digit[i]) - static_cast<std::int_fast32_t>(x.digit[i]) - overflow;
349  if (diff>=0)
350  {
351  digit[i] = static_cast<std::uint16_t>(diff);
352  overflow = 0;
353  }
354  else
355  {
356  digit[i] = static_cast<std::uint16_t>(diff+bitmask+1);
357  overflow = 1;
358  }
359  }
360  return *this;
361  }
362 
363  template <int k>
365  {
366  bigunsignedint<2*k> finalproduct(0);
367 
368  for (unsigned int m=0; m<n; m++) // digit in right factor
369  {
370  bigunsignedint<2*k> singleproduct(0);
371  std::uint_fast32_t overflow(0);
372  for (unsigned int i=0; i<n; i++)
373  {
374  std::uint_fast32_t digitproduct = static_cast<std::uint_fast32_t>(digit[i])*static_cast<std::uint_fast32_t>(x.digit[m])+overflow;
375  singleproduct.digit[i+m] = static_cast<std::uint16_t>(digitproduct&bitmask);
376  overflow = (digitproduct>>bits)&bitmask;
377  }
378  finalproduct = finalproduct+singleproduct;
379  }
380 
381  for (unsigned int i=0; i<n; i++) digit[i] = finalproduct.digit[i];
382  return *this;
383  }
384 
385  template <int k>
387  {
388  std::uint_fast32_t overflow=1;
389 
390  for (unsigned int i=0; i<n; i++)
391  {
392  std::uint_fast32_t sum = static_cast<std::uint_fast32_t>(digit[i]) + overflow;
393  digit[i] = sum&bitmask;
394  overflow = (sum>>bits)&overflowmask;
395  }
396  return *this;
397  }
398 
399  template <int k>
401  {
402  if(x==0)
403  DUNE_THROW(Dune::MathError, "division by zero!");
404 
405  // better slow than nothing
406  bigunsignedint<k> result(0);
407 
408  while (*this>=x)
409  {
410  ++result;
411  *this -= x;
412  }
413 
414  *this = result;
415  return *this;
416  }
417 
418  template <int k>
420  {
421  // better slow than nothing
422  while (*this>=x)
423  {
424  *this -= x;
425  }
426 
427  return *this;
428  }
429 
430  template <int k>
432  {
433  for (unsigned int i=0; i<n; i++)
434  digit[i] = digit[i]&x.digit[i];
435  return *this;
436  }
437 
438  template <int k>
440  {
441  for (unsigned int i=0; i<n; i++)
442  digit[i] = digit[i]^x.digit[i];
443  return *this;
444  }
445 
446  template <int k>
448  {
449  for (unsigned int i=0; i<n; i++)
450  digit[i] = digit[i]|x.digit[i];
451  return *this;
452  }
453 
454  template <int k>
456  {
457  bigunsignedint<k> result;
458  for (unsigned int i=0; i<n; i++)
459  result.digit[i] = ~digit[i];
460  return result;
461  }
462 
463  template <int k>
465  {
466  bigunsignedint<k> result(0);
467 
468  // multiples of bits
469  int j=shift/bits;
470  for (int i=n-1-j; i>=0; i--)
471  result.digit[i+j] = digit[i];
472 
473  // remainder
474  j=shift%bits;
475  for (int i=n-1; i>=0; i--)
476  {
477  unsigned int temp = result.digit[i];
478  temp = temp<<j;
479  result.digit[i] = static_cast<std::uint16_t>(temp&bitmask);
480  temp = temp>>bits;
481  if (i+1<(int)n)
482  result.digit[i+1] = result.digit[i+1]|temp;
483  }
484 
485  return result;
486  }
487 
488  template <int k>
490  {
491  bigunsignedint<k> result(0);
492 
493  // multiples of bits
494  int j=shift/bits;
495  for (unsigned int i=0; i<n-j; i++)
496  result.digit[i] = digit[i+j];
497 
498  // remainder
499  j=shift%bits;
500  for (unsigned int i=0; i<n; i++)
501  {
502  std::uint_fast32_t temp = result.digit[i];
503  temp = temp<<(bits-j);
504  result.digit[i] = static_cast<std::uint16_t>((temp&compbitmask)>>bits);
505  if (i>0)
506  result.digit[i-1] = result.digit[i-1] | (temp&bitmask);
507  }
508 
509  return result;
510  }
511 
512  template <int k>
514  {
515  for (unsigned int i=0; i<n; i++)
516  if (digit[i]!=x.digit[i]) return true;
517  return false;
518  }
519 
520  template <int k>
522  {
523  return !((*this)!=x);
524  }
525 
526  template <int k>
528  {
529  for (int i=n-1; i>=0; i--)
530  if (digit[i]<x.digit[i]) return true;
531  else if (digit[i]>x.digit[i]) return false;
532  return false;
533  }
534 
535  template <int k>
537  {
538  for (int i=n-1; i>=0; i--)
539  if (digit[i]<x.digit[i]) return true;
540  else if (digit[i]>x.digit[i]) return false;
541  return true;
542  }
543 
544  template <int k>
546  {
547  return !((*this)<=x);
548  }
549 
550  template <int k>
552  {
553  return !((*this)<x);
554  }
555 
556 
557  template <int k>
558  inline bigunsignedint<k> operator+ (const bigunsignedint<k>& x, std::uintmax_t y)
559  {
560  bigunsignedint<k> temp(y);
561  return x+temp;
562  }
563 
564  template <int k>
565  inline bigunsignedint<k> operator- (const bigunsignedint<k>& x, std::uintmax_t y)
566  {
567  bigunsignedint<k> temp(y);
568  return x-temp;
569  }
570 
571  template <int k>
572  inline bigunsignedint<k> operator* (const bigunsignedint<k>& x, std::uintmax_t y)
573  {
574  bigunsignedint<k> temp(y);
575  return x*temp;
576  }
577 
578  template <int k>
579  inline bigunsignedint<k> operator/ (const bigunsignedint<k>& x, std::uintmax_t y)
580  {
581  bigunsignedint<k> temp(y);
582  return x/temp;
583  }
584 
585  template <int k>
586  inline bigunsignedint<k> operator% (const bigunsignedint<k>& x, std::uintmax_t y)
587  {
588  bigunsignedint<k> temp(y);
589  return x%temp;
590  }
591 
592  template <int k>
593  inline bigunsignedint<k> operator+ (std::uintmax_t x, const bigunsignedint<k>& y)
594  {
595  bigunsignedint<k> temp(x);
596  return temp+y;
597  }
598 
599  template <int k>
600  inline bigunsignedint<k> operator- (std::uintmax_t x, const bigunsignedint<k>& y)
601  {
602  bigunsignedint<k> temp(x);
603  return temp-y;
604  }
605 
606  template <int k>
607  inline bigunsignedint<k> operator* (std::uintmax_t x, const bigunsignedint<k>& y)
608  {
609  bigunsignedint<k> temp(x);
610  return temp*y;
611  }
612 
613  template <int k>
614  inline bigunsignedint<k> operator/ (std::uintmax_t x, const bigunsignedint<k>& y)
615  {
616  bigunsignedint<k> temp(x);
617  return temp/y;
618  }
619 
620  template <int k>
621  inline bigunsignedint<k> operator% (std::uintmax_t x, const bigunsignedint<k>& y)
622  {
623  bigunsignedint<k> temp(x);
624  return temp%y;
625  }
626 
627  // Forward declare type-trait for numbers
628  template<class T> struct IsNumber;
629 
631  template <int k>
632  struct IsNumber<bigunsignedint<k>> : public std::true_type {};
633 
635 }
636 
637 namespace std
638 {
639  template<int k>
640  struct numeric_limits<Dune::bigunsignedint<k> >
641  : private Dune::Impl::numeric_limits_helper<Dune::bigunsignedint<k> > // for access to internal state of bigunsignedint
642  {
643  public:
644  static const bool is_specialized = true;
645 
647  {
648  return static_cast<Dune::bigunsignedint<k> >(0);
649  }
650 
652  {
654  for(std::size_t i=0; i < Dune::bigunsignedint<k>::n; ++i)
655  // access internal state via the helper base class
656  Dune::Impl::numeric_limits_helper<Dune::bigunsignedint<k> >::
658  return max_;
659  }
660 
661 
662  static const int digits = Dune::bigunsignedint<k>::bits *
664  static const bool is_signed = false;
665  static const bool is_integer = true;
666  static const bool is_exact = true;
667  static const int radix = 2;
668 
670  {
671  return static_cast<Dune::bigunsignedint<k> >(0);
672  }
673 
675  {
676  return static_cast<Dune::bigunsignedint<k> >(0);
677  }
678 
679  static const int min_exponent = 0;
680  static const int min_exponent10 = 0;
681  static const int max_exponent = 0;
682  static const int max_exponent10 = 0;
683 
684  static const bool has_infinity = false;
685  static const bool has_quiet_NaN = false;
686  static const bool has_signaling_NaN = false;
687 
688  static const float_denorm_style has_denorm = denorm_absent;
689  static const bool has_denorm_loss = false;
690 
692  {
693  return static_cast<Dune::bigunsignedint<k> >(0);
694  }
695 
697  {
698  return static_cast<Dune::bigunsignedint<k> >(0);
699  }
700 
702  {
703  return static_cast<Dune::bigunsignedint<k> >(0);
704  }
705 
707  {
708  return static_cast<Dune::bigunsignedint<k> >(0);
709  }
710 
711  static const bool is_iec559 = false;
712  static const bool is_bounded = true;
713  static const bool is_modulo = true;
714 
715  static const bool traps = false;
716  static const bool tinyness_before = false;
717  static const float_round_style round_style = round_toward_zero;
718 
719  };
720 
721 }
722 
724 
725 #endif
bigunsignedint< k > operator*(const bigunsignedint< k > &x) const
multiply
static Dune::bigunsignedint< k > epsilon()
Definition: bigunsignedint.hh:669
bigunsignedint< k > operator>>(int i) const
right shift
Definition: bigunsignedint.hh:489
static constexpr int overflowmask
Definition: bigunsignedint.hh:83
static constexpr int hexdigits
Definition: bigunsignedint.hh:80
bigunsignedint< k > & operator^=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:439
bigunsignedint< k > operator%(const bigunsignedint< k > &x) const
double todouble() const
Convert to a double.
Definition: bigunsignedint.hh:259
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: bigunsignedint.hh:628
bigunsignedint< k > operator-(const bigunsignedint< k > &x) const
subtract
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
bigunsignedint< k > & operator-=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:342
static Dune::bigunsignedint< k > quiet_NaN() noexcept
Definition: bigunsignedint.hh:696
bigunsignedint< k > operator+(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:558
bigunsignedint< k > operator|(const bigunsignedint< k > &x) const
bitwise or
friend std::size_t hash_value(const bigunsignedint &arg)
Definition: bigunsignedint.hh:203
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:572
bool operator!=(const bigunsignedint< k > &x) const
not equal
Definition: bigunsignedint.hh:513
friend int bit_width(const bigunsignedint &arg)
Bit width.
Definition: bigunsignedint.hh:184
static Dune::bigunsignedint< k > max()
Definition: bigunsignedint.hh:651
Base class for Dune-Exceptions.
Definition: exceptions.hh:96
static constexpr int n
Definition: bigunsignedint.hh:79
bigunsignedint< k > & operator++()
prefix increment
Definition: bigunsignedint.hh:386
static Dune::bigunsignedint< k > denorm_min() noexcept
Definition: bigunsignedint.hh:706
static constexpr int bits
Definition: bigunsignedint.hh:78
I i
Definition: hybridmultiindex.hh:328
bool operator==(const bigunsignedint< k > &x) const
equal
Definition: bigunsignedint.hh:521
friend int countl_zero(const bigunsignedint &arg)
Count left zero bits.
Definition: bigunsignedint.hh:198
bool operator>=(const bigunsignedint< k > &x) const
greater or equal
Definition: bigunsignedint.hh:551
#define DUNE_BINOP(OP)
Definition: bigunsignedint.hh:307
void assign(T &dst, const T &src, bool mask)
masked Simd assignment (scalar version)
Definition: simd.hh:447
Portable very large unsigned integers.
Definition: bigunsignedint.hh:74
bigunsignedint< k > & operator|=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:447
static constexpr int bitmask
Definition: bigunsignedint.hh:81
Dune namespace
Definition: alignedallocator.hh:12
static Dune::bigunsignedint< k > signaling_NaN() noexcept
Definition: bigunsignedint.hh:701
void print(std::ostream &s) const
Print number in hex notation.
Definition: bigunsignedint.hh:278
bool operator>(const bigunsignedint< k > &x) const
greater than
Definition: bigunsignedint.hh:545
std::uint_least32_t touint() const
export to other types
Definition: bigunsignedint.hh:253
Support for calculating hash values of objects.
bigunsignedint< k > operator/(const bigunsignedint< k > &x) const
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
bigunsignedint< k > operator-(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:565
bigunsignedint< k > operator/(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:579
bigunsignedint< k > operator+(const bigunsignedint< k > &x) const
add
bigunsignedint< k > & operator/=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:400
bigunsignedint< k > operator<<(int i) const
left shift
Definition: bigunsignedint.hh:464
bigunsignedint< k > & operator+=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:328
bigunsignedint< k > operator%(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:586
A few common exception classes.
bool operator<(const bigunsignedint< k > &x) const
less than
Definition: bigunsignedint.hh:527
static Dune::bigunsignedint< k > round_error()
Definition: bigunsignedint.hh:674
std::size_t hash_range(It first, It last)
Hashes all elements in the range [first,last) and returns the combined hash.
Definition: hash.hh:322
Default exception class for mathematical errors.
Definition: exceptions.hh:335
bigunsignedint< k > operator^(const bigunsignedint< k > &x) const
bitwise exor
#define DUNE_HASH_TYPE(...)
Wrapper macro for the type to be hashed in DUNE_DEFINE_HASH.
Definition: hash.hh:117
bool operator<=(const bigunsignedint< k > &x) const
less than or equal
Definition: bigunsignedint.hh:536
bigunsignedint< k > & operator%=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:419
A traits class describing the mapping of types onto MPI_Datatypes.
Definition: bigunsignedint.hh:29
static Dune::bigunsignedint< k > infinity() noexcept
Definition: bigunsignedint.hh:691
STL namespace.
static constexpr int compbitmask
Definition: bigunsignedint.hh:82
bigunsignedint< k > & operator*=(const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:364
bigunsignedint< k > operator~() const
bitwise complement
Definition: bigunsignedint.hh:455
static Dune::bigunsignedint< k > min()
Definition: bigunsignedint.hh:646
#define DUNE_DEFINE_HASH(template_args, type)
Defines the required struct specialization to make type hashable via Dune::hash.
Definition: hash.hh:100
bigunsignedint< k > & operator &=(const bigunsignedint< k > &x)
bigunsignedint< k > operator &(const bigunsignedint< k > &x) const
bitwise and
#define DUNE_HASH_TEMPLATE_ARGS(...)
Wrapper macro for the template arguments in DUNE_DEFINE_HASH.
Definition: hash.hh:109
bigunsignedint()
Construct uninitialized.
Definition: bigunsignedint.hh:220