DUNE PDELab (git)

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
24namespace 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
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>
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
614namespace 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
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: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
STL namespace.
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.111.3 (Jul 15, 22:36, 2024)