• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stillwater-sc / universal / 23218775201

17 Mar 2026 10:11PM UTC coverage: 84.305% (+0.2%) from 84.112%
23218775201

push

github

web-flow
feat(blas): add serialization regression tests and verify #509 fix (#589)

Add regression level 1 tests for the serialization facility:

serialization.cpp:
- Exercise ReportFormats for lns and dbns (the lns::fraction() stub
  that caused #509 is now implemented)
- Native float vector save/restore round-trip

typed_serialization.cpp:
- lns<8,2> vector round-trip (directly exercises #509 scenario)
- dbns<8,3> vector round-trip
- integer<32> vector round-trip
- Plus existing float, double, half, type-mismatch, multi-dataset tests

The lns::fraction() function is no longer a stub -- it correctly
extracts the lower rbits as the fractional part of the fixed-point
exponent. This means #509 is resolved.

Resolves #585
Relates to #509

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

51 of 69 new or added lines in 2 files covered. (73.91%)

1 existing line in 1 file now uncovered.

44180 of 52405 relevant lines covered (84.3%)

6014239.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.78
/include/sw/universal/number/integer/integer_impl.hpp
1
#pragma once
2
// integer_impl.hpp: implementation of a fixed-size arbitrary precision integer number
3
//
4
// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc.
5
//
6
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
7
#include <string>
8
#include <sstream>
9
#include <iostream>
10
#include <iomanip>
11
#include <algorithm>
12
#include <regex>
13
#include <vector>
14
#include <map>
15

16
// supporting types and functions
17
#include <universal/number/shared/specific_value_encoding.hpp>
18
#include <universal/number/shared/blocktype.hpp>
19
#include <universal/native/integers.hpp> // just for printing native integers in binary form
20
#include <universal/internal/blocktype/carry.hpp> // carry-detection intrinsics for uint64_t limbs
21

22
/*
23
the integer arithmetic can be configured to:
24
- throw exceptions on overflow
25
- throw exceptions on arithmetic
26
- throw exceptions on encoding errors for Whole and Natural Numbers
27

28
you need the exception types defined, but you have the option to throw them
29
 */
30
#include <universal/number/integer/exceptions.hpp>
31

32
 // composition types used by integer
33
#include <universal/number/support/decimal.hpp>
34
#include <universal/internal/blocktriple/blocktriple.hpp>
35

36
namespace sw { namespace universal {
37

38
enum class IntegerNumberType {
39
        IntegerNumber = 0,  // { ...,-3,-2,-1,0,1,2,3,... }
40
        WholeNumber   = 1,  // {              0,1,2,3,... }
41
        NaturalNumber = 2   // {                1,2,3,... }
42
};
43

44
constexpr IntegerNumberType IntegerNumber = IntegerNumberType::IntegerNumber;
45
constexpr IntegerNumberType WholeNumber = IntegerNumberType::WholeNumber;
46
constexpr IntegerNumberType NaturalNumber = IntegerNumberType::NaturalNumber;
47

48
// scale calculate the power of 2 exponent that would capture an approximation of a normalized real value
49
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
50
inline long scale(const integer<nbits, BlockType, NumberType>& i) {
248✔
51
        integer<nbits, BlockType, NumberType> v(i);
248✔
52
        if (i.sign()) { // special case handling
248✔
53
                v.twosComplement();
48✔
54
                if (v == i) {  // special case of 10000..... largest negative number in 2's complement encoding
48✔
55
                        return long(nbits - 1);
3✔
56
                }
57
        }
58
        // calculate scale
59
        long scale = 0;
245✔
60
        while (v > 1) {
9,500✔
61
                ++scale;
9,255✔
62
                v >>= 1;
9,255✔
63
        }
64
        return scale;
245✔
65
}
66

67
// signed integer conversion
68
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
69
inline constexpr integer<nbits, BlockType, NumberType>& convert(int64_t v, integer<nbits, BlockType, NumberType>& result) {        return result.convert(v); }
70
// unsigned integer conversion
71
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
72
inline constexpr integer<nbits, BlockType, NumberType>& convert(uint64_t v, integer<nbits, BlockType, NumberType>& result) { return result.convert(v); }
73

74
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
75
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& v);
76

77
// idiv_t for integer<nbits, BlockType, NumberType> to capture quotient and remainder during long division
78
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
79
struct idiv_t {
80
        idiv_t() : quot{ 0 }, rem{ 0 } {};
1,691,013✔
81
        integer<nbits, BlockType, NumberType> quot; // quotient
82
        integer<nbits, BlockType, NumberType> rem;  // remainder
83
};
84

85
/*
86
The rules for detecting overflow in a two's complement sum are simple:
87
 - If the sum of two positive numbers yields a negative result, the sum has overflowed.
88
 - If the sum of two negative numbers yields a positive result, the sum has overflowed.
89
 - Otherwise, the sum has not overflowed.
90
It is important to note the overflow and carry out can each occur without the other. 
91
In unsigned numbers, carry out is equivalent to overflow. In two's complement, carry out tells 
92
you nothing about overflow.
93

94
The reason for the rules is that overflow in two's complement occurs, not when a bit is carried out 
95
out of the left column, but when one is carried into it. That is, when there is a carry into the sign. 
96
The rules detect this error by examining the sign of the result. A negative and positive added together 
97
cannot overflow, because the sum is between the addends. Since both of the addends fit within the
98
allowable range of numbers, and their sum is between them, it must fit as well.
99

100
When implementing addition/subtraction on chuncks the overflow condition must be deduced from the 
101
chunk values. The chunks need to be interpreted as unsigned binary segments.
102
*/
103

104
// integer is an arbitrary fixed-sized 2's complement integer
105
template<unsigned _nbits, typename bt = std::uint8_t, IntegerNumberType _NumberType = IntegerNumberType::IntegerNumber>
106
class integer {
107
public:
108
        // cache template parameters
109
        static constexpr unsigned nbits = _nbits;
110
        typedef bt BlockType;
111
        static constexpr IntegerNumberType NumberType = _NumberType;
112
        // derive other parameters
113
        static constexpr unsigned bitsInByte = 8ull;
114
        static constexpr unsigned bitsInBlock = sizeof(bt) * bitsInByte;
115
        static constexpr unsigned nrBlocks = 1ull + ((nbits - 1ull) / bitsInBlock);
116
        static constexpr unsigned MSU = nrBlocks - 1ull;
117
        static constexpr bt       ALL_ONES = bt(~0); // block type specific all 1's value
118
        static constexpr unsigned bitSurplus = (nrBlocks * bitsInBlock - nbits);
119
        static constexpr unsigned bitsInMSU = bitsInBlock - bitSurplus;
120
        static constexpr bool     EXACT_FIT = (bitSurplus == 0);
121
        static constexpr unsigned signBitShift = (EXACT_FIT ? (bitsInBlock - 1) : bitsInMSU - 1);
122
        static constexpr bt       SIGN_BIT_MASK = bt(1ull << signBitShift);
123
        static constexpr bt       MSU_MASK = bt(ALL_ONES >> bitSurplus);
124
        static constexpr bt       SIGN_EXTENTION_BITS = static_cast<bt>(~MSU_MASK);
125
        static constexpr uint64_t storageMask = (uint64_t(~0) >> (64u - bitsInBlock));
126
        static constexpr uint64_t BASE = (ALL_ONES + 1ull);
127

128
        /// trivial constructor
129
        constexpr integer() noexcept = default;
130

131
        /// Construct a new integer from another, sign extend when necessary, BlockTypes must be the same
132
        template<unsigned srcbits>
133
        integer(const integer<srcbits, BlockType, NumberType>& a) {
1,954,023✔
134
//                static_assert(srcbits > nbits, "Source integer is bigger than target: potential loss of precision"); // TODO: do we want this?
135
                bitcopy(a);
1,954,023✔
136
                if constexpr (srcbits < nbits && NumberType == IntegerNumberType::IntegerNumber) {
137
                        if (a.sign()) { // sign extend
536,818✔
138
                                for (unsigned i = srcbits; i < nbits; ++i) {
523,690✔
139
                                        setbit(i);
261,845✔
140
                                }
141
                        }
142
                }
143
        }
1,954,023✔
144

145
        // initializers for native types
146
        constexpr integer(signed char initial_value)        noexcept { *this = initial_value; }
147
        constexpr integer(short initial_value)              noexcept { *this = initial_value; }
148
        constexpr integer(int initial_value)                noexcept { *this = initial_value; }
28,477,769✔
149
        constexpr integer(long initial_value)               noexcept { *this = initial_value; }
14✔
150
        constexpr integer(long long initial_value)          noexcept { *this = initial_value; }
203,571✔
151
        constexpr integer(char initial_value)               noexcept { *this = initial_value; }
152
        constexpr integer(unsigned short initial_value)     noexcept { *this = initial_value; }
153
        constexpr integer(unsigned int initial_value)       noexcept { *this = initial_value; }
12✔
154
        constexpr integer(unsigned long initial_value)      noexcept { *this = initial_value; }
368✔
155
        constexpr integer(unsigned long long initial_value) noexcept { *this = initial_value; }
12✔
156
        constexpr integer(float initial_value)              noexcept { *this = initial_value; }
20✔
157
        constexpr integer(double initial_value)             noexcept { *this = initial_value; }
100✔
158
        constexpr integer(long double initial_value)        noexcept { *this = initial_value; }
159

160
        // specific value constructors
161
        constexpr integer(const std::string& s) noexcept { assign(s); }
1✔
162
        constexpr integer(const SpecificValue code) noexcept
163
                : _block{ 0 } {
164
                switch (code) {
165
                case SpecificValue::maxpos:
166
                        maxpos();
167
                        break;
168
                case SpecificValue::minpos:
169
                        minpos();
170
                        break;
171
                case SpecificValue::zero:
172
                default:
173
                        zero();
174
                        break;
175
                case SpecificValue::minneg:
176
                        minneg();
177
                        break;
178
                case SpecificValue::maxneg:
179
                        maxneg();
180
                        break;
181
                case SpecificValue::infneg:
182
                case SpecificValue::infpos:
183
                case SpecificValue::qnan:
184
                case SpecificValue::snan:
185
                case SpecificValue::nar:
186
                        zero();
187
                        break;
188
                }
189
        }
190

191
        // access operator for bits
192
        // this needs a proxy to be able to create l-values
193
        // bool operator[](const unsigned int i) const //
194

195
        // simpler interface for now, using at(i) and set(i)/reset(i)
196

197
        // assignment operators for native types
198
        constexpr integer& operator=(signed char rhs)        { return convert_signed(rhs); }
199
        constexpr integer& operator=(short rhs)              { return convert_signed(rhs); }
200
        constexpr integer& operator=(int rhs)                { return convert_signed(rhs); }
33,689,546✔
201
        constexpr integer& operator=(long rhs)               { return convert_signed(rhs); }
1,936,671✔
202
        constexpr integer& operator=(long long rhs)          { return convert_signed(rhs); }
204,356✔
203
        constexpr integer& operator=(char rhs)               { return convert_unsigned(rhs); }
204
        constexpr integer& operator=(unsigned short rhs)     { return convert_unsigned(rhs); }
522,242✔
205
        constexpr integer& operator=(unsigned int rhs)       { return convert_unsigned(rhs); }
3,523✔
206
        constexpr integer& operator=(unsigned long rhs)      { return convert_unsigned(rhs); }
1,172✔
207
        constexpr integer& operator=(unsigned long long rhs) { return convert_unsigned(rhs); }
213✔
208
        constexpr integer& operator=(float rhs)              { return convert_ieee(rhs); }
24✔
209
        constexpr integer& operator=(double rhs)             { return convert_ieee(rhs); }
758✔
210
#if LONG_DOUBLE_SUPPORT
211
        constexpr integer& operator=(long double rhs)        { return convert_ieee(rhs); }
212
#endif
213

214
#ifdef ADAPTER_POSIT_AND_INTEGER
215
        // convenience assignment operator 
216
        template<unsigned nbits, unsigned es>
217
        integer& operator=(const posit<nbits, es>& rhs) {
218
                convert_p2i(rhs, *this);
219
                return *this;
220
        }
221
#endif // ADAPTER_POSIT_AND_INTEGER
222

223
        // prefix operators
224
        constexpr integer operator-() const {
666,721✔
225
                integer negated(*this);
666,721✔
226
                negated.flip();
666,721✔
227
                negated += 1;
666,721✔
228
                return negated;
666,721✔
229
        }
230
        // one's complement
231
        constexpr integer operator~() const {
232
                integer complement(*this);
233
                complement.flip();
234
                return complement;
235
        }
236
        // increment
237
        constexpr integer operator++(int) {
238
                integer tmp(*this);
239
                operator++();
240
                return tmp;
241
        }
242
        constexpr integer& operator++() {
22,510,197✔
243
                *this += integer(1);
22,510,197✔
244
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
22,510,197✔
245
                return *this;
22,510,197✔
246
        }
247
        // decrement
248
        constexpr integer operator--(int) {
249
                integer tmp(*this);
250
                operator--();
251
                return tmp;
252
        }
253
        constexpr integer& operator--() {
594✔
254
                *this -= integer(1);
594✔
255
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
594✔
256
                return *this;
594✔
257
        }
258

259
        // conversion operators
260
        explicit operator unsigned char()      const noexcept { return to_unsigned_integer<unsigned char>(); }
12✔
261
        explicit operator unsigned short()     const noexcept { return to_unsigned_integer<unsigned short>(); }
12✔
262
        explicit operator unsigned int()       const noexcept { return to_unsigned_integer<unsigned int>(); }
12✔
263
        explicit operator unsigned long()      const noexcept { return to_unsigned_integer<unsigned long>(); }
12✔
264
        explicit operator unsigned long long() const noexcept { return to_unsigned_integer<unsigned long long>(); }
265
        explicit operator signed char()        const noexcept { return to_integer<signed char>(); }
12✔
266
        explicit operator short()              const noexcept { return to_integer<short>(); }
12✔
267
        explicit operator int()                const noexcept { return to_integer<int>(); }
14✔
268
        explicit operator long()               const noexcept { return to_integer<long>(); }
2,341,083✔
269
        explicit operator long long()          const noexcept { return to_integer<long long>(); }
512✔
270
        explicit operator float()              const noexcept { return to_real<float>(); }
271
        explicit operator double()             const noexcept { return to_real<double>(); }
765✔
272
#if LONG_DOUBLE_SUPPORT
273
        explicit operator long double()        const noexcept { return to_real<long double>(); }
274
#endif
275

276
        // arithmetic operators
277
        integer& operator+=(const integer& rhs) {
51,191,828✔
278
                if constexpr (nrBlocks == 1) {
279
                        _block[0] = static_cast<bt>(_block[0] + rhs.block(0));
34,957,333✔
280
                        // null any leading bits that fall outside of nbits
281
                        _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
34,957,333✔
282
                }
283
                else if constexpr (bitsInBlock == 64) {
284
                        // uint64_t limbs: use carry-detection intrinsics
285
                        integer<nbits, BlockType, NumberType> sum;
286
                        uint64_t carry = 0;
1,165,988✔
287
                        for (unsigned i = 0; i < nrBlocks; ++i) {
20,987,384✔
288
                                sum._block[i] = addcarry(_block[i], rhs._block[i], carry, carry);
19,821,396✔
289
                        }
290
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
291
                        sum._block[MSU] = static_cast<bt>(MSU_MASK & sum._block[MSU]);
1,165,988✔
292
                        *this = sum;
1,165,988✔
293
                }
294
                else {
295
                        integer<nbits, BlockType, NumberType> sum;
296
                        std::uint64_t carry = 0;
15,068,507✔
297
                        BlockType* pA = _block;
15,068,507✔
298
                        BlockType const* pB = rhs._block;
15,068,507✔
299
                        BlockType* pC = sum._block;
15,068,507✔
300
                        BlockType* pEnd = pC + nrBlocks;
15,068,507✔
301
                        while (pC != pEnd) {
103,076,777✔
302
                                carry += static_cast<std::uint64_t>(*pA) + static_cast<std::uint64_t>(*pB);
88,008,270✔
303
                                *pC = static_cast<bt>(carry);
88,008,270✔
304
                                carry >>= bitsInBlock;
88,008,270✔
305
                                ++pA; ++pB; ++pC;
88,008,270✔
306
                        }
307
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
308
                        BlockType* pLast = pEnd - 1;
15,068,507✔
309
                        *pLast = static_cast<bt>(MSU_MASK & *pLast);
15,068,507✔
310
        #if INTEGER_THROW_ARITHMETIC_EXCEPTION
311
                        // TODO: what is the real overflow condition?
312
                        // it is not carry == 1 as  say 1 + -1 sets the carry but is 0
313
                //                if (carry) throw integer_overflow();
314
        #endif
315
                        *this = sum;
15,068,507✔
316
                }
317
                return *this;
51,191,828✔
318
        }
319
        integer& operator-=(const integer& rhs) {
19,002,861✔
320
                if constexpr (NumberType == WholeNumber) {
321
                        if (*this < rhs) {
1✔
322
                                throw integer_wholenumber_cannot_be_negative{};
1✔
323
                        }
324
                        if (*this == rhs) {
×
325
                                throw integer_wholenumber_cannot_be_zero{};
×
326
                        }
327
                        std::cerr << "subtractor for WholeNumbers TBD\n";
×
328
                }
329
                else if constexpr (NumberType == NaturalNumber) {
330
                        if (*this < rhs) {
1✔
331
                                throw integer_wholenumber_cannot_be_negative{};
1✔
332
                        }
333
                        std::cerr << "subtractor for NaturalNumbers TBD\n";
×
334
                }
335
                else {
336
                        integer twos(rhs);
19,002,859✔
337
                        operator+=(twos.twosComplement());
19,002,859✔
338
                }
339
                return *this;
19,002,859✔
340
        }
341
        integer& operator*=(const integer& rhs) {
3,220,564✔
342
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
343
                        if constexpr (nrBlocks == 1) {
344
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
3,215,852✔
345
                        }
346
                        else if constexpr (bitsInBlock == 64) {
347
                                // uint64_t limbs: use mul128/addcarry intrinsics
348
                                integer<nbits + 1, BlockType, NumberType> base(*this);
200✔
349
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
200✔
350
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
200✔
351
                                if (base.isneg()) {
200✔
352
                                        base.twosComplement();
×
353
                                }
354
                                if (multiplicant.isneg()) {
200✔
355
                                        multiplicant.twosComplement();
×
356
                                }
357
                                clear();
200✔
358
                                for (unsigned i = 0; i < nrBlocks; ++i) {
3,400✔
359
                                        uint64_t carry = 0;
3,200✔
360
                                        for (unsigned j = 0; j < nrBlocks; ++j) {
54,400✔
361
                                                if (i + j < nrBlocks) {
51,200✔
362
                                                        uint64_t lo, hi;
363
                                                        mul128(base.block(i), multiplicant.block(j), lo, hi);
27,200✔
364
                                                        uint64_t c1 = 0;
27,200✔
365
                                                        uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
27,200✔
366
                                                        _block[i + j] = sum;
27,200✔
367
                                                        carry = hi + c1;
27,200✔
368
                                                }
369
                                        }
370
                                }
371
                                if (resultIsNeg) twosComplement();
200✔
372
                        }
373
                        else {
374
                                // is there a better way than upconverting to deal with maxneg in a 2's complement encoding?
375
                                integer<nbits + 1, BlockType, NumberType> base(*this);
4,512✔
376
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
4,512✔
377
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
4,512✔
378
                                if (base.isneg()) {
4,512✔
379
                                        base.twosComplement();
×
380
                                }
381
                                if (multiplicant.isneg()) {
4,512✔
382
                                        multiplicant.twosComplement();
×
383
                                }
384
                                clear();
4,512✔
385
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
39,473✔
386
                                        std::uint64_t segment(0);
34,961✔
387
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
427,376✔
388
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
392,415✔
389

390
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
392,415✔
391
                                                        segment += _block[i + j];
213,688✔
392
                                                        _block[i + j] = static_cast<bt>(segment);
213,688✔
393
                                                        segment >>= bitsInBlock;
213,688✔
394
                                                }
395
                                        }
396
                                }
397
                                if (resultIsNeg) twosComplement();
4,512✔
398
                        }
399
                }
400
                else {  // whole and natural numbers are closed under multiplication (modulo)
401
                        if constexpr (nrBlocks == 1) {
402
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
403
                        }
404
                        else if constexpr (bitsInBlock == 64) {
405
                                // uint64_t limbs: use mul128/addcarry intrinsics
406
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
407
                                clear();
408
                                for (unsigned i = 0; i < nrBlocks; ++i) {
409
                                        uint64_t carry = 0;
410
                                        for (unsigned j = 0; j < nrBlocks; ++j) {
411
                                                if (i + j < nrBlocks) {
412
                                                        uint64_t lo, hi;
413
                                                        mul128(base.block(i), multiplicant.block(j), lo, hi);
414
                                                        uint64_t c1 = 0;
415
                                                        uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
416
                                                        _block[i + j] = sum;
417
                                                        carry = hi + c1;
418
                                                }
419
                                        }
420
                                }
421
                        }
422
                        else {
423
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
424
                                clear();
425
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
426
                                        std::uint64_t segment(0);
427
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
428
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
429

430
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
431
                                                        segment += _block[i + j];
432
                                                        _block[i + j] = static_cast<bt>(segment);
433
                                                        segment >>= bitsInBlock;
434
                                                }
435
                                        }
436
                                }
437
                        }
438
                }
439
                // null any leading bits that fall outside of nbits
440
                _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
3,220,564✔
441
                return *this;
3,220,564✔
442
        }
443
        integer& operator*=(const BlockType& scale) noexcept {
169✔
444
                if constexpr (bitsInBlock == 64) {
445
                        // uint64_t limbs: use mul128/addcarry intrinsics
446
                        uint64_t carry = 0;
447
                        for (unsigned i = 0; i < nrBlocks; ++i) {
448
                                uint64_t lo, hi;
449
                                mul128(_block[i], static_cast<uint64_t>(scale), lo, hi);
450
                                uint64_t c1 = 0;
451
                                _block[i] = addcarry(lo, carry, uint64_t(0), c1);
452
                                carry = hi + c1;
453
                        }
454
                }
455
                else {
456
                        std::uint64_t scaleFactor(scale), segment(0);
169✔
457
                        for (unsigned i = 0; i < nrBlocks; ++i) {
1,049✔
458
                                segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
880✔
459
                                _block[i] = static_cast<BlockType>(segment);
880✔
460
                                segment >>= bitsInBlock;
880✔
461
                        }
462
                }
463
                return *this;
169✔
464
        }
465
        integer& operator/=(const integer& rhs) {
4,847,727✔
466
                if constexpr (EXACT_FIT && 1 == nrBlocks) {
467
                        if (rhs._block[0] == 0) {
3,215,159✔
468
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
469
                                throw integer_divide_by_zero{};
257✔
470
#else
471
                                std::cerr << "integer_divide_by_zero\n";
×
472
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
473
                        }
474
                        if constexpr (NumberType == WholeNumber) {
475
                                if (*this < rhs) {
1✔
476
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
477
                                        throw integer_wholenumber_cannot_be_zero{};
1✔
478
#else
479
                                        std::cerr << "whole number cannot be zero but division would yield 0\n";
480
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
481
                                }
482
                        }
483
                        if constexpr (sizeof(BlockType) == 1) {
484
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) / std::int8_t(rhs._block[0]));
1,117,748✔
485
                        }
486
                        else if constexpr (sizeof(BlockType) == 2) {
487
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) / std::int16_t(rhs._block[0]));
1,048,577✔
488
                        }
489
                        else if constexpr (sizeof(BlockType) == 4) {
490
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) / std::int32_t(rhs._block[0]));
524,288✔
491
                        }
492
                        else if constexpr (sizeof(BlockType) == 8) {
493
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) / std::int64_t(rhs._block[0]));                
524,288✔
494
                        }
495
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,214,901✔
496
                }
497
                else {
498
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
1,632,568✔
499
                        *this = divresult.quot;
1,631,464✔
500
                }
501
                return *this;
4,846,365✔
502
        }
503
        integer& operator%=(const integer& rhs) {
3,270,893✔
504
                if constexpr (nbits == (sizeof(BlockType) * 8)) {
505
                        if (rhs._block[0] == 0) {
3,211,264✔
506
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
507
                                throw integer_divide_by_zero{};
256✔
508
#else
509
                                std::cerr << "integer_divide_by_zero\n";
×
510
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
511
                        }
512
                        if constexpr (sizeof(BlockType) == 1) {
513
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) % std::int8_t(rhs._block[0]));
1,113,856✔
514
                        }
515
                        else if constexpr (sizeof(BlockType) == 2) {
516
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) % std::int16_t(rhs._block[0]));
1,048,576✔
517
                        }
518
                        else if constexpr (sizeof(BlockType) == 4) {
519
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) % std::int32_t(rhs._block[0]));
524,288✔
520
                        }
521
                        else if constexpr (sizeof(BlockType) == 8) {
522
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) % std::int64_t(rhs._block[0]));
524,288✔
523
                        }
524
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,211,008✔
525
                }
526
                else {
527
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
59,629✔
528
                        *this = divresult.rem;
59,549✔
529
                }
530

531
                return *this;
3,270,557✔
532
        }
533

534
        // arithmetic shift right operator
535
        integer& operator<<=(int bitsToShift) {
1,417,593✔
536
                if (bitsToShift == 0) return *this;
1,417,593✔
537
                if (bitsToShift < 0) return operator>>=(-bitsToShift);
277,817✔
538
                if (bitsToShift > static_cast<int>(nbits)) {
277,777✔
539
                        setzero();
×
540
                        return *this;
×
541
                }
542
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
277,777✔
543
                        int blockShift = bitsToShift / static_cast<int>(bitsInBlock);
92,380✔
544
                        for (int i = static_cast<int>(MSU); i >= blockShift; --i) {
679,501✔
545
                                _block[i] = bt(_block[i - blockShift]);
587,121✔
546
                        }
547
                        for (int i = blockShift - 1; i >= 0; --i) {
291,752✔
548
                                _block[i] = bt(0);
199,372✔
549
                        }
550
                        // adjust the shift
551
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
92,380✔
552
                        if (bitsToShift == 0) {
92,380✔
553
                                _block[MSU] &= MSU_MASK;
5,391✔
554
                                return *this;
5,391✔
555
                        }
556
                }
557
                if constexpr (MSU > 0) {
558
                        // construct the mask for the upper bits in the block that needs to move to the higher word
559
                        bt mask = 0xFFFFFFFFFFFFFFFFull << (bitsInBlock - bitsToShift);
182,725✔
560
                        for (unsigned i = MSU; i > 0; --i) {
1,015,679✔
561
                                _block[i] <<= bitsToShift;
832,954✔
562
                                // mix in the bits from the right
563
                                bt bits = bt(mask & _block[i - 1]);
832,954✔
564
                                _block[i] |= (bits >> (bitsInBlock - bitsToShift));
832,954✔
565
                        }
566
                }
567
                _block[0] <<= bitsToShift;        
272,386✔
568
                _block[MSU] &= MSU_MASK; // null any leading bits that fall outside of nbits
272,386✔
569
                return *this;
272,386✔
570
        }
571
        integer& operator>>=(int bitsToShift) {
4,149,938✔
572
                if (bitsToShift == 0) return *this;
4,149,938✔
573
                if (bitsToShift < 0) return operator<<=(-bitsToShift);
4,149,934✔
574
                if (bitsToShift >= static_cast<int>(nbits)) {
4,149,934✔
575
                        setzero();
4✔
576
                        return *this;
4✔
577
                }
578
                bool signext = sign();
4,149,930✔
579
                unsigned blockShift = 0;
4,149,930✔
580
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
4,149,930✔
581
                        blockShift = bitsToShift / bitsInBlock;
40✔
582
                        if (MSU >= blockShift) {
40✔
583
                                // shift by blocks
584
                                for (unsigned i = 0; i <= MSU - blockShift; ++i) {
136✔
585
                                        _block[i] = bt(_block[i + blockShift]);
96✔
586
                                }
587
                        }
588
                        // adjust the shift
589
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
40✔
590
                        if (bitsToShift == 0) {
40✔
591
                                // fix up the leading zeros if we have a negative number
592
                                if (signext) {
7✔
593
                                        // bitsToShift is guaranteed to be less than nbits
594
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
7✔
595
                                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
119✔
596
                                                setbit(i);
112✔
597
                                        }
598
                                }
599
                                else {
600
                                        // clean up the blocks we have shifted clean
601
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
×
602
                                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
×
603
                                                setbit(i, false);
×
604
                                        }
605
                                }
606
                                return *this;
7✔
607
                        }
608
                }
609
                if constexpr (MSU > 0) {
610
                        bt mask = ALL_ONES;
3,317,802✔
611
                        mask >>= (bitsInBlock - bitsToShift); // this is a mask for the lower bits in the block that need to move to the lower word
3,317,802✔
612
                        for (unsigned i = 0; i < MSU; ++i) {  // TODO: can this be improved? we should not have to work on the upper blocks in case we block shifted
29,083,405✔
613
                                _block[i] >>= bitsToShift;
25,765,603✔
614
                                // mix in the bits from the left
615
                                bt bits = bt(mask & _block[i + 1]);
25,765,603✔
616
                                _block[i] |= (bits << (bitsInBlock - bitsToShift));
25,765,603✔
617
                        }
618
                }
619
                _block[MSU] >>= bitsToShift;
4,149,923✔
620

621
                // fix up the leading zeros if we have a negative number
622
                if (signext) {
4,149,923✔
623
                        // bitsToShift is guaranteed to be less than nbits
624
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
61✔
625
                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
742✔
626
                                setbit(i);
681✔
627
                        }
628
                }
629
                else {
630
                        // clean up the blocks we have shifted clean
631
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
4,149,862✔
632
                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
8,300,018✔
633
                                setbit(i, false);
4,150,156✔
634
                        }
635
                }
636

637
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
638
                _block[MSU] &= MSU_MASK;
4,149,923✔
639
                return *this;
4,149,923✔
640
        }
641
        integer& logicShiftRight(int shift) {
6✔
642
                if (shift == 0) return *this;
6✔
643
                if (shift < 0) {
6✔
644
                        return operator<<=(-shift);
×
645
                }
646
                if (nbits <= unsigned(shift)) {
6✔
647
                        clear();
×
648
                        return *this;
×
649
                }
650
                integer<nbits, BlockType, NumberType> target{};
6✔
651
                for (int i = nbits - 1; i >= shift; --i) {  // TODO: inefficient as it works at the bit level
6,144✔
652
                        target.setbit(static_cast<unsigned>(i - shift), at(static_cast<unsigned>(i)));
6,138✔
653
                }
654
                *this = target;
6✔
655
                return *this;
6✔
656
        }
657
        integer& operator&=(const integer& rhs) {
658
                for (unsigned i = 0; i < nrBlocks; ++i) {
659
                        _block[i] &= rhs._block[i];
660
                }
661
                _block[MSU] &= MSU_MASK;
662
                return *this;
663
        }
664
        integer& operator|=(const integer& rhs) {
665
                for (unsigned i = 0; i < nrBlocks; ++i) {
666
                        _block[i] |= rhs._block[i];
667
                }
668
                _block[MSU] &= MSU_MASK;
669
                return *this;
670
        }
671
        integer& operator^=(const integer& rhs) {
672
                for (unsigned i = 0; i < nrBlocks; ++i) {
673
                        _block[i] ^= rhs._block[i];
674
                }
675
                _block[MSU] &= MSU_MASK;
676
                return *this;
677
        }
678

679
        // modifiers
680
        constexpr void clear() noexcept { 
36,757,172✔
681
                bt* p = _block;
36,757,172✔
682
                if constexpr (0 == nrBlocks) {
683
                        return;
684
                }
685
                else if constexpr (1 == nrBlocks) {
686
                        *p = bt(0);
21,214,670✔
687
                }
688
                else if constexpr (2 == nrBlocks) {
689
                        *p++ = bt(0);
10,192,506✔
690
                        *p = bt(0);
10,192,506✔
691
                }
692
                else if constexpr (3 == nrBlocks) {
693
                        *p++ = bt(0);
88,435✔
694
                        *p++ = bt(0);
88,435✔
695
                        *p   = bt(0);
88,435✔
696
                }
697
                else if constexpr (4 == nrBlocks) {
698
                        *p++ = bt(0);
222,085✔
699
                        *p++ = bt(0);
222,085✔
700
                        *p++ = bt(0);
222,085✔
701
                        *p   = bt(0);
222,085✔
702
                }
703
                else {
704
                        for (unsigned i = 0; i < nrBlocks; ++i) {
62,582,633✔
705
                                *p++ = bt(0);
57,543,157✔
706
                        }
707
                }
708
        }
36,757,172✔
709
        constexpr void setzero() noexcept { clear(); }
5✔
710
        constexpr integer& maxpos() noexcept {
1✔
711
                clear();
1✔
712
                setbit(nbits - 1ull, true);
1✔
713
                flip();
1✔
714
                return *this;
1✔
715
        }
716
        constexpr integer& minpos() noexcept {
1✔
717
                clear();
1✔
718
                setbit(0, true);
1✔
719
                return *this;
1✔
720
        }
721
        constexpr integer& zero() noexcept {
722
                clear();
723
                return *this;
724
        }
725
        constexpr integer& minneg() noexcept {
1✔
726
                clear();
1✔
727
                flip();
1✔
728
                return *this;
1✔
729
        }
730
        constexpr integer& maxneg() noexcept {
1✔
731
                clear();
1✔
732
                setbit(nbits - 1ull, true);
1✔
733
                return *this;
1✔
734
        }
735
        constexpr void setbit(unsigned i, bool v = true) noexcept {
40,617,910✔
736
                unsigned blockIndex = i / bitsInBlock;
40,617,910✔
737
                if (blockIndex < nrBlocks) {
40,617,910✔
738
                        bt block = _block[blockIndex];
40,617,910✔
739
                        bt null = ~(1ull << (i % bitsInBlock));
40,617,910✔
740
                        bt bit = bt(v ? 1 : 0);
40,617,910✔
741
                        bt mask = bt(bit << (i % bitsInBlock));
40,617,910✔
742
                        _block[blockIndex] = bt((block & null) | mask);
40,617,910✔
743
                }
744
                // nop if out of bounds
745
        }
40,617,910✔
746
        constexpr void setbyte(unsigned byteIndex, uint8_t data) {
232✔
747
                uint8_t mask = 0x1u;
232✔
748
                unsigned start = byteIndex * 8;
232✔
749
                unsigned end = start + 8;
232✔
750
                for (unsigned i = start; i < end; ++i) {
2,088✔
751
                        setbit(i, static_cast<bool>(mask & data));
1,856✔
752
                        mask <<= 1;
1,856✔
753
                }
754
        }
232✔
755
        constexpr void setblock(unsigned i, bt value) noexcept {
11✔
756
                if (i < nrBlocks) _block[i] = value;
11✔
757
        }
11✔
758
        // use un-interpreted raw bits to set the bits of the integer
759
        constexpr integer& setbits(uint64_t raw_bits) noexcept {
2,341,238✔
760
                if constexpr (0 == nrBlocks) {
761
                        return *this;
762
                }
763
                else if constexpr (1 == nrBlocks) {
764
                        _block[0] = raw_bits & storageMask;
1,290,434✔
765
                }
766
                else if constexpr (2 == nrBlocks) {
767
                        if constexpr (bitsInBlock < 64) {
768
                                _block[0] = raw_bits & storageMask;
1,050,640✔
769
                                raw_bits >>= bitsInBlock;
1,050,640✔
770
                                _block[1] = raw_bits & storageMask;
1,050,640✔
771
                        }
772
                        else {
773
                                _block[0] = raw_bits & storageMask;
774
                                _block[1] = 0;
775
                        }
776
                }
777
                else if constexpr (3 == nrBlocks) {
778
                        if constexpr (bitsInBlock < 64) {
779
                                _block[0] = raw_bits & storageMask;
20✔
780
                                raw_bits >>= bitsInBlock;
20✔
781
                                _block[1] = raw_bits & storageMask;
20✔
782
                                raw_bits >>= bitsInBlock;
20✔
783
                                _block[2] = raw_bits & storageMask;
20✔
784
                        }
785
                        else {
786
                                _block[0] = raw_bits & storageMask;
787
                                _block[1] = 0;
788
                                _block[2] = 0;
789
                        }
790
                }
791
                else if constexpr (4 == nrBlocks) {
792
                        if constexpr (bitsInBlock < 64) {
793
                                _block[0] = raw_bits & storageMask;
3✔
794
                                raw_bits >>= bitsInBlock;
3✔
795
                                _block[1] = raw_bits & storageMask;
3✔
796
                                raw_bits >>= bitsInBlock;
3✔
797
                                _block[2] = raw_bits & storageMask;
3✔
798
                                raw_bits >>= bitsInBlock;
3✔
799
                                _block[3] = raw_bits & storageMask;
3✔
800
                        }
801
                        else {
802
                                _block[0] = raw_bits & storageMask;
803
                                _block[1] = 0;
804
                                _block[2] = 0;
805
                                _block[3] = 0;
806
                        }
807
                }
808
                else {
809
                        if constexpr (bitsInBlock < 64) {
810
                                for (unsigned i = 0; i < nrBlocks; ++i) {
1,047✔
811
                                        _block[i] = raw_bits & storageMask;
906✔
812
                                        raw_bits >>= bitsInBlock;
906✔
813
                                }
814
                        }
815
                        else {
816
                                _block[0] = raw_bits & storageMask;
817
                                for (unsigned i = 1; i < nrBlocks; ++i) {
818
                                        _block[i] = 0;
819
                                }
820
                        }
821
                }
822
                _block[MSU] &= MSU_MASK; // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
2,341,238✔
823
                return *this;
2,341,238✔
824
        }
825
        integer& assign(const std::string& txt) noexcept {
19✔
826
                if (!parse(txt, *this)) {
19✔
827
                        std::cerr << "Unable to parse: " << txt << std::endl;
×
828
                }
829
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
830
                _block[MSU] = static_cast<BlockType>(MSU_MASK & _block[MSU]);
19✔
831
                return *this;
19✔
832
        }
833
        // pure bit copy of source integer, no sign extension
834
        template<unsigned src_nbits>
835
        constexpr void bitcopy(const integer<src_nbits, BlockType, NumberType>& src) noexcept {
5,336,049✔
836
                // no need to clear as we are going to overwrite all blocks
837
                for (unsigned i = 0; i < nrBlocks; ++i) { // use nrBlocks of receiver even when src is smaller, src.block() will return 0 for blocks it doesn't have, nulling the receiver's blocks
15,902,423✔
838
                        _block[i] = src.block(i);
10,566,374✔
839
                }
840
                _block[MSU] &= MSU_MASK; // assert precondition of properly nulled leading non-bits
5,336,049✔
841
        }
5,336,049✔
842
        // in-place one's complement
843
        constexpr integer& flip() {
20,130,453✔
844
                for (unsigned i = 0; i < nrBlocks; ++i) {
85,363,369✔
845
                        _block[i] = static_cast<bt>(~_block[i]);
65,232,916✔
846
                }
847
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
20,130,453✔
848
                return *this;
20,130,453✔
849
        }
850
        // in-place 2's complement
851
        constexpr integer& twosComplement() {
19,330,329✔
852
                flip();
19,330,329✔
853
                return ++(*this);
19,330,329✔
854
        }
855

856
        // selectors
857
        constexpr bool iszero() const noexcept {
5,247,696✔
858
                for (unsigned i = 0; i < nrBlocks; ++i) {
5,298,507✔
859
                        if (_block[i] != 0) return false;
5,282,130✔
860
                }
861
                return true;
16,377✔
862
        }
863
        constexpr bool ispos()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this > 0; else return true; }
864
        constexpr bool isneg()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this < 0; else return false; }
1,442,149✔
865
        constexpr bool isone()  const noexcept {
305✔
866
                for (unsigned i = 0; i < nrBlocks; ++i) {
307✔
867
                        if (i == 0) {
305✔
868
                                if (_block[0] != BlockType(1u)) return false;
305✔
869
                        }
870
                        else {
871
                                if (_block[i] != BlockType(0u)) return false;
×
872
                        }
873
                }
874
                return true;
2✔
875
        }
876
        constexpr bool isodd()  const noexcept  { return bool(_block[0] & 0x01); }
118✔
877
        constexpr bool iseven() const noexcept { return !isodd(); }
112✔
878
        constexpr bool sign()   const noexcept { return at(nbits - 1); }
34,204,096✔
879
        constexpr bool at(unsigned bitIndex) const noexcept {
34,273,872✔
880
                if (bitIndex < nbits) {
34,273,872✔
881
                        bt word = _block[bitIndex / bitsInBlock];
34,273,872✔
882
                        bt mask = bt(1ull << (bitIndex % bitsInBlock));
34,273,872✔
883
                        return (word & mask);
34,273,872✔
884
                }
885
                return false;
×
886
        }
887
        constexpr bool test(unsigned i)  const noexcept { return at(i); }
10✔
888
        constexpr bt   block(unsigned i) const noexcept { if (i < nrBlocks) return _block[i]; else return bt(0u); }
50,385,922✔
889
        constexpr uint8_t nibble(unsigned n) const noexcept {
×
890
                if (n < (1 + ((nbits - 1) >> 2))) {
×
891
                        bt word = _block[(n * 4) / bitsInBlock];
×
892
                        int nibbleIndexInWord = int(n % (bitsInBlock >> 2ull));
×
893
                        bt mask = bt(0xF << (nibbleIndexInWord * 4));
×
894
                        bt nibblebits = bt(mask & word);
×
895
                        return uint8_t(nibblebits >> (nibbleIndexInWord * 4));
×
896
                }
897
                return 0;
×
898
        }
899
        // normalize: decompose integer value into a blocktriple<nbits-1, REP> for quire accumulation
900
        template<typename TargetBlockType = BlockType>
901
        void normalize(blocktriple<nbits - 1, BlockTripleOperator::REP, TargetBlockType>& tgt) const {
902
                if (iszero()) { tgt.setzero(); return; }
903
                tgt.setzero();
904
                tgt.setnormal();
905
                // For WholeNumber/NaturalNumber, sign() returns the raw MSB which is a data bit,
906
                // not a sign indicator. Only IntegerNumber has a true sign bit.
907
                const bool negative = (NumberType == IntegerNumberType::IntegerNumber) && sign();
908
                tgt.setsign(negative);
909
                // get magnitude
910
                integer mag = negative ? -(*this) : *this;
911
                signed msb = findMsb(mag);
912
                tgt.setscale(msb);  // integer: scale = position of MSB
913
                // copy magnitude bits into significand
914
                constexpr unsigned f = nbits - 1;
915
                tgt.setbit(f);  // hidden bit
916
                for (signed i = msb - 1; i >= 0 && (msb - 1 - i) < static_cast<signed>(f); --i) {
917
                        tgt.setbit(static_cast<unsigned>(f - 1 - (msb - 1 - i)), mag.at(static_cast<unsigned>(i)));
918
                }
919
        }
920

921
        // operators
922
        // reduce returns the ratio and remainder of a and b in *this and r
923
        void reduce(const integer& a, const integer& b, integer& r) {
594,176✔
924
                if (b.iszero()) {
594,176✔
925
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
926
                        throw integer_divide_by_zero{};
1,360✔
927
#else
928
                        std::cerr << "integer_divide_by_zero\n";
929
                        return;
930
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
931
                }
932

933
                if (a.iszero()) {
592,816✔
934
                        clear();
1,355✔
935
                        r.clear();
1,355✔
936
                        return;
1,355✔
937
                }
938
                if constexpr (nrBlocks == 1) { // completely reduce this to native div and rem
939
                        BlockType _a = a._block[0];
330,340✔
940
                        BlockType _b = b._block[0];
330,340✔
941
                        if constexpr (NumberType == IntegerNumber) {
942
                                bool sign_a = _a & SIGN_BIT_MASK;
330,340✔
943
                                bool sign_b = _b & SIGN_BIT_MASK;
330,340✔
944
                                if constexpr (8 == bitsInBlock) {
945
                                        std::int8_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
69,219✔
946
                                        std::int8_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
69,219✔
947
                                        *this = static_cast<BlockType>(a0 / b0);
69,219✔
948
                                        r = static_cast<BlockType>(a0 % b0);
69,219✔
949
                                }
950
                                else if constexpr (16 == bitsInBlock) {
951
                                        std::int16_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
261,121✔
952
                                        std::int16_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
261,121✔
953
                                        *this = static_cast<BlockType>(a0 / b0);
261,121✔
954
                                        r = static_cast<BlockType>(a0 % b0);
261,121✔
955
                                }
956
                                else if constexpr (32 == bitsInBlock) {
957
                                        std::int32_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
958
                                        std::int32_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
959
                                        *this = static_cast<BlockType>(a0 / b0);
960
                                        r = static_cast<BlockType>(a0 % b0);
961
                                }
962
                                else {
963
                                        std::int64_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
964
                                        std::int64_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
965
                                        *this = static_cast<BlockType>(a0 / b0);
966
                                        r = static_cast<BlockType>(a0 % b0);
967
                                }
968
                        }
969
                        else {
970
                                *this = static_cast<BlockType>(_a / _b);
971
                                r = static_cast<BlockType>(_a % _b);
972
                        }
973
                }
974
                else {
975
                        clear();
261,121✔
976
                        // no need to constexpr guard this for IntegerNumber as sign() will return false for Whole and Natural Numbers
977
                        bool sign_a = a.sign();
261,121✔
978
                        bool sign_b = b.sign();
261,121✔
979
                        bool sign_q = sign_a ^ sign_b;
261,121✔
980
                        using Integer = integer<nbits+1, BlockType, NumberType>; // nbits+1 to deal with maxneg
981
                        Integer _a(a), _b(b);
261,121✔
982
                        if (sign_a) _a.twosComplement();
261,121✔
983
                        if (sign_b) _b.twosComplement();                        
261,121✔
984
                        
985
                        // filter out the easy stuff
986
                        if (_a < _b) { r = a; clear(); return; }
392,191✔
987

988
                        // determine first non-zero limbs
989
                        unsigned m{ 0 }, n{ 0 };
131,071✔
990
                        for (unsigned i = nrBlocks; i > 0; --i) {
261,631✔
991
                                if (_a.block(i - 1) != 0) {
261,631✔
992
                                        m = static_cast<unsigned>(i);
131,071✔
993
                                        break;
131,071✔
994
                                }
995
                        }
996
                        for (unsigned i = nrBlocks; i > 0; --i) {
262,141✔
997
                                if (_b.block(i - 1) != 0) {
262,141✔
998
                                        n = static_cast<unsigned>(i);
131,071✔
999
                                        break;
131,071✔
1000
                                }
1001
                        }
1002

1003
                        // single limb divisor
1004
                        if (n == 1) {
131,071✔
1005
                                std::uint64_t remainder{ 0 };
131,070✔
1006
                                auto divisor = _b.block(0);
131,070✔
1007
                                for (unsigned j = m; j > 0; --j) {
262,650✔
1008
                                        std::uint64_t dividend = remainder * BASE + _a.block(j - 1);
131,580✔
1009
                                        std::uint64_t limbQuotient = dividend / divisor;
131,580✔
1010
                                        _block[j - 1] = static_cast<BlockType>(limbQuotient);
131,580✔
1011
                                        remainder = dividend - limbQuotient * divisor;
131,580✔
1012
                                }
1013
                                r._block[0] = static_cast<BlockType>(remainder);
131,070✔
1014
                                if (sign_q) twosComplement();
131,070✔
1015
                                return;
131,070✔
1016
                        }
1017

1018
                        // Knuth's algorithm calculates a normalization factor d
1019
                        // that perfectly aligns b so that b0 >= floor(BASE/2),
1020
                        // a requirement for the relationship: (qHat - 2) <= q <= qHat
1021

1022
                        using OriginalInteger = integer<nbits, BlockType, NumberType>;
1023
                        using ExpandedInteger = integer<nbits + sizeof(BlockType) * 8, BlockType, NumberType>; // need room for overflow to receive the normalization bits
1024

1025
                        int shift = nlz(b.block(n - 1));
1✔
1026
                        ExpandedInteger normalized_a;
1027
                        normalized_a.setblock(m, static_cast<BlockType>((_a.block(m - 1) >> (bitsInBlock - shift))));
1✔
1028
                        for (unsigned i = m - 1; i > 0; --i) {
2✔
1029
                                normalized_a.setblock(i, static_cast<BlockType>((_a.block(i) << shift) | (_a.block(i - 1) >> (bitsInBlock - shift))));
1✔
1030
                        }
1031
                        normalized_a.setblock(0, static_cast<BlockType>(_a.block(0) << shift));
1✔
1032
                        // normalize b
1033
                        OriginalInteger normalized_b;
1034
                        unsigned n_minus_1 = n - 1;
1✔
1035
                        for (unsigned i = n_minus_1; i > 0; --i) {
2✔
1036
                                normalized_b.setblock(i, static_cast<BlockType>((_b.block(i) << shift) | (_b.block(i - 1) >> (bitsInBlock - shift))));
1✔
1037
                        }
1038
                        normalized_b.setblock(0, static_cast<BlockType>(_b.block(0) << shift));
1✔
1039

1040
//                        std::cout << "normalized a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1041
//                        std::cout << "normalized b :             " << normalized_b.showLimbs() << " : " << normalized_b.showLimbValues() << '\n';
1042

1043
                        // divide by limb
1044
                        std::uint64_t divisor = normalized_b._block[n - 1];
1✔
1045
                        std::uint64_t v_nminus2 = normalized_b._block[n - 2]; // n > 1 at this point
1✔
1046
                        for (int j = static_cast<int>(m - n); j >= 0; --j) {
2✔
1047
                                std::uint64_t dividend = normalized_a.block(j + n) * BASE + normalized_a.block(j + n - 1);
1✔
1048
                                std::uint64_t qhat = dividend / divisor;
1✔
1049
                                std::uint64_t rhat = dividend - qhat * divisor;
1✔
1050

1051
                                while (qhat >= BASE || qhat * v_nminus2 > BASE * rhat + normalized_a.block(j + n - 2)) {
1✔
1052
                                        --qhat;
×
1053
                                        rhat += divisor;
×
1054
                                        if (rhat < BASE) continue;
×
1055
                                }
1056
                                std::uint64_t borrow{ 0 };
1✔
1057
                                std::uint64_t diff{ 0 };
1✔
1058
                                for (unsigned i = 0; i < n; ++i) {
3✔
1059
                                        std::uint64_t p = qhat * normalized_b.block(i);
2✔
1060
                                        diff = normalized_a.block(i + j) - static_cast<BlockType>(p) - borrow;
2✔
1061
                                        normalized_a.setblock(i + j, static_cast<BlockType>(diff));
2✔
1062
                                        borrow = (p >> bitsInBlock) - (diff >> bitsInBlock);
2✔
1063
                                }
1064
                                std::int64_t signedBorrow = static_cast<int64_t>(normalized_a.block(j + n) - borrow);
1✔
1065
                                normalized_a.setblock(j + n, static_cast<BlockType>(signedBorrow));
1✔
1066

1067
//                                std::cout << "   updated a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1068

1069
                                setblock(static_cast<unsigned>(j), static_cast<BlockType>(qhat));
1✔
1070
                                if (signedBorrow < 0) { // subtracted too much, add back
1✔
1071
                                        std::cout << "subtracted too much, add back\n";
×
1072
                                        _block[j] -= 1;
×
1073
                                        std::uint64_t carry{ 0 };
×
1074
                                        for (unsigned i = 0; i < n; ++i) {
×
1075
                                                carry += static_cast<std::uint64_t>(normalized_a.block(i + j)) + static_cast<std::uint64_t>(normalized_b.block(i));
×
1076
                                                normalized_a.setblock(i + j, static_cast<BlockType>(carry));
×
1077
                                                carry >>= 32;
×
1078
                                        }
1079
                                        BlockType rectified = static_cast<BlockType>(normalized_a.block(j + n) + carry);
×
1080
                                        normalized_a.setblock(j + n, rectified);
×
1081
                                }
1082
//                                std::cout << "   updated a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1083
                        }
1084
                        if (sign_q) twosComplement();
1✔
1085

1086
                        // remainder needs to be normalized
1087
                        for (unsigned i = 0; i < n - 1; ++i) {
2✔
1088
                                std::uint64_t remainder = static_cast<uint64_t>(normalized_a.block(i) >> shift);
1✔
1089
                                remainder |= static_cast<uint64_t>(normalized_a.block(i + 1) << (32 - shift));
1✔
1090
                                r.setblock(i, static_cast<BlockType>(remainder));
1✔
1091
                        }
1092
                        r.setblock(n - 1, static_cast<BlockType>(normalized_a.block(n - 1) >> shift));
1✔
1093
                }
1094
        }
1095
        // signed integer conversion
1096
        template<typename SignedInt>
1097
        constexpr integer& convert_signed(SignedInt rhs) {
35,830,573✔
1098
                clear();
35,830,573✔
1099
                if (0 == rhs) {
35,830,573✔
1100
                        if constexpr (NumberType == WholeNumber) {
1101
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1102
                                throw integer_wholenumber_cannot_be_zero();
1✔
1103
#else
1104
                                return *this;
×
1105
#endif
1106
                        }
1107
                        else {
1108
                                return *this;
10,764,433✔
1109
                        }
1110
                }
1111
                if constexpr (NumberType == WholeNumber) {
1112
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1113
                        if (rhs < 0) throw integer_wholenumber_cannot_be_negative();
5✔
1114
#else
1115
                        if (rhs < 0) return *this;
×
1116
#endif
1117
                }
1118
                if constexpr (NumberType == NaturalNumber) {
1119
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1120
                        if (rhs < 0) throw integer_naturalnumber_cannot_be_negative();
5✔
1121
#else
1122
                        if (rhs < 0) return *this;
×
1123
#endif
1124
                }
1125

1126
                int64_t v = rhs;
25,066,137✔
1127
                for (unsigned i = 0; i < nbits && v != 0; ++i) {
58,941,016✔
1128
                        if (v & 0x1ull) setbit(i);
33,874,879✔
1129
                        v >>= 1;
33,874,879✔
1130
                }
1131
                if constexpr (nbits > 64) {
1132
                        if (rhs < 0) {        // sign extend if negative
3,619,908✔
1133
                                for (unsigned i = 64; i < nbits; ++i) {
65✔
1134
                                        setbit(i);
64✔
1135
                                }
1136
                        }
1137
                }
1138
                return *this;
25,066,137✔
1139
        }
1140
        // unsigned integer conversion
1141
        template<typename UnsignedInt>
1142
        constexpr integer& convert_unsigned(UnsignedInt rhs) {
527,150✔
1143
                clear();
527,150✔
1144
                if (0 == rhs) {
527,150✔
1145
                        if constexpr (NumberType == WholeNumber) {
1146
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1147
                                throw integer_wholenumber_cannot_be_zero();
×
1148
#else
1149
                                return *this;
×
1150
#endif
1151
                        }
1152
                        else {
1153
                                return *this;
135,900✔
1154
                        }
1155
                }
1156
                uint64_t v = rhs;
391,250✔
1157
                constexpr unsigned argbits = sizeof(rhs);
391,250✔
1158
                unsigned upper = (nbits <= _nbits ? nbits : argbits);
391,250✔
1159
                for (unsigned i = 0; i < upper; ++i) {
4,351,884✔
1160
                        if (v & 0x1ull) setbit(i);
3,960,634✔
1161
                        v >>= 1;
3,960,634✔
1162
                }
1163
                return *this;
391,250✔
1164
        }
1165
        // native IEEE-754 conversion
1166
        // TODO: currently only supports integer values of 64bits or less
1167
        template<typename Real>
1168
        constexpr integer& convert_ieee(Real rhs) noexcept {
782✔
1169
                clear();
782✔
1170
                return *this = static_cast<long long>(rhs); // TODO: this clamps the IEEE range to +-2^63
782✔
1171
        }
1172

1173
        // show the binary encodings of the limbs
1174
        std::string showLimbs() const {
1175
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1176
                std::stringstream s;
1177
                unsigned i = Integer::MSU;
1178
                while (i > 0) {
1179
                        s << to_binary(_block[i], sizeof(BlockType) * 8, true) << ' ';
1180
                        --i;
1181
                }
1182
                s << to_binary(_block[0], sizeof(BlockType) * 8, true);
1183
                return s.str();
1184
        }
1185
        // show the values of the limbs as a radix-BlockType number
1186
        std::string showLimbValues() const {
1187
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1188
                std::stringstream s;
1189
                unsigned i = Integer::MSU;
1190
                while (i > 0) {
1191
                        s << std::setw(5) << unsigned(_block[i]) << ", ";
1192
                        --i;
1193
                }
1194
                s << std::setw(5) << unsigned(_block[0]);
1195
                return s.str();
1196
        }
1197

1198
protected:
1199
        // HELPER methods
1200

1201
        // to_integer converts to native signed integer
1202
        // TODO: enable_if this for integral types only
1203
        template<typename TargetInt>
1204
        TargetInt to_integer() const noexcept {
2,341,633✔
1205
                TargetInt v{ 0 };
2,341,633✔
1206
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
2,341,633✔
1207

1208
                constexpr unsigned sizeoftarget   = 8 * sizeof(TargetInt);
2,335,028✔
1209
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
2,335,028✔
1210
                unsigned upperBlock = static_cast<unsigned>(std::min(MSU, upperTargetBlock));
2,335,028✔
1211
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1212
                        for (unsigned b = 0; b <= upperBlock; ++b) {
5,720,535✔
1213
                                std::uint64_t data = _block[b];
3,385,539✔
1214
                                v |= (data << (b * bitsInBlock));
3,385,539✔
1215
                        }
1216
                        unsigned upper = nbits;
2,334,996✔
1217
                        if (sign() && upper < sizeoftarget) { // sign extend
2,334,996✔
1218
                                uint64_t mask = (1ull << upper);
1,171,045✔
1219
                                for (unsigned i = upper; i < sizeoftarget; ++i) {
65,984,283✔
1220
                                        v |= mask;
64,813,238✔
1221
                                        mask <<= 1;
64,813,238✔
1222
                                }
1223
                        }
1224
                }
1225
                else {
1226
                        for (unsigned b = 0; b <= upperBlock; ++b) {
106✔
1227
                                std::uint64_t data = _block[b];
74✔
1228
                                v |= (data << (b * bitsInBlock));
74✔
1229
                        }
1230
                }
1231

1232
                return v;
2,335,028✔
1233
        }
1234

1235
        // to_unsigned_integer converts to native unsigned integer
1236
    // TODO: enable_if this for integral types only
1237
        template<typename TargetInt>
1238
        TargetInt to_unsigned_integer() const noexcept {
48✔
1239
                TargetInt v{ 0 };
48✔
1240
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
48✔
1241

1242
                constexpr unsigned sizeoftarget = 8 * sizeof(TargetInt);
48✔
1243
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
48✔
1244
                unsigned upperBlock = std::min(MSU, upperTargetBlock);
48✔
1245
                for (unsigned b = 0; b <= upperBlock; ++b) {
159✔
1246
                        std::uint64_t data = _block[b];
111✔
1247
                        v |= (data << (b * bitsInBlock));
111✔
1248
                }
1249

1250
                return v;
48✔
1251
        }
1252

1253
        // TODO: enable_if this for native floating-point types only
1254
        template<typename Real>
1255
        constexpr Real to_real() const noexcept {
765✔
1256
                Real r = 0.0;
765✔
1257
                Real bitValue = static_cast<Real>(1.0);
765✔
1258
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1259
                        integer<nbits + 1, bt, NumberType> v{ *this }; // deal with maxneg in 2's complement
765✔
1260
                        if (isneg()) v = -v;
765✔
1261
                        for (unsigned i = 0; i < nbits; ++i) { // upper bound is nbits + 1 - 1 == nbits
35,117✔
1262
                                if (v.at(i)) r += bitValue;
34,352✔
1263
                                bitValue *= static_cast<Real>(2.0);
34,352✔
1264
                        }
1265
                        if (isneg()) r = -r;
765✔
1266
                }
1267
                else if constexpr (NumberType == IntegerNumberType::WholeNumber) {
1268
                        for (unsigned i = 0; i < nbits; ++i) {
1269
                                if (at(i)) r += bitValue;
1270
                                bitValue *= static_cast<Real>(2.0);
1271
                        }
1272
                }
1273
                else { // NaturalNumber
1274
                        if (iszero()) std::cerr << "internal error: natural number is set to 0\n";
1275
                        for (unsigned i = 0; i < nbits; ++i) {
1276
                                if (at(i)) r += bitValue;
1277
                                bitValue *= static_cast<Real>(2.0);
1278
                        }
1279
                }
1280

1281
                return r;
765✔
1282
        }
1283

1284
private:
1285
        bt _block[nrBlocks];
1286

1287
        // convert
1288
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1289
        friend std::string convert_to_decimal_string(const integer<nnbits, BBlockType, NNumberType>& value);
1290

1291
        // integer - integer logic comparisons
1292
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1293
        friend bool operator==(const integer<nnbits, BBlockType, NNumberType>& lhs, const integer<nnbits, BBlockType, NNumberType>& rhs);
1294

1295
        // find the most significant bit set
1296
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1297
        friend signed findMsb(const integer<nnbits, BBlockType, NNumberType>& v);
1298
};
1299

1300
////////////////////////    INTEGER functions   /////////////////////////////////
1301

1302
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1303
inline integer<nbits, BlockType, NumberType> abs(const integer<nbits, BlockType, NumberType>& a) {
1304
        integer<nbits, BlockType, NumberType> b(a);
1305
        return (a >= 0 ? b : b.twosComplement());
1306
}
1307

1308
// free function to create a 1's complement copy of an integer
1309
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1310
inline integer<nbits, BlockType, NumberType> onesComplement(const integer<nbits, BlockType, NumberType>& value) {
1✔
1311
        integer<nbits, BlockType, NumberType> ones(value);
1✔
1312
        return ones.flip();
1✔
1313
}
1314
// free function to create the 2's complement of an integer
1315
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1316
inline integer<nbits, BlockType, NumberType> twosComplement(const integer<nbits, BlockType, NumberType>& value) {
43✔
1317
        integer<nbits, BlockType, NumberType> twos(value);
43✔
1318
        return twos.twosComplement();;
86✔
1319
}
1320

1321
// convert integer to decimal string
1322
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1323
std::string convert_to_decimal_string(const integer<nbits, BlockType, NumberType>& value) {
3✔
1324
        if (value.iszero()) {
3✔
1325
                return std::string("0");
×
1326
        }
1327
        integer<nbits, BlockType, NumberType> number = value.sign() ? twosComplement(value) : value;
3✔
1328
        support::decimal partial, multiplier;
3✔
1329
        partial.setzero();
3✔
1330
        multiplier.setdigit(1);
3✔
1331
        // convert integer to decimal by adding and doubling multipliers
1332
        for (unsigned i = 0; i < nbits; ++i) {
579✔
1333
                if (number.at(i)) {
576✔
1334
                        support::add(partial, multiplier);
282✔
1335
                        // std::cout << partial << std::endl;
1336
                }
1337
                support::add(multiplier, multiplier);
576✔
1338
        }
1339
        std::stringstream str;
3✔
1340
        if (value.sign()) str << '-';
3✔
1341
        for (support::decimal::const_reverse_iterator rit = partial.rbegin(); rit != partial.rend(); ++rit) {
166✔
1342
                str << (int)*rit;
163✔
1343
        }
1344
        return str.str();
3✔
1345
}
3✔
1346

1347
// findMsb takes an integer<nbits, BlockType, NumberType> reference and returns the 0-based position of the most significant bit, -1 if v == 0
1348
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1349
inline signed findMsb(const integer<nbits, BlockType, NumberType>& v) {
2,834,685✔
1350
        BlockType const* pV = v._block + v.nrBlocks - 1;
2,834,685✔
1351
        BlockType const* pLast = v._block;
2,834,685✔
1352
        BlockType BlockMsb = BlockType(BlockType(1u) << (v.bitsInBlock - 1));
2,834,685✔
1353
        signed msb = static_cast<signed>(v.nbits - 1ull); // the case for an aligned MSB
2,834,685✔
1354
        unsigned rem = nbits % v.bitsInBlock;
2,834,685✔
1355
        // we are organized little-endian
1356
        // check if the blocks are aligned with the representation
1357
        if (rem > 0) {
2,834,685✔
1358
                // the top bits are unaligned: construct the right mask
1359
                BlockType mask = BlockType(BlockType(1u) << (rem - 1u));
2,834,670✔
1360
                while (mask != 0) {
47,423,115✔
1361
                        if (*pV & mask) return msb;
45,908,520✔
1362
                        --msb;
44,588,445✔
1363
                        mask >>= 1;
44,588,445✔
1364
                }
1365
                if (msb < 0) return msb;
1,514,595✔
1366
                --pV;
1,514,589✔
1367
        }
1368
        // invariant: msb is now aligned with the blocks
1369
        // std::cout << "invariant msb : " << msb << '\n';
1370
        while (pV >= pLast) {
2,389,315✔
1371
                if (*pV != 0) {
2,389,315✔
1372
                        BlockType mask = BlockMsb;
1,514,604✔
1373
                        while (mask != 0) {
35,439,897✔
1374
                                if (*pV & mask) return msb;
35,439,897✔
1375
                                --msb;
33,925,293✔
1376
                                mask >>= 1;
33,925,293✔
1377
                        }
1378
                }
1379
                else {
1380
                        msb -= v.bitsInBlock;
874,711✔
1381
                }
1382
                --pV;
874,711✔
1383
        }
1384
        return msb; // == -1 if no significant bit found
×
1385
}
1386

1387
////////////////////////    INTEGER operators   /////////////////////////////////
1388

1389
// remainder returns a mod b in c
1390
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1391
void remainder(integer<nbits, BlockType, NumberType>& c, const integer<nbits, BlockType, NumberType>& a, const integer<nbits, BlockType, NumberType>& b) {
1392
        if (b == integer<nbits, BlockType, NumberType>(0)) {
1393
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1394
                throw integer_divide_by_zero{};
1395
#else
1396
                std::cerr << "integer_divide_by_zero\n";
1397
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1398
        }
1399
        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(a, b);
1400
        c = divresult.rem;
1401
}
1402

1403
// divide integer<nbits, BlockType, NumberType> a and b and return result argument
1404
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1405
idiv_t<nbits, BlockType, NumberType> idiv(const integer<nbits, BlockType, NumberType>& _a, const integer<nbits, BlockType, NumberType>& _b) {
1,692,197✔
1406
        if (_b.iszero()) {
1,692,197✔
1407
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1408
                throw integer_divide_by_zero{};
1,184✔
1409
#else
1410
                std::cerr << "integer_divide_by_zero\n";
×
1411
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1412
        }
1413

1414
        idiv_t<nbits, BlockType, NumberType> divresult;
1,691,013✔
1415
        divresult.rem = 0;
1,691,013✔
1416
        divresult.quot = 0;
1,691,013✔
1417

1418
        // generate the absolute values to do long division
1419
        if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1420
                using Integer = integer<nbits+1, BlockType, NumberType>;
1421
                // 2's complement special case -max requires an signed int that is 1 bit bigger to represent abs()
1422
                bool a_negative = _a.sign();
1,691,013✔
1423
                bool b_negative = _b.sign();
1,691,013✔
1424
                bool result_negative = (a_negative ^ b_negative);
1,691,013✔
1425
                Integer a; a.bitcopy(a_negative ? -_a : _a);
1,691,013✔
1426
                Integer b; b.bitcopy(b_negative ? -_b : _b);
1,691,013✔
1427

1428
                if (a < b) {
1,691,013✔
1429
                        divresult.quot = 0; // a / b = 0
273,808✔
1430
                        divresult.rem = _a; // a % b = a when a / b = 0
273,808✔
1431
                        return divresult;
273,808✔
1432
                }
1433
                // initialize the long division
1434
                integer<nbits + 1, BlockType, NumberType> accumulator = a;
1,417,205✔
1435
                // prepare the subtractand
1436
                integer<nbits + 1, BlockType, NumberType> subtractand = b;
1,417,205✔
1437
                int msb_b = findMsb(b);
1,417,205✔
1438
                int msb_a = findMsb(a);
1,417,205✔
1439
                int shift = msb_a - msb_b;
1,417,205✔
1440
                subtractand <<= shift;
1,417,205✔
1441
                divresult.quot = 0;
1,417,205✔
1442
                // long division
1443
                for (int i = shift; i >= 0; --i) {
5,557,744✔
1444
                        if (subtractand <= accumulator) {
4,140,539✔
1445
                                accumulator -= subtractand;
2,555,035✔
1446
                                divresult.quot.setbit(static_cast<unsigned>(i));
2,555,035✔
1447
                        }
1448
                        else {
1449
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
1,585,504✔
1450
                        }
1451
                        subtractand >>= 1;
4,140,539✔
1452
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1453
                }
1454
                if (result_negative) {  // take 2's complement
1,417,205✔
1455
                        divresult.quot.flip();
133,369✔
1456
                        divresult.quot += 1;
133,369✔
1457
                }
1458
                if (_a.isneg()) {
1,417,205✔
1459
                        divresult.rem = -accumulator;
133,961✔
1460
                }
1461
                else {
1462
                        divresult.rem = accumulator;
1,283,244✔
1463
                }
1464
        }
1465
        else {
1466
                if (_a < _b) {
×
1467
                        divresult.rem = _a; // a % b = a when a / b = 0
×
1468
                        return divresult; // a / b = 0 when b > a
×
1469
                }
1470
                using Integer = integer<nbits, BlockType, NumberType>;
1471
                Integer accumulator(_a), subtractand(_b);
×
1472
                int msb_b = findMsb(_b);
×
1473
                int msb_a = findMsb(_a);
×
1474
                int shift = msb_a - msb_b;
×
1475
                subtractand <<= shift;
×
1476
                // long division
1477
                for (int i = shift; i >= 0; --i) {
×
1478
                        if (subtractand <= accumulator) {
×
1479
                                accumulator -= subtractand;
×
1480
                                divresult.quot.setbit(static_cast<unsigned>(i));
×
1481
                        }
1482
                        else {
1483
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
×
1484
                        }
1485
                        subtractand >>= 1;
×
1486
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1487
                }
1488
                divresult.rem = accumulator;
×
1489
        }
1490

1491
        return divresult;
1,417,205✔
1492
}
1493

1494
/// stream operators
1495

1496
// read a integer ASCII format and make a binary integer out of it
1497
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1498
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& value) {
24✔
1499
        bool bSuccess = false;
24✔
1500
        value.clear();
24✔
1501
        // check if the txt is an integer form: [0123456789]+
1502
        std::regex decimal_regex("^[-+]*[0-9]+");
24✔
1503
        std::regex octal_regex("^[-+]*0[1-7][0-7]*$");
24✔
1504
        std::regex hex_regex("^[-+]*0[xX][0-9a-fA-F']+");
24✔
1505
        // setup associative array to map chars to nibbles
1506
        static std::map<char, int> charLookup{
38✔
1507
                { '0', 0 },
1508
                { '1', 1 },
1509
                { '2', 2 },
1510
                { '3', 3 },
1511
                { '4', 4 },
1512
                { '5', 5 },
1513
                { '6', 6 },
1514
                { '7', 7 },
1515
                { '8', 8 },
1516
                { '9', 9 },
1517
                { 'a', 10 },
1518
                { 'b', 11 },
1519
                { 'c', 12 },
1520
                { 'd', 13 },
1521
                { 'e', 14 },
1522
                { 'f', 15 },
1523
                { 'A', 10 },
1524
                { 'B', 11 },
1525
                { 'C', 12 },
1526
                { 'D', 13 },
1527
                { 'E', 14 },
1528
                { 'F', 15 },
1529
        };
1530
        if (std::regex_match(number, octal_regex)) {
24✔
1531
                std::cout << "found an octal representation\n";
×
1532
                for (std::string::const_reverse_iterator r = number.rbegin();
×
1533
                        r != number.rend();
×
1534
                        ++r) {
×
1535
                        std::cout << "char = " << *r << std::endl;
×
1536
                }
1537
                bSuccess = false; // TODO
×
1538
        }
1539
        else if (std::regex_match(number, hex_regex)) {
24✔
1540
                //std::cout << "found a hexadecimal representation\n";
1541
                // each char is a nibble
1542
                int maxByteIndex = nbits / 8;
15✔
1543
                int byte = 0;
15✔
1544
                int byteIndex = 0;
15✔
1545
                bool odd = false;
15✔
1546
                for (std::string::const_reverse_iterator r = number.rbegin();
15✔
1547
                        r != number.rend() && byteIndex < maxByteIndex;
580✔
1548
                        ++r) {
565✔
1549
                        if (*r == '\'') {
569✔
1550
                                // ignore
1551
                        }
1552
                        else if (*r == 'x' || *r == 'X') {
468✔
1553
                                if (odd) {
4✔
1554
                                        // complete the most significant byte
1555
                                        value.setbyte(static_cast<unsigned>(byteIndex), static_cast<uint8_t>(byte));
×
1556
                                }
1557
                                // check that we have [-+]0[xX] format
1558
                                ++r;
4✔
1559
                                if (r != number.rend()) {
4✔
1560
                                        if (*r == '0') {
4✔
1561
                                                // check if we have a sign
1562
                                                ++r;
4✔
1563
                                                if (r == number.rend()) {
4✔
1564
                                                        // no sign, thus by definition positive
1565
                                                        bSuccess = true;
4✔
1566
                                                }
1567
                                                else if (*r == '+') {
×
1568
                                                        // optional positive sign, no further action necessary
1569
                                                        bSuccess = true;
×
1570
                                                }
1571
                                                else if (*r == '-') {
×
1572
                                                        // negative sign, invert
1573
                                                        value = -value;
×
1574
                                                        bSuccess = true;
×
1575
                                                }
1576
                                                else {
1577
                                                        // the regex will have filtered this out
1578
                                                        return false;
×
1579
                                                }
1580
                                        }
1581
                                        else {
1582
                                                // we didn't find the obligatory '0', the regex should have filtered this out
1583
                                                return false;
×
1584
                                        }
1585
                                }
1586
                                else {
1587
                                        // we are missing the obligatory '0', the regex should have filtered this out
1588
                                        return false;
×
1589
                                }
1590
                                // we have reached the end of our parse
1591
                                break;
4✔
1592
                        }
1593
                        else {
1594
                                if (odd) {
464✔
1595
                                        byte += charLookup.at(*r) << 4;
232✔
1596
                                        value.setbyte(static_cast<unsigned>(byteIndex), static_cast<uint8_t>(byte));
232✔
1597
                                        ++byteIndex;
232✔
1598
                                }
1599
                                else {
1600
                                        byte = charLookup.at(*r);
232✔
1601
                                }
1602
                                odd = !odd;
464✔
1603
                        }
1604
                }
1605
                bSuccess = true;
15✔
1606
        }
1607
        else if (std::regex_match(number, decimal_regex)) {
9✔
1608
                //std::cout << "found a decimal integer representation\n";
1609
                integer<nbits, BlockType, NumberType> scale = 1;
9✔
1610
                for (std::string::const_reverse_iterator r = number.rbegin();
9✔
1611
                        r != number.rend();
92✔
1612
                        ++r) {
83✔
1613
                        if (*r == '-') {
83✔
1614
                                value = -value;
2✔
1615
                        }
1616
                        else if (*r == '+') {
81✔
1617
                                break;
×
1618
                        }
1619
                        else {
1620
                                integer<nbits, BlockType, NumberType> digit = charLookup.at(*r);
81✔
1621
                                value += scale * digit;
81✔
1622
                                scale *= 10;
81✔
1623
                        }
1624
                }
1625
                bSuccess = true;
9✔
1626
        }
1627

1628
        return bSuccess;
24✔
1629
}
24✔
1630

1631
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1632
std::string to_string(const integer<nbits, BlockType, NumberType>& n) {
2✔
1633
        return convert_to_decimal_string(n);
2✔
1634
}
1635

1636
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1637
std::string convert_to_string(std::ios_base::fmtflags flags, const integer<nbits, BlockType, NumberType>& n) {
4,275✔
1638
        using IntegerBase = integer<nbits, BlockType, NumberType>;
1639

1640
        // set the base of the target number system to convert to
1641
        int base = 10;
4,275✔
1642
        if ((flags & std::ios_base::oct) == std::ios_base::oct) base = 8;
4,275✔
1643
        if ((flags & std::ios_base::hex) == std::ios_base::hex) base = 16;
4,275✔
1644

1645
        std::string result;
4,275✔
1646
        if (base == 8 || base == 16) {
4,275✔
1647
                if (n.sign()) return std::string("negative value: ignored");
20✔
1648

1649
                BlockType shift = static_cast<BlockType>(base == 8 ? 3 : 4);
14✔
1650
                BlockType mask = static_cast<BlockType>((1u << shift) - 1);
14✔
1651
                IntegerBase t(n);
14✔
1652
                result.assign(nbits / shift + ((nbits % shift) ? 1 : 0), '0');
14✔
1653
                std::string::size_type pos = result.size() - 1u;
14✔
1654
                for (unsigned i = 0; i < nbits / static_cast<unsigned>(shift); ++i) {
42✔
1655
                        char c = '0' + static_cast<char>(t.block(0) & mask);
28✔
1656
                        if (c > '9')
28✔
1657
                                c += 'A' - '9' - static_cast<char>(1);
×
1658
                        result[pos--] = c;
28✔
1659
                        t >>= static_cast<int>(shift);
28✔
1660
                }
1661
                if (nbits % shift) {
14✔
1662
                        mask = static_cast<BlockType>((1u << (nbits % shift)) - 1);
7✔
1663
                        char c = '0' + static_cast<char>(t.block(0) & mask);
7✔
1664
                        if (c > '9')
7✔
1665
                                c += 'A' - '9';
×
1666
                        result[pos] = c;
7✔
1667
                }
1668
                //
1669
                // Get rid of leading zeros:
1670
                //
1671
                std::string::size_type fnz = result.find_first_not_of('0');
14✔
1672
                if (!result.empty() && (fnz == std::string::npos)) fnz = result.size() - 1;
14✔
1673
                result.erase(0, fnz);
14✔
1674
                if (flags & std::ios_base::showbase) {
14✔
1675
                        const char* pp = base == 8 ? "0" : "0x";
×
1676
                        result.insert(0ull, pp);
×
1677
                }
1678
        }
14✔
1679
        else {
1680
                using Integer = integer<nbits + 1, BlockType, NumberType>;  // nbits+1 to be able to represent maxneg in 2's complement form
1681

1682
                Integer t(n);
4,259✔
1683
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1684
                        if (t.sign()) t.twosComplement();
4,259✔
1685
                }
1686

1687
                Integer block10;
1688
                unsigned digits_in_block10 = 2;
4,259✔
1689
                if constexpr (IntegerBase::bitsInBlock == 8) {
1690
                        block10 = 100u;
3,507✔
1691
                        digits_in_block10 = 2;
3,507✔
1692
                }
1693
                else if constexpr (IntegerBase::bitsInBlock == 16) {
1694
                        block10 = 10'000u;
4✔
1695
                        digits_in_block10 = 4;
4✔
1696
                }
1697
                else if constexpr (IntegerBase::bitsInBlock == 32) {
1698
                        block10 = 1'000'000'000ul;
548✔
1699
                        digits_in_block10 = 9;
548✔
1700
                }
1701
                else if constexpr (IntegerBase::bitsInBlock == 64) {
1702
                        block10 = 1'000'000'000'000'000'000ull;
200✔
1703
                        digits_in_block10 = 18;
200✔
1704
                }
1705

1706
                result.assign(nbits / 3 + 1u, '0');
4,259✔
1707
                int pos = static_cast<int>(result.size() - 1u);
4,259✔
1708
                while (!t.iszero()) {
23,796✔
1709
                        Integer t2 = t / block10;
20,645✔
1710
                        Integer r  = t % block10;
20,645✔
1711
                        BlockType v = r.block(0);
20,645✔
1712
                        for (unsigned i = 0; i < digits_in_block10; ++i) {
93,368✔
1713
                                char c = '0' + static_cast<char>(v % 10);
73,831✔
1714
                                v /= 10;
73,831✔
1715
                                result[static_cast<unsigned>(pos)] = c;
73,831✔
1716
//                                std::cout << "result : " << result << " : pos : " << pos << '\n';
1717
                                if (pos-- == 0) break;
73,831✔
1718
                        }
1719
                        t = t2;
20,645✔
1720
                        if (pos < 0) break;
20,645✔
1721
                }
1722

1723
                std::string::size_type firstDigit = result.find_first_not_of('0');
4,259✔
1724
                result.erase(0, firstDigit);
4,259✔
1725
                if (result.empty())        result = std::string("0");
4,323✔
1726
                if (n.isneg()) { // no need to specialize as isneg() will return false for Natural and Whole Number types
4,259✔
1727
                        result.insert(static_cast<std::string::size_type>(0), 1, '-');
212✔
1728
                }
1729
                else if (flags & std::ios_base::showpos) {
4,047✔
1730
                        result.insert(static_cast<std::string::size_type>(0), 1, '+');
38✔
1731
                }
1732
        }
1733
        return result;
4,273✔
1734
}
4,275✔
1735

1736
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1737
inline std::ostream& operator<<(std::ostream& ostr, const integer<nbits, BlockType, NumberType>& i) {
4,275✔
1738
        std::string s = convert_to_string(ostr.flags(), i);
4,275✔
1739
        std::streamsize width = ostr.width();
4,275✔
1740
        if (width > static_cast<std::streamsize>(s.size())) {
4,275✔
1741
                char fill = ostr.fill();
288✔
1742
                if ((ostr.flags() & std::ios_base::left) == std::ios_base::left)
288✔
1743
                        s.append(static_cast<std::string::size_type>(width - s.size()), fill);
2✔
1744
                else
1745
                        s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(width - s.size()), fill);
286✔
1746
        }
1747
        return ostr << s;
8,550✔
1748
}
4,275✔
1749

1750
// read an ASCII integer format
1751
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1752
inline std::istream& operator>>(std::istream& istr, integer<nbits, BlockType, NumberType>& p) {
4✔
1753
        std::string txt;
4✔
1754
        istr >> txt;
4✔
1755
        if (!parse(txt, p)) {
4✔
UNCOV
1756
                std::cerr << "unable to parse -" << txt << "- into a posit value\n";
×
1757
        }
1758
        return istr;
4✔
1759
}
4✔
1760

1761
////////////////// string operators
1762
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1763
inline std::string to_binary(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
355✔
1764
        std::stringstream s;
355✔
1765
        s << "0b";
355✔
1766
        for (int i = nbits - 1; i >= 0; --i) {
12,287✔
1767
                s << (number.at(static_cast<unsigned>(i)) ? "1" : "0");
11,932✔
1768
                if (i > 0 && (i % 4) == 0 && nibbleMarker) s << '\'';
11,932✔
1769
        }
1770
        return s.str();
710✔
1771
}
355✔
1772

1773
//////////////////////////////////////////////////////////////////////////////////////////////////////
1774
// integer - integer binary logic operators
1775

1776
// equal: precondition is that the storage is properly nulled in all arithmetic paths
1777
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1778
inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,400,211✔
1779
        for (unsigned i = 0; i < lhs.nrBlocks; ++i) {
6,439,984✔
1780
                if (lhs._block[i] != rhs._block[i]) return false;
4,436,081✔
1781
        }
1782
        return true;
2,003,903✔
1783
}
1784
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1785
inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,002,790✔
1786
        return !operator==(lhs, rhs);
2,002,790✔
1787
}
1788
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1789
inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
7,846,559✔
1790
        if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
1791
                for (int i = static_cast<int>(lhs.nrBlocks) - 1; i >= 0; --i) {
3✔
1792
                        if (lhs.block(static_cast<unsigned>(i)) == rhs.block(static_cast<unsigned>(i))) continue;
3✔
1793
                        if (lhs.block(static_cast<unsigned>(i)) < rhs.block(static_cast<unsigned>(i))) return true;
3✔
1794
                }
1795
                return false;
×
1796
        }
1797
        else {
1798
                bool lhs_is_negative = lhs.sign();
7,846,556✔
1799
                bool rhs_is_negative = rhs.sign();
7,846,556✔
1800
                if (lhs_is_negative && !rhs_is_negative) return true;
7,846,556✔
1801
                if (rhs_is_negative && !lhs_is_negative) return false;
7,646,239✔
1802
                // arguments have the same sign
1803
                integer<nbits, BlockType, NumberType> diff;
1804
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1805
                // we need to catch and ignore the exception
1806
                try {
1807
                        diff = (lhs - rhs);
2,205,146✔
1808
                }
1809
                catch (const integer_overflow& e) {
×
1810
                        // all good as the arithmetic is modulo
1811
                        const char* p = e.what();
×
1812
                        if (p) --p;
×
1813
                }
1814
#else 
1815
                diff = (lhs - rhs);
5,375,297✔
1816
#endif
1817
                return diff.sign();
7,580,443✔
1818
        }
1819
}
1820
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1821
inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,208,436✔
1822
        return operator< (rhs, lhs);
4,208,436✔
1823
}
1824
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1825
inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,208,158✔
1826
        return !operator> (lhs, rhs);
4,208,158✔
1827
}
1828
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1829
inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
65,792✔
1830
        return !operator< (lhs, rhs);
65,792✔
1831
}
1832

1833
//////////////////////////////////////////////////////////////////////////////////////////////////////
1834
// integer - literal binary logic operators
1835
// equal: precondition is that the byte-storage is properly nulled in all arithmetic paths
1836
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1837
inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
231,515✔
1838
        return operator==(lhs, integer<nbits, BlockType, NumberType>(rhs));
231,515✔
1839
}
1840
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1841
inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
305✔
1842
        return !operator==(lhs, rhs);
305✔
1843
}
1844
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1845
inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
1,477,700✔
1846
        return operator<(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,477,700✔
1847
}
1848
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1849
inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
9,511✔
1850
        return operator< (integer<nbits, BlockType, NumberType>(rhs), lhs);
9,511✔
1851
}
1852
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1853
inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
12✔
1854
        return operator< (lhs, rhs) || operator==(lhs, rhs);
12✔
1855
}
1856
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1857
inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
668✔
1858
        return !operator< (lhs, rhs);
668✔
1859
}
1860

1861
//////////////////////////////////////////////////////////////////////////////////////////////////////
1862
// literal - integer binary logic operators
1863
// precondition is that the byte-storage is properly nulled in all arithmetic paths
1864

1865
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1866
inline bool operator==(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
13✔
1867
        return operator==(integer<nbits, BlockType, NumberType>(lhs), rhs);
13✔
1868
}
1869
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1870
inline bool operator!=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
1871
        return !operator==(lhs, rhs);
6✔
1872
}
1873
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1874
inline bool operator< (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
18✔
1875
        return operator<(integer<nbits, BlockType, NumberType>(lhs), rhs);
18✔
1876
}
1877
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1878
inline bool operator> (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
1879
        return operator< (rhs, lhs);
6✔
1880
}
1881
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1882
inline bool operator<=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
1883
        return operator< (lhs, rhs) || operator==(lhs, rhs);
6✔
1884
}
1885
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1886
inline bool operator>=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
1887
        return !operator< (lhs, rhs);
6✔
1888
}
1889

1890
//////////////////////////////////////////////////////////////////////////////////////////////////////
1891

1892
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1893
inline integer<nbits, BlockType, NumberType> operator<<(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
180✔
1894
        integer<nbits, BlockType, NumberType> shifted(lhs);
180✔
1895
        return (shifted <<= shift);
360✔
1896
}
1897

1898
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1899
inline integer<nbits, BlockType, NumberType> operator>>(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
76✔
1900
        integer<nbits, BlockType, NumberType> shifted(lhs);
76✔
1901
        return (shifted >>= shift);
152✔
1902
}
1903

1904
//////////////////////////////////////////////////////////////////////////////////////////////////////
1905
// integer - integer binary arithmetic operators
1906
// BINARY ADDITION
1907
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1908
inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
8,878,323✔
1909
        integer<nbits, BlockType, NumberType> sum(lhs);
8,878,323✔
1910
        sum += rhs;
8,878,323✔
1911
        return sum;
8,878,323✔
1912
}
1913
// BINARY SUBTRACTION
1914
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1915
inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
16,447,231✔
1916
        integer<nbits, BlockType, NumberType> diff(lhs);
16,447,231✔
1917
        diff -= rhs;
16,447,231✔
1918
        return diff;
16,447,229✔
1919
}
1920
// BINARY MULTIPLICATION
1921
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1922
inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,220,558✔
1923
        integer<nbits, BlockType, NumberType> mul(lhs);
3,220,558✔
1924
        mul *= rhs;
3,220,558✔
1925
        return mul;
3,220,558✔
1926
}
1927
// BINARY DIVISION
1928
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1929
inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,847,599✔
1930
        integer<nbits, BlockType, NumberType> ratio(lhs);
4,847,599✔
1931
        ratio /= rhs;
4,847,599✔
1932
        return ratio;
4,846,237✔
1933
}
1934
// BINARY REMAINDER
1935
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1936
inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,270,893✔
1937
        integer<nbits, BlockType, NumberType> ratio(lhs);
3,270,893✔
1938
        ratio %= rhs;
3,270,893✔
1939
        return ratio;
3,270,557✔
1940
}
1941
// BINARY BIT-WISE AND
1942
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1943
inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1944
        integer<nbits, BlockType, NumberType> bitwise(lhs);
1945
        bitwise &= rhs;
1946
        return bitwise;
1947
}
1948
// BINARY BIT-WISE OR
1949
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1950
inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1951
        integer<nbits, BlockType, NumberType> bitwise(lhs);
1952
        bitwise |= rhs;
1953
        return bitwise;
1954
}
1955
// BINARY BIT-WISE XOR
1956
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1957
inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1958
        integer<nbits, BlockType, NumberType> bitwise(lhs);
1959
        bitwise ^= rhs;
1960
        return bitwise;
1961
}
1962

1963
//////////////////////////////////////////////////////////////////////////////////////////////////////
1964
// integer - literal binary arithmetic operators
1965
// BINARY ADDITION
1966
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1967
inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
489✔
1968
        return operator+(lhs, integer<nbits, BlockType, NumberType>(rhs));
489✔
1969
}
1970
// BINARY SUBTRACTION
1971
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1972
inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
197,088✔
1973
        return operator-(lhs, integer<nbits, BlockType, NumberType>(rhs));
197,088✔
1974
}
1975
// BINARY MULTIPLICATION
1976
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1977
inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4,460✔
1978
        return operator*(lhs, integer<nbits, BlockType, NumberType>(rhs));
4,460✔
1979
}
1980
// BINARY DIVISION
1981
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1982
inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1,513✔
1983
        return operator/(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,513✔
1984
}
1985
// BINARY REMAINDER
1986
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1987
inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4✔
1988
        return operator%(lhs, integer<nbits, BlockType, NumberType>(rhs));
4✔
1989
}
1990
// BINARY BIT-WISE AND
1991
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1992
inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1993
        return operator&(lhs, integer<nbits, BlockType, NumberType>(rhs));
1994
}
1995
// BINARY BIT-WISE OR
1996
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1997
inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1998
        return operator|(lhs, integer<nbits, BlockType, NumberType>(rhs));
1999
}
2000
// BINARY BIT-WISE XOR
2001
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2002
inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2003
        return operator^(lhs, integer<nbits, BlockType, NumberType>(rhs));
2004
}
2005
//////////////////////////////////////////////////////////////////////////////////////////////////////
2006
// literal - integer binary arithmetic operators
2007
// BINARY ADDITION
2008
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2009
inline integer<nbits, BlockType, NumberType> operator+(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1✔
2010
        return operator+(integer<nbits, BlockType, NumberType>(lhs), rhs);
1✔
2011
}
2012
// BINARY SUBTRACTION
2013
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2014
inline integer<nbits, BlockType, NumberType> operator-(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2015
        return operator-(integer<nbits, BlockType, NumberType>(lhs), rhs);
2016
}
2017
// BINARY MULTIPLICATION
2018
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2019
inline integer<nbits, BlockType, NumberType> operator*(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4✔
2020
        return operator*(integer<nbits, BlockType, NumberType>(lhs), rhs);
4✔
2021
}
2022
// BINARY DIVISION
2023
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2024
inline integer<nbits, BlockType, NumberType> operator/(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2025
        return operator/(integer<nbits, BlockType, NumberType>(lhs), rhs);
2026
}
2027
// BINARY REMAINDER
2028
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2029
inline integer<nbits, BlockType, NumberType> operator%(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2030
        return operator%(integer<nbits, BlockType, NumberType>(lhs), rhs);
2031
}
2032
// BINARY BIT-WISE AND
2033
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2034
inline integer<nbits, BlockType, NumberType> operator&(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2035
        return operator&(integer<nbits, BlockType, NumberType>(lhs), rhs);
2036
}
2037
// BINARY BIT-WISE OR
2038
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2039
inline integer<nbits, BlockType, NumberType> operator|(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2040
        return operator|(integer<nbits, BlockType, NumberType>(lhs), rhs);
2041
}
2042
// BINARY BIT-WISE XOR
2043
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2044
inline integer<nbits, BlockType, NumberType> operator^(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2045
        return operator^(integer<nbits, BlockType, NumberType>(lhs), rhs);
2046
}
2047

2048
}} // namespace sw::universal
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc