DUNE PDELab (2.7)

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
22namespace 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
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>
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
603namespace 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
bitwise or
bigunsignedint< k > operator^(const bigunsignedint< k > &x) const
bitwise exor
bigunsignedint< k > operator*(const bigunsignedint< k > &x) const
multiply
bigunsignedint< k > operator%(const bigunsignedint< k > &x) const
bigunsignedint< k > operator-(const bigunsignedint< k > &x) const
subtract
bigunsignedint< k > operator&(const bigunsignedint< k > &x) const
bitwise and
bigunsignedint< k > operator/(const bigunsignedint< k > &x) const
bigunsignedint< k > operator+(const bigunsignedint< k > &x) const
add
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
STL namespace.
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.111.3 (Jul 15, 22:36, 2024)