Loading [MathJax]/extensions/tex2jax.js

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 <bit>
11#include <iostream>
12#include <limits>
13#include <cstdint>
14#include <cstdlib>
15#include <type_traits>
17#include <dune/common/hash.hh>
18
25namespace 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
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
100 bigunsignedint<k>& operator+= (const bigunsignedint<k>& x);
101
104 bigunsignedint<k>& operator-= (const bigunsignedint<k>& x);
105
108 bigunsignedint<k>& operator*= (const bigunsignedint<k>& x);
109
112
117 bigunsignedint<k>& operator/= (const bigunsignedint<k>& x);
118
123 bigunsignedint<k>& operator%= (const bigunsignedint<k>& x);
124
127 bigunsignedint<k>& operator&= (const bigunsignedint<k>& x);
128
131 bigunsignedint<k>& operator^= (const bigunsignedint<k>& x);
132
135 bigunsignedint<k>& operator|= (const bigunsignedint<k>& x);
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>
328 inline bigunsignedint<k>& bigunsignedint<k>::operator+= (const bigunsignedint<k>& x)
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>
342 inline bigunsignedint<k>& bigunsignedint<k>::operator-= (const bigunsignedint<k>& x)
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>
364 inline bigunsignedint<k>& bigunsignedint<k>::operator*= (const bigunsignedint<k>& x)
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>
419 inline bigunsignedint<k>& bigunsignedint<k>::operator%= (const bigunsignedint<k>& x)
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>
431 inline bigunsignedint<k>& bigunsignedint<k>::operator&= (const bigunsignedint<k>& x)
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>
439 inline bigunsignedint<k>& bigunsignedint<k>::operator^= (const bigunsignedint<k>& x)
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>
447 inline bigunsignedint<k>& bigunsignedint<k>::operator|= (const bigunsignedint<k>& x)
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
637namespace 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
669 static Dune::bigunsignedint<k> epsilon()
670 {
671 return static_cast<Dune::bigunsignedint<k> >(0);
672 }
673
674 static Dune::bigunsignedint<k> round_error()
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
691 static Dune::bigunsignedint<k> infinity() noexcept
692 {
693 return static_cast<Dune::bigunsignedint<k> >(0);
694 }
695
696 static Dune::bigunsignedint<k> quiet_NaN() noexcept
697 {
698 return static_cast<Dune::bigunsignedint<k> >(0);
699 }
700
701 static Dune::bigunsignedint<k> signaling_NaN() noexcept
702 {
703 return static_cast<Dune::bigunsignedint<k> >(0);
704 }
705
706 static Dune::bigunsignedint<k> denorm_min() noexcept
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
Base class for Dune-Exceptions.
Definition: exceptions.hh:96
Default exception class for mathematical errors.
Definition: exceptions.hh:333
Portable very large unsigned integers.
Definition: bigunsignedint.hh:74
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
friend int bit_width(const bigunsignedint &arg)
Bit width.
Definition: bigunsignedint.hh:184
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
friend int countl_zero(const bigunsignedint &arg)
Count left zero bits.
Definition: bigunsignedint.hh:198
A few common exception classes.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:312
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:485
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:507
bigunsignedint< k > operator<<(int i) const
left shift
Definition: bigunsignedint.hh:464
bool operator<=(const bigunsignedint< k > &x) const
less than or equal
Definition: bigunsignedint.hh:536
void print(std::ostream &s) const
Print number in hex notation.
Definition: bigunsignedint.hh:278
bool operator<(const bigunsignedint< k > &x) const
less than
Definition: bigunsignedint.hh:527
bool operator==(const bigunsignedint< k > &x) const
equal
Definition: bigunsignedint.hh:521
bool operator!=(const bigunsignedint< k > &x) const
not equal
Definition: bigunsignedint.hh:513
bigunsignedint()
Construct uninitialized.
Definition: bigunsignedint.hh:220
bool operator>=(const bigunsignedint< k > &x) const
greater or equal
Definition: bigunsignedint.hh:551
bigunsignedint< k > operator>>(int i) const
right shift
Definition: bigunsignedint.hh:489
bigunsignedint< k > operator~() const
bitwise complement
Definition: bigunsignedint.hh:455
bigunsignedint< k > & operator++()
prefix increment
Definition: bigunsignedint.hh:386
double todouble() const
Convert to a double.
Definition: bigunsignedint.hh:259
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.
#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
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Mar 12, 23:28, 2025)