Dune Core Modules (2.7.0)

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