Dune Core Modules (unstable)

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