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

stillwater-sc / universal / 24969843496

26 Apr 2026 11:32PM UTC coverage: 84.312% (+0.03%) from 84.282%
24969843496

push

github

web-flow
fix(integer): implement WholeNumber/NaturalNumber operator-= (#779)

Replaces the placeholder std::cerr "subtractor TBD" no-op with a real
constexpr-safe magnitude subtractor. Both NumberType modes are
unsigned-domain, so the implementation is a straightforward limb-wise
borrow loop.

The borrow propagation uses the formulation:
  incoming borrow == 0: borrow-out iff a < b
  incoming borrow == 1: borrow-out iff a <= b   (a-b-1 wraps when a == b)
which works uniformly across bt = uint8/uint16/uint32/uint64 limbs
without overflow concerns from widening (b + borrow) at the largest
limb size.

Critical design choice: the WholeNumber/NaturalNumber semantic
preconditions (result >= 1 / result >= 0) are gated behind
INTEGER_THROW_ARITHMETIC_EXCEPTION -- matching the convention already
used in operator/= and convert_signed/unsigned. Under THROW=0 (the
default) the magnitude subtractor runs unconditionally.

This gating is necessary because internal algorithms call -= with
operands that would violate the semantic preconditions in the user-
facing sense:
  - Long division (line 1598/1632): accumulator -= subtractand,
    where accumulator == subtractand at the boundary
  - Decimal conversion (line 1862-1863): the / and % chain calls into
    long division
  - Stream output (operator<<): wraps decimal conversion
Throwing in those paths would break printing and division for
WholeNumber and NaturalNumber types entirely, which is exactly the
failure mode this PR was authored to fix.

Out-of-domain user code under THROW=0 gets defined modular wraparound,
the same convention IntegerNumber uses by default. Out-of-domain user
code under THROW=1 still throws integer_wholenumber_cannot_be_negative
or integer_wholenumber_cannot_be_zero as before.

Tests:
  - static/integer/binary/api/constexpr.cpp: extended the
    "Edge cases" block with 5 new static_asserts covering N32/W32
    single-limb subtraction, multi-limb cross-limb borrow (256 - 1
    via N64u8), and the Natura... (continued)

9 of 11 new or added lines in 1 file covered. (81.82%)

45489 of 53953 relevant lines covered (84.31%)

6354648.95 hits per line

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

88.35
/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 <type_traits>  // for std::is_constant_evaluated() dispatch around mul128/addcarry
14
#include <vector>
15
#include <map>
16

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

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

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

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

37
namespace sw { namespace universal {
38

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

277
        // arithmetic operators
278
        constexpr integer& operator+=(const integer& rhs) {
51,161,792✔
279
                if constexpr (nrBlocks == 1) {
280
                        _block[0] = static_cast<bt>(_block[0] + rhs.block(0));
34,957,337✔
281
                        // null any leading bits that fall outside of nbits
282
                        _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
34,957,337✔
283
                }
284
                else if constexpr (bitsInBlock == 64) {
285
                        // uint64_t limbs: addcarry uses platform intrinsics (not constexpr on MSVC).
286
                        // Dispatch to a portable carry path in constant-evaluated context.
287
                        integer<nbits, BlockType, NumberType> sum;
288
                        if (std::is_constant_evaluated()) {
1,165,996✔
289
                                uint64_t carry = 0;
×
290
                                for (unsigned i = 0; i < nrBlocks; ++i) {
×
291
                                        uint64_t a = _block[i];
×
292
                                        uint64_t b = rhs._block[i];
×
293
                                        uint64_t s1 = a + carry;
×
294
                                        uint64_t c1 = (s1 < a) ? 1ull : 0ull;
×
295
                                        uint64_t r  = s1 + b;
×
296
                                        uint64_t c2 = (r < s1) ? 1ull : 0ull;
×
297
                                        sum._block[i] = r;
×
298
                                        carry = c1 + c2;
×
299
                                }
300
                        }
301
                        else {
302
                                uint64_t carry = 0;
1,165,996✔
303
                                for (unsigned i = 0; i < nrBlocks; ++i) {
20,987,416✔
304
                                        sum._block[i] = addcarry(_block[i], rhs._block[i], carry, carry);
19,821,420✔
305
                                }
306
                        }
307
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
308
                        sum._block[MSU] = static_cast<bt>(MSU_MASK & sum._block[MSU]);
1,165,996✔
309
                        *this = sum;
1,165,996✔
310
                }
311
                else {
312
                        // Multi-limb path for bt = uint8_t/uint16_t/uint32_t.
313
                        // Index-based loop (constexpr-friendly; pointer arithmetic on stack
314
                        // arrays is forbidden in constexpr).
315
                        integer<nbits, BlockType, NumberType> sum;
316
                        std::uint64_t carry = 0;
15,038,459✔
317
                        for (unsigned i = 0; i < nrBlocks; ++i) {
102,064,560✔
318
                                carry += static_cast<std::uint64_t>(_block[i]) + static_cast<std::uint64_t>(rhs._block[i]);
87,026,101✔
319
                                sum._block[i] = static_cast<bt>(carry);
87,026,101✔
320
                                carry >>= bitsInBlock;
87,026,101✔
321
                        }
322
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
323
                        sum._block[MSU] = static_cast<bt>(MSU_MASK & sum._block[MSU]);
15,038,459✔
324
        #if INTEGER_THROW_ARITHMETIC_EXCEPTION
325
                        // TODO: what is the real overflow condition?
326
                        // it is not carry == 1 as  say 1 + -1 sets the carry but is 0
327
                //                if (carry) throw integer_overflow();
328
        #endif
329
                        *this = sum;
15,038,459✔
330
                }
331
                return *this;
51,161,792✔
332
        }
333
        constexpr integer& operator-=(const integer& rhs) {
18,987,847✔
334
                if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
335
                        // Both modes are unsigned-domain. The semantic preconditions
336
                        // (WholeNumber: result must be >= 1; NaturalNumber: result >= 0)
337
                        // are checked only when INTEGER_THROW_ARITHMETIC_EXCEPTION is on
338
                        // -- matching the convention used by operator/= and convert_*.
339
                        //
340
                        // Under THROW=0 (the default) the magnitude subtractor runs
341
                        // unconditionally. This is necessary because internal algorithms
342
                        // (long division at line 1598/1632, decimal conversion via the
343
                        // quotient/remainder loop) call -= with operands that may be
344
                        // equal or that may produce an out-of-domain modular result;
345
                        // throwing in those paths would break printing and division.
346
                        // Out-of-domain user code under THROW=0 gets defined modular
347
                        // wraparound, the same convention IntegerNumber uses.
348
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
349
                        if (*this < rhs) {
2✔
350
                                throw integer_wholenumber_cannot_be_negative{};
2✔
351
                        }
352
                        if constexpr (NumberType == WholeNumber) {
NEW
353
                                if (*this == rhs) {
×
NEW
354
                                        throw integer_wholenumber_cannot_be_zero{};
×
355
                                }
356
                        }
357
#endif
358
                        // Magnitude subtraction with limb-wise borrow propagation.
359
                        // constexpr-safe: only bt-typed integer arithmetic.
360
                        //
361
                        // Borrow-out logic per limb:
362
                        //   incoming borrow == 0: borrow-out iff a < b
363
                        //   incoming borrow == 1: borrow-out iff a <= b  (a - b - 1 wraps when a == b too)
364
                        // This formulation works uniformly for bt = uint8/16/32/64 without
365
                        // overflow concerns from widening b + borrow at the largest limb size.
366
                        unsigned borrow = 0;
7✔
367
                        for (unsigned i = 0; i < nrBlocks; ++i) {
35✔
368
                                bt a = _block[i];
28✔
369
                                bt b = rhs._block[i];
28✔
370
                                bt diff = static_cast<bt>(a - b - borrow);
28✔
371
                                borrow = (borrow == 0) ? (a < b ? 1u : 0u)
30✔
372
                                                       : (a <= b ? 1u : 0u);
2✔
373
                                _block[i] = diff;
28✔
374
                        }
375
                        // Clear bits above nbits in the most significant unit.
376
                        _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK);
7✔
377
                }
378
                else {
379
                        integer twos(rhs);
18,987,838✔
380
                        operator+=(twos.twosComplement());
18,987,838✔
381
                }
382
                return *this;
18,987,845✔
383
        }
384
        constexpr integer& operator*=(const integer& rhs) {
3,220,565✔
385
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
386
                        if constexpr (nrBlocks == 1) {
387
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
3,215,852✔
388
                        }
389
                        else if constexpr (bitsInBlock == 64) {
390
                                // uint64_t limbs: mul128/addcarry use platform intrinsics that are
391
                                // not constexpr on MSVC. In constant-evaluated context, fall back
392
                                // to a portable double-loop using the index-loop formulation
393
                                // (same as the bt < 64 branch below). At runtime we keep the
394
                                // intrinsic path for performance.
395
                                integer<nbits + 1, BlockType, NumberType> base(*this);
201✔
396
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
201✔
397
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
201✔
398
                                if (base.isneg()) {
201✔
399
                                        base.twosComplement();
×
400
                                }
401
                                if (multiplicant.isneg()) {
201✔
402
                                        multiplicant.twosComplement();
×
403
                                }
404
                                clear();
201✔
405
                                if (std::is_constant_evaluated()) {
201✔
406
                                        // Constexpr-safe 64x64 -> 128 mul + carry propagation. Uses
407
                                        // __int128 on gcc/clang (where it is constexpr-friendly).
408
                                        // On MSVC (no __int128), constexpr eval of integer<N, uint64_t>
409
                                        // is unsupported -- callers can use uint32_t limbs there.
410
#if defined(__SIZEOF_INT128__)
411
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
×
412
                                                uint128_t carry = 0;
×
413
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
×
414
                                                        if (i + j < nrBlocks) {
×
415
                                                                uint128_t product = static_cast<uint128_t>(base.block(i)) * multiplicant.block(j);
×
416
                                                                uint128_t sum = product + _block[i + j] + carry;
×
417
                                                                _block[i + j] = static_cast<bt>(sum);
×
418
                                                                carry = sum >> 64;
×
419
                                                        }
420
                                                }
421
                                        }
422
#else
423
                                        // MSVC fallback (or any platform without __int128): truncating
424
                                        // fallback. Documented limitation: uint64-limb integer<>
425
                                        // constexpr arithmetic loses high-half of partial products.
426
                                        for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
427
                                                std::uint64_t segment(0);
428
                                                for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
429
                                                        segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
430
                                                        if (i + j < static_cast<unsigned>(nrBlocks)) {
431
                                                                segment += _block[i + j];
432
                                                                _block[i + j] = static_cast<bt>(segment);
433
                                                                segment = 0;
434
                                                        }
435
                                                }
436
                                        }
437
#endif
438
                                }
439
                                else {
440
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
3,403✔
441
                                                uint64_t carry = 0;
3,202✔
442
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
54,406✔
443
                                                        if (i + j < nrBlocks) {
51,204✔
444
                                                                uint64_t lo, hi;
445
                                                                mul128(base.block(i), multiplicant.block(j), lo, hi);
27,203✔
446
                                                                uint64_t c1 = 0;
27,203✔
447
                                                                uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
27,203✔
448
                                                                _block[i + j] = sum;
27,203✔
449
                                                                carry = hi + c1;
27,203✔
450
                                                        }
451
                                                }
452
                                        }
453
                                }
454
                                if (resultIsNeg) twosComplement();
201✔
455
                        }
456
                        else {
457
                                // is there a better way than upconverting to deal with maxneg in a 2's complement encoding?
458
                                integer<nbits + 1, BlockType, NumberType> base(*this);
4,512✔
459
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
4,512✔
460
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
4,512✔
461
                                if (base.isneg()) {
4,512✔
462
                                        base.twosComplement();
×
463
                                }
464
                                if (multiplicant.isneg()) {
4,512✔
465
                                        multiplicant.twosComplement();
×
466
                                }
467
                                clear();
4,512✔
468
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
39,473✔
469
                                        std::uint64_t segment(0);
34,961✔
470
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
427,376✔
471
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
392,415✔
472

473
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
392,415✔
474
                                                        segment += _block[i + j];
213,688✔
475
                                                        _block[i + j] = static_cast<bt>(segment);
213,688✔
476
                                                        segment >>= bitsInBlock;
213,688✔
477
                                                }
478
                                        }
479
                                }
480
                                if (resultIsNeg) twosComplement();
4,512✔
481
                        }
482
                }
483
                else {  // whole and natural numbers are closed under multiplication (modulo)
484
                        if constexpr (nrBlocks == 1) {
485
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
486
                        }
487
                        else if constexpr (bitsInBlock == 64) {
488
                                // Same is_constant_evaluated dispatch as the IntegerNumber branch
489
                                // above to keep mul128/addcarry intrinsics out of constexpr context.
490
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
491
                                clear();
492
                                if (std::is_constant_evaluated()) {
493
                                        // Same __int128 carry propagation as the IntegerNumber branch above
494
#if defined(__SIZEOF_INT128__)
495
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
496
                                                uint128_t carry = 0;
497
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
498
                                                        if (i + j < nrBlocks) {
499
                                                                uint128_t product = static_cast<uint128_t>(base.block(i)) * multiplicant.block(j);
500
                                                                uint128_t sum = product + _block[i + j] + carry;
501
                                                                _block[i + j] = static_cast<bt>(sum);
502
                                                                carry = sum >> 64;
503
                                                        }
504
                                                }
505
                                        }
506
#else
507
                                        for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
508
                                                std::uint64_t segment(0);
509
                                                for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
510
                                                        segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
511
                                                        if (i + j < static_cast<unsigned>(nrBlocks)) {
512
                                                                segment += _block[i + j];
513
                                                                _block[i + j] = static_cast<bt>(segment);
514
                                                                segment = 0;
515
                                                        }
516
                                                }
517
                                        }
518
#endif
519
                                }
520
                                else {
521
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
522
                                                uint64_t carry = 0;
523
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
524
                                                        if (i + j < nrBlocks) {
525
                                                                uint64_t lo, hi;
526
                                                                mul128(base.block(i), multiplicant.block(j), lo, hi);
527
                                                                uint64_t c1 = 0;
528
                                                                uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
529
                                                                _block[i + j] = sum;
530
                                                                carry = hi + c1;
531
                                                        }
532
                                                }
533
                                        }
534
                                }
535
                        }
536
                        else {
537
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
538
                                clear();
539
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
540
                                        std::uint64_t segment(0);
541
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
542
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
543

544
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
545
                                                        segment += _block[i + j];
546
                                                        _block[i + j] = static_cast<bt>(segment);
547
                                                        segment >>= bitsInBlock;
548
                                                }
549
                                        }
550
                                }
551
                        }
552
                }
553
                // null any leading bits that fall outside of nbits
554
                _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
3,220,565✔
555
                return *this;
3,220,565✔
556
        }
557
        constexpr integer& operator*=(const BlockType& scale) noexcept {
169✔
558
                if constexpr (bitsInBlock == 64) {
559
                        // uint64_t limbs: same mul128/addcarry dispatch as operator*=
560
                        if (std::is_constant_evaluated()) {
561
#if defined(__SIZEOF_INT128__)
562
                                uint128_t carry = 0;
563
                                for (unsigned i = 0; i < nrBlocks; ++i) {
564
                                        uint128_t product = static_cast<uint128_t>(_block[i]) * scale + carry;
565
                                        _block[i] = static_cast<BlockType>(product);
566
                                        carry = product >> 64;
567
                                }
568
#else
569
                                std::uint64_t scaleFactor(scale), segment(0);
570
                                for (unsigned i = 0; i < nrBlocks; ++i) {
571
                                        segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
572
                                        _block[i] = static_cast<BlockType>(segment);
573
                                        segment = 0;
574
                                }
575
#endif
576
                        }
577
                        else {
578
                                uint64_t carry = 0;
579
                                for (unsigned i = 0; i < nrBlocks; ++i) {
580
                                        uint64_t lo, hi;
581
                                        mul128(_block[i], static_cast<uint64_t>(scale), lo, hi);
582
                                        uint64_t c1 = 0;
583
                                        _block[i] = addcarry(lo, carry, uint64_t(0), c1);
584
                                        carry = hi + c1;
585
                                }
586
                        }
587
                }
588
                else {
589
                        std::uint64_t scaleFactor(scale), segment(0);
169✔
590
                        for (unsigned i = 0; i < nrBlocks; ++i) {
1,049✔
591
                                segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
880✔
592
                                _block[i] = static_cast<BlockType>(segment);
880✔
593
                                segment >>= bitsInBlock;
880✔
594
                        }
595
                }
596
                return *this;
169✔
597
        }
598
        constexpr integer& operator/=(const integer& rhs) {
4,847,729✔
599
                if constexpr (EXACT_FIT && 1 == nrBlocks) {
600
                        if (rhs._block[0] == 0) {
3,215,160✔
601
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
602
                                throw integer_divide_by_zero{};
257✔
603
#else
604
                                // When exceptions are disabled we still must avoid the actual
605
                                // divide-by-zero below (UB at runtime; constexpr eval would
606
                                // be ill-formed). Set the result to 0 and bail out.
607
                                if (!std::is_constant_evaluated()) {
1✔
608
                                        std::cerr << "integer_divide_by_zero\n";
1✔
609
                                }
610
                                clear();
1✔
611
                                return *this;
1✔
612
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
613
                        }
614
                        if constexpr (NumberType == WholeNumber) {
615
                                if (*this < rhs) {
1✔
616
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
617
                                        throw integer_wholenumber_cannot_be_zero{};
1✔
618
#else
619
                                        if (!std::is_constant_evaluated()) {
620
                                                std::cerr << "whole number cannot be zero but division would yield 0\n";
621
                                        }
622
                                        clear();
623
                                        return *this;
624
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
625
                                }
626
                        }
627
                        if constexpr (sizeof(BlockType) == 1) {
628
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) / std::int8_t(rhs._block[0]));
1,117,748✔
629
                        }
630
                        else if constexpr (sizeof(BlockType) == 2) {
631
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) / std::int16_t(rhs._block[0]));
1,048,577✔
632
                        }
633
                        else if constexpr (sizeof(BlockType) == 4) {
634
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) / std::int32_t(rhs._block[0]));
524,288✔
635
                        }
636
                        else if constexpr (sizeof(BlockType) == 8) {
637
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) / std::int64_t(rhs._block[0]));                
524,288✔
638
                        }
639
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,214,901✔
640
                }
641
                else {
642
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
1,632,569✔
643
                        *this = divresult.quot;
1,631,465✔
644
                }
645
                return *this;
4,846,366✔
646
        }
647
        constexpr integer& operator%=(const integer& rhs) {
3,270,844✔
648
                if constexpr (nbits == (sizeof(BlockType) * 8)) {
649
                        if (rhs._block[0] == 0) {
3,211,265✔
650
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
651
                                throw integer_divide_by_zero{};
256✔
652
#else
653
                                // When exceptions are disabled we still must avoid the actual
654
                                // modulo-by-zero below (UB at runtime; constexpr would be
655
                                // ill-formed). Set the result to 0 and bail out.
656
                                if (!std::is_constant_evaluated()) {
1✔
657
                                        std::cerr << "integer_divide_by_zero\n";
1✔
658
                                }
659
                                clear();
1✔
660
                                return *this;
1✔
661
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
662
                        }
663
                        if constexpr (sizeof(BlockType) == 1) {
664
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) % std::int8_t(rhs._block[0]));
1,113,856✔
665
                        }
666
                        else if constexpr (sizeof(BlockType) == 2) {
667
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) % std::int16_t(rhs._block[0]));
1,048,576✔
668
                        }
669
                        else if constexpr (sizeof(BlockType) == 4) {
670
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) % std::int32_t(rhs._block[0]));
524,288✔
671
                        }
672
                        else if constexpr (sizeof(BlockType) == 8) {
673
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) % std::int64_t(rhs._block[0]));
524,288✔
674
                        }
675
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,211,008✔
676
                }
677
                else {
678
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
59,579✔
679
                        *this = divresult.rem;
59,499✔
680
                }
681

682
                return *this;
3,270,507✔
683
        }
684

685
        // arithmetic shift right operator
686
        constexpr integer& operator<<=(int bitsToShift) {
1,417,535✔
687
                if (bitsToShift == 0) return *this;
1,417,535✔
688
                if (bitsToShift < 0) return operator>>=(-bitsToShift);
277,756✔
689
                if (bitsToShift > static_cast<int>(nbits)) {
277,716✔
690
                        setzero();
×
691
                        return *this;
×
692
                }
693
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
277,716✔
694
                        int blockShift = bitsToShift / static_cast<int>(bitsInBlock);
92,373✔
695
                        for (int i = static_cast<int>(MSU); i >= blockShift; --i) {
679,570✔
696
                                _block[i] = bt(_block[i - blockShift]);
587,197✔
697
                        }
698
                        for (int i = blockShift - 1; i >= 0; --i) {
291,438✔
699
                                _block[i] = bt(0);
199,065✔
700
                        }
701
                        // adjust the shift
702
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
92,373✔
703
                        if (bitsToShift == 0) {
92,373✔
704
                                _block[MSU] &= MSU_MASK;
5,390✔
705
                                return *this;
5,390✔
706
                        }
707
                }
708
                if constexpr (MSU > 0) {
709
                        // construct the mask for the upper bits in the block that needs to move to the higher word
710
                        bt mask = 0xFFFFFFFFFFFFFFFFull << (bitsInBlock - bitsToShift);
182,665✔
711
                        for (unsigned i = MSU; i > 0; --i) {
1,013,747✔
712
                                _block[i] <<= bitsToShift;
831,082✔
713
                                // mix in the bits from the right
714
                                bt bits = bt(mask & _block[i - 1]);
831,082✔
715
                                _block[i] |= (bits >> (bitsInBlock - bitsToShift));
831,082✔
716
                        }
717
                }
718
                _block[0] <<= bitsToShift;        
272,326✔
719
                _block[MSU] &= MSU_MASK; // null any leading bits that fall outside of nbits
272,326✔
720
                return *this;
272,326✔
721
        }
722
        constexpr integer& operator>>=(int bitsToShift) {
4,139,819✔
723
                if (bitsToShift == 0) return *this;
4,139,819✔
724
                if (bitsToShift < 0) return operator<<=(-bitsToShift);
4,139,815✔
725
                if (bitsToShift >= static_cast<int>(nbits)) {
4,139,815✔
726
                        setzero();
4✔
727
                        return *this;
4✔
728
                }
729
                bool signext = sign();
4,139,811✔
730
                unsigned blockShift = 0;
4,139,811✔
731
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
4,139,811✔
732
                        blockShift = bitsToShift / bitsInBlock;
40✔
733
                        if (MSU >= blockShift) {
40✔
734
                                // shift by blocks
735
                                for (unsigned i = 0; i <= MSU - blockShift; ++i) {
136✔
736
                                        _block[i] = bt(_block[i + blockShift]);
96✔
737
                                }
738
                        }
739
                        // adjust the shift
740
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
40✔
741
                        if (bitsToShift == 0) {
40✔
742
                                // fix up the leading zeros if we have a negative number
743
                                if (signext) {
7✔
744
                                        // bitsToShift is guaranteed to be less than nbits
745
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
7✔
746
                                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
119✔
747
                                                setbit(i);
112✔
748
                                        }
749
                                }
750
                                else {
751
                                        // clean up the blocks we have shifted clean
752
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
×
753
                                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
×
754
                                                setbit(i, false);
×
755
                                        }
756
                                }
757
                                return *this;
7✔
758
                        }
759
                }
760
                if constexpr (MSU > 0) {
761
                        bt mask = ALL_ONES;
3,307,683✔
762
                        mask >>= (bitsInBlock - bitsToShift); // this is a mask for the lower bits in the block that need to move to the lower word
3,307,683✔
763
                        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
28,753,094✔
764
                                _block[i] >>= bitsToShift;
25,445,411✔
765
                                // mix in the bits from the left
766
                                bt bits = bt(mask & _block[i + 1]);
25,445,411✔
767
                                _block[i] |= (bits << (bitsInBlock - bitsToShift));
25,445,411✔
768
                        }
769
                }
770
                _block[MSU] >>= bitsToShift;
4,139,804✔
771

772
                // fix up the leading zeros if we have a negative number
773
                if (signext) {
4,139,804✔
774
                        // bitsToShift is guaranteed to be less than nbits
775
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
61✔
776
                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
742✔
777
                                setbit(i);
681✔
778
                        }
779
                }
780
                else {
781
                        // clean up the blocks we have shifted clean
782
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
4,139,743✔
783
                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
8,279,780✔
784
                                setbit(i, false);
4,140,037✔
785
                        }
786
                }
787

788
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
789
                _block[MSU] &= MSU_MASK;
4,139,804✔
790
                return *this;
4,139,804✔
791
        }
792
        constexpr integer& logicShiftRight(int shift) {
6✔
793
                if (shift == 0) return *this;
6✔
794
                if (shift < 0) {
6✔
795
                        return operator<<=(-shift);
×
796
                }
797
                if (nbits <= unsigned(shift)) {
6✔
798
                        clear();
×
799
                        return *this;
×
800
                }
801
                integer<nbits, BlockType, NumberType> target{};
6✔
802
                for (int i = nbits - 1; i >= shift; --i) {  // TODO: inefficient as it works at the bit level
6,144✔
803
                        target.setbit(static_cast<unsigned>(i - shift), at(static_cast<unsigned>(i)));
6,138✔
804
                }
805
                *this = target;
6✔
806
                return *this;
6✔
807
        }
808
        constexpr integer& operator&=(const integer& rhs) {
809
                for (unsigned i = 0; i < nrBlocks; ++i) {
810
                        _block[i] &= rhs._block[i];
811
                }
812
                _block[MSU] &= MSU_MASK;
813
                return *this;
814
        }
815
        constexpr integer& operator|=(const integer& rhs) {
816
                for (unsigned i = 0; i < nrBlocks; ++i) {
817
                        _block[i] |= rhs._block[i];
818
                }
819
                _block[MSU] &= MSU_MASK;
820
                return *this;
821
        }
822
        constexpr integer& operator^=(const integer& rhs) {
823
                for (unsigned i = 0; i < nrBlocks; ++i) {
824
                        _block[i] ^= rhs._block[i];
825
                }
826
                _block[MSU] &= MSU_MASK;
827
                return *this;
828
        }
829

830
        // modifiers
831
        constexpr void clear() noexcept { 
33,359,899✔
832
                bt* p = _block;
33,359,899✔
833
                if constexpr (0 == nrBlocks) {
834
                        return;
835
                }
836
                else if constexpr (1 == nrBlocks) {
837
                        *p = bt(0);
19,625,567✔
838
                }
839
                else if constexpr (2 == nrBlocks) {
840
                        *p++ = bt(0);
8,615,865✔
841
                        *p = bt(0);
8,615,865✔
842
                }
843
                else if constexpr (3 == nrBlocks) {
844
                        *p++ = bt(0);
73,087✔
845
                        *p++ = bt(0);
73,087✔
846
                        *p   = bt(0);
73,087✔
847
                }
848
                else if constexpr (4 == nrBlocks) {
849
                        *p++ = bt(0);
203,383✔
850
                        *p++ = bt(0);
203,383✔
851
                        *p++ = bt(0);
203,383✔
852
                        *p   = bt(0);
203,383✔
853
                }
854
                else {
855
                        for (unsigned i = 0; i < nrBlocks; ++i) {
60,269,302✔
856
                                *p++ = bt(0);
55,427,305✔
857
                        }
858
                }
859
        }
33,359,899✔
860
        constexpr void setzero() noexcept { clear(); }
5✔
861
        constexpr integer& maxpos() noexcept {
1✔
862
                clear();
1✔
863
                setbit(nbits - 1ull, true);
1✔
864
                flip();
1✔
865
                return *this;
1✔
866
        }
867
        constexpr integer& minpos() noexcept {
1✔
868
                clear();
1✔
869
                setbit(0, true);
1✔
870
                return *this;
1✔
871
        }
872
        constexpr integer& zero() noexcept {
873
                clear();
874
                return *this;
875
        }
876
        constexpr integer& minneg() noexcept {
1✔
877
                clear();
1✔
878
                flip();
1✔
879
                return *this;
1✔
880
        }
881
        constexpr integer& maxneg() noexcept {
1✔
882
                clear();
1✔
883
                setbit(nbits - 1ull, true);
1✔
884
                return *this;
1✔
885
        }
886
        constexpr void setbit(unsigned i, bool v = true) noexcept {
40,582,727✔
887
                unsigned blockIndex = i / bitsInBlock;
40,582,727✔
888
                if (blockIndex < nrBlocks) {
40,582,727✔
889
                        bt block = _block[blockIndex];
40,582,727✔
890
                        bt null = ~(1ull << (i % bitsInBlock));
40,582,727✔
891
                        bt bit = bt(v ? 1 : 0);
40,582,727✔
892
                        bt mask = bt(bit << (i % bitsInBlock));
40,582,727✔
893
                        _block[blockIndex] = bt((block & null) | mask);
40,582,727✔
894
                }
895
                // nop if out of bounds
896
        }
40,582,727✔
897
        constexpr void setbyte(unsigned byteIndex, uint8_t data) {
232✔
898
                uint8_t mask = 0x1u;
232✔
899
                unsigned start = byteIndex * 8;
232✔
900
                unsigned end = start + 8;
232✔
901
                for (unsigned i = start; i < end; ++i) {
2,088✔
902
                        setbit(i, static_cast<bool>(mask & data));
1,856✔
903
                        mask <<= 1;
1,856✔
904
                }
905
        }
232✔
906
        constexpr void setblock(unsigned i, bt value) noexcept {
11✔
907
                if (i < nrBlocks) _block[i] = value;
11✔
908
        }
11✔
909
        // use un-interpreted raw bits to set the bits of the integer
910
        constexpr integer& setbits(uint64_t raw_bits) noexcept {
2,341,238✔
911
                if constexpr (0 == nrBlocks) {
912
                        return *this;
913
                }
914
                else if constexpr (1 == nrBlocks) {
915
                        _block[0] = raw_bits & storageMask;
1,290,434✔
916
                }
917
                else if constexpr (2 == nrBlocks) {
918
                        if constexpr (bitsInBlock < 64) {
919
                                _block[0] = raw_bits & storageMask;
1,050,640✔
920
                                raw_bits >>= bitsInBlock;
1,050,640✔
921
                                _block[1] = raw_bits & storageMask;
1,050,640✔
922
                        }
923
                        else {
924
                                _block[0] = raw_bits & storageMask;
925
                                _block[1] = 0;
926
                        }
927
                }
928
                else if constexpr (3 == nrBlocks) {
929
                        if constexpr (bitsInBlock < 64) {
930
                                _block[0] = raw_bits & storageMask;
20✔
931
                                raw_bits >>= bitsInBlock;
20✔
932
                                _block[1] = raw_bits & storageMask;
20✔
933
                                raw_bits >>= bitsInBlock;
20✔
934
                                _block[2] = raw_bits & storageMask;
20✔
935
                        }
936
                        else {
937
                                _block[0] = raw_bits & storageMask;
938
                                _block[1] = 0;
939
                                _block[2] = 0;
940
                        }
941
                }
942
                else if constexpr (4 == nrBlocks) {
943
                        if constexpr (bitsInBlock < 64) {
944
                                _block[0] = raw_bits & storageMask;
3✔
945
                                raw_bits >>= bitsInBlock;
3✔
946
                                _block[1] = raw_bits & storageMask;
3✔
947
                                raw_bits >>= bitsInBlock;
3✔
948
                                _block[2] = raw_bits & storageMask;
3✔
949
                                raw_bits >>= bitsInBlock;
3✔
950
                                _block[3] = raw_bits & storageMask;
3✔
951
                        }
952
                        else {
953
                                _block[0] = raw_bits & storageMask;
954
                                _block[1] = 0;
955
                                _block[2] = 0;
956
                                _block[3] = 0;
957
                        }
958
                }
959
                else {
960
                        if constexpr (bitsInBlock < 64) {
961
                                for (unsigned i = 0; i < nrBlocks; ++i) {
1,047✔
962
                                        _block[i] = raw_bits & storageMask;
906✔
963
                                        raw_bits >>= bitsInBlock;
906✔
964
                                }
965
                        }
966
                        else {
967
                                _block[0] = raw_bits & storageMask;
968
                                for (unsigned i = 1; i < nrBlocks; ++i) {
969
                                        _block[i] = 0;
970
                                }
971
                        }
972
                }
973
                _block[MSU] &= MSU_MASK; // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
2,341,238✔
974
                return *this;
2,341,238✔
975
        }
976
        integer& assign(const std::string& txt) noexcept {
19✔
977
                if (!parse(txt, *this)) {
19✔
978
                        std::cerr << "Unable to parse: " << txt << std::endl;
×
979
                }
980
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
981
                _block[MSU] = static_cast<BlockType>(MSU_MASK & _block[MSU]);
19✔
982
                return *this;
19✔
983
        }
984
        // pure bit copy of source integer, no sign extension
985
        template<unsigned src_nbits>
986
        constexpr void bitcopy(const integer<src_nbits, BlockType, NumberType>& src) noexcept {
5,335,903✔
987
                // no need to clear as we are going to overwrite all blocks
988
                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,896,911✔
989
                        _block[i] = src.block(i);
10,561,008✔
990
                }
991
                _block[MSU] &= MSU_MASK; // assert precondition of properly nulled leading non-bits
5,335,903✔
992
        }
5,335,903✔
993
        // in-place one's complement
994
        constexpr integer& flip() {
20,115,435✔
995
                for (unsigned i = 0; i < nrBlocks; ++i) {
84,857,345✔
996
                        _block[i] = static_cast<bt>(~_block[i]);
64,741,910✔
997
                }
998
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
20,115,435✔
999
                return *this;
20,115,435✔
1000
        }
1001
        // in-place 2's complement
1002
        constexpr integer& twosComplement() {
19,315,310✔
1003
                flip();
19,315,310✔
1004
                return ++(*this);
19,315,310✔
1005
        }
1006

1007
        // selectors
1008
        constexpr bool iszero() const noexcept {
5,247,666✔
1009
                for (unsigned i = 0; i < nrBlocks; ++i) {
5,298,489✔
1010
                        if (_block[i] != 0) return false;
5,282,104✔
1011
                }
1012
                return true;
16,385✔
1013
        }
1014
        constexpr bool ispos()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this > 0; else return true; }
1015
        constexpr bool isneg()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this < 0; else return false; }
1,442,107✔
1016
        constexpr bool isone()  const noexcept {
305✔
1017
                for (unsigned i = 0; i < nrBlocks; ++i) {
307✔
1018
                        if (i == 0) {
305✔
1019
                                if (_block[0] != BlockType(1u)) return false;
305✔
1020
                        }
1021
                        else {
1022
                                if (_block[i] != BlockType(0u)) return false;
×
1023
                        }
1024
                }
1025
                return true;
2✔
1026
        }
1027
        constexpr bool isodd()  const noexcept  { return bool(_block[0] & 0x01); }
118✔
1028
        constexpr bool iseven() const noexcept { return !isodd(); }
112✔
1029
        constexpr bool sign()   const noexcept { return at(nbits - 1); }
34,163,259✔
1030
        constexpr bool at(unsigned bitIndex) const noexcept {
34,233,163✔
1031
                if (bitIndex < nbits) {
34,233,163✔
1032
                        bt word = _block[bitIndex / bitsInBlock];
34,233,163✔
1033
                        bt mask = bt(1ull << (bitIndex % bitsInBlock));
34,233,163✔
1034
                        return (word & mask);
34,233,163✔
1035
                }
1036
                return false;
×
1037
        }
1038
        constexpr bool test(unsigned i)  const noexcept { return at(i); }
10✔
1039
        constexpr bt   block(unsigned i) const noexcept { if (i < nrBlocks) return _block[i]; else return bt(0u); }
50,380,567✔
1040
        constexpr uint8_t nibble(unsigned n) const noexcept {
×
1041
                if (n < (1 + ((nbits - 1) >> 2))) {
×
1042
                        bt word = _block[(n * 4) / bitsInBlock];
×
1043
                        int nibbleIndexInWord = int(n % (bitsInBlock >> 2ull));
×
1044
                        bt mask = bt(0xF << (nibbleIndexInWord * 4));
×
1045
                        bt nibblebits = bt(mask & word);
×
1046
                        return uint8_t(nibblebits >> (nibbleIndexInWord * 4));
×
1047
                }
1048
                return 0;
×
1049
        }
1050
        // normalize: decompose integer value into a blocktriple<nbits-1, REP> for quire accumulation
1051
        template<typename TargetBlockType = BlockType>
1052
        void normalize(blocktriple<nbits - 1, BlockTripleOperator::REP, TargetBlockType>& tgt) const {
1053
                if (iszero()) { tgt.setzero(); return; }
1054
                tgt.setzero();
1055
                tgt.setnormal();
1056
                // For WholeNumber/NaturalNumber, sign() returns the raw MSB which is a data bit,
1057
                // not a sign indicator. Only IntegerNumber has a true sign bit.
1058
                const bool negative = (NumberType == IntegerNumberType::IntegerNumber) && sign();
1059
                tgt.setsign(negative);
1060
                // get magnitude
1061
                integer mag = negative ? -(*this) : *this;
1062
                signed msb = findMsb(mag);
1063
                tgt.setscale(msb);  // integer: scale = position of MSB
1064
                // copy magnitude bits into significand
1065
                constexpr unsigned f = nbits - 1;
1066
                tgt.setbit(f);  // hidden bit
1067
                for (signed i = msb - 1; i >= 0 && (msb - 1 - i) < static_cast<signed>(f); --i) {
1068
                        tgt.setbit(static_cast<unsigned>(f - 1 - (msb - 1 - i)), mag.at(static_cast<unsigned>(i)));
1069
                }
1070
        }
1071

1072
        // operators
1073
        // reduce returns the ratio and remainder of a and b in *this and r
1074
        void reduce(const integer& a, const integer& b, integer& r) {
594,176✔
1075
                if (b.iszero()) {
594,176✔
1076
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1077
                        throw integer_divide_by_zero{};
1,360✔
1078
#else
1079
                        std::cerr << "integer_divide_by_zero\n";
1080
                        return;
1081
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1082
                }
1083

1084
                if (a.iszero()) {
592,816✔
1085
                        clear();
1,355✔
1086
                        r.clear();
1,355✔
1087
                        return;
1,355✔
1088
                }
1089
                if constexpr (nrBlocks == 1) { // completely reduce this to native div and rem
1090
                        BlockType _a = a._block[0];
330,340✔
1091
                        BlockType _b = b._block[0];
330,340✔
1092
                        if constexpr (NumberType == IntegerNumber) {
1093
                                bool sign_a = _a & SIGN_BIT_MASK;
330,340✔
1094
                                bool sign_b = _b & SIGN_BIT_MASK;
330,340✔
1095
                                if constexpr (8 == bitsInBlock) {
1096
                                        std::int8_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
69,219✔
1097
                                        std::int8_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
69,219✔
1098
                                        *this = static_cast<BlockType>(a0 / b0);
69,219✔
1099
                                        r = static_cast<BlockType>(a0 % b0);
69,219✔
1100
                                }
1101
                                else if constexpr (16 == bitsInBlock) {
1102
                                        std::int16_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
261,121✔
1103
                                        std::int16_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
261,121✔
1104
                                        *this = static_cast<BlockType>(a0 / b0);
261,121✔
1105
                                        r = static_cast<BlockType>(a0 % b0);
261,121✔
1106
                                }
1107
                                else if constexpr (32 == bitsInBlock) {
1108
                                        std::int32_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
1109
                                        std::int32_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
1110
                                        *this = static_cast<BlockType>(a0 / b0);
1111
                                        r = static_cast<BlockType>(a0 % b0);
1112
                                }
1113
                                else {
1114
                                        std::int64_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
1115
                                        std::int64_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
1116
                                        *this = static_cast<BlockType>(a0 / b0);
1117
                                        r = static_cast<BlockType>(a0 % b0);
1118
                                }
1119
                        }
1120
                        else {
1121
                                *this = static_cast<BlockType>(_a / _b);
1122
                                r = static_cast<BlockType>(_a % _b);
1123
                        }
1124
                }
1125
                else {
1126
                        clear();
261,121✔
1127
                        // no need to constexpr guard this for IntegerNumber as sign() will return false for Whole and Natural Numbers
1128
                        bool sign_a = a.sign();
261,121✔
1129
                        bool sign_b = b.sign();
261,121✔
1130
                        bool sign_q = sign_a ^ sign_b;
261,121✔
1131
                        using Integer = integer<nbits+1, BlockType, NumberType>; // nbits+1 to deal with maxneg
1132
                        Integer _a(a), _b(b);
261,121✔
1133
                        if (sign_a) _a.twosComplement();
261,121✔
1134
                        if (sign_b) _b.twosComplement();                        
261,121✔
1135
                        
1136
                        // filter out the easy stuff
1137
                        if (_a < _b) { r = a; clear(); return; }
392,191✔
1138

1139
                        // determine first non-zero limbs
1140
                        unsigned m{ 0 }, n{ 0 };
131,071✔
1141
                        for (unsigned i = nrBlocks; i > 0; --i) {
261,631✔
1142
                                if (_a.block(i - 1) != 0) {
261,631✔
1143
                                        m = static_cast<unsigned>(i);
131,071✔
1144
                                        break;
131,071✔
1145
                                }
1146
                        }
1147
                        for (unsigned i = nrBlocks; i > 0; --i) {
262,141✔
1148
                                if (_b.block(i - 1) != 0) {
262,141✔
1149
                                        n = static_cast<unsigned>(i);
131,071✔
1150
                                        break;
131,071✔
1151
                                }
1152
                        }
1153

1154
                        // single limb divisor
1155
                        if (n == 1) {
131,071✔
1156
                                std::uint64_t remainder{ 0 };
131,070✔
1157
                                auto divisor = _b.block(0);
131,070✔
1158
                                for (unsigned j = m; j > 0; --j) {
262,650✔
1159
                                        std::uint64_t dividend = remainder * BASE + _a.block(j - 1);
131,580✔
1160
                                        std::uint64_t limbQuotient = dividend / divisor;
131,580✔
1161
                                        _block[j - 1] = static_cast<BlockType>(limbQuotient);
131,580✔
1162
                                        remainder = dividend - limbQuotient * divisor;
131,580✔
1163
                                }
1164
                                r._block[0] = static_cast<BlockType>(remainder);
131,070✔
1165
                                if (sign_q) twosComplement();
131,070✔
1166
                                return;
131,070✔
1167
                        }
1168

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

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

1176
                        int shift = nlz(b.block(n - 1));
1✔
1177
                        ExpandedInteger normalized_a;
1178
                        normalized_a.setblock(m, static_cast<BlockType>((_a.block(m - 1) >> (bitsInBlock - shift))));
1✔
1179
                        for (unsigned i = m - 1; i > 0; --i) {
2✔
1180
                                normalized_a.setblock(i, static_cast<BlockType>((_a.block(i) << shift) | (_a.block(i - 1) >> (bitsInBlock - shift))));
1✔
1181
                        }
1182
                        normalized_a.setblock(0, static_cast<BlockType>(_a.block(0) << shift));
1✔
1183
                        // normalize b
1184
                        OriginalInteger normalized_b;
1185
                        unsigned n_minus_1 = n - 1;
1✔
1186
                        for (unsigned i = n_minus_1; i > 0; --i) {
2✔
1187
                                normalized_b.setblock(i, static_cast<BlockType>((_b.block(i) << shift) | (_b.block(i - 1) >> (bitsInBlock - shift))));
1✔
1188
                        }
1189
                        normalized_b.setblock(0, static_cast<BlockType>(_b.block(0) << shift));
1✔
1190

1191
//                        std::cout << "normalized a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1192
//                        std::cout << "normalized b :             " << normalized_b.showLimbs() << " : " << normalized_b.showLimbValues() << '\n';
1193

1194
                        // divide by limb
1195
                        std::uint64_t divisor = normalized_b._block[n - 1];
1✔
1196
                        std::uint64_t v_nminus2 = normalized_b._block[n - 2]; // n > 1 at this point
1✔
1197
                        for (int j = static_cast<int>(m - n); j >= 0; --j) {
2✔
1198
                                std::uint64_t dividend = normalized_a.block(j + n) * BASE + normalized_a.block(j + n - 1);
1✔
1199
                                std::uint64_t qhat = dividend / divisor;
1✔
1200
                                std::uint64_t rhat = dividend - qhat * divisor;
1✔
1201

1202
                                while (qhat >= BASE || qhat * v_nminus2 > BASE * rhat + normalized_a.block(j + n - 2)) {
1✔
1203
                                        --qhat;
×
1204
                                        rhat += divisor;
×
1205
                                        if (rhat < BASE) continue;
×
1206
                                }
1207
                                std::uint64_t borrow{ 0 };
1✔
1208
                                std::uint64_t diff{ 0 };
1✔
1209
                                for (unsigned i = 0; i < n; ++i) {
3✔
1210
                                        std::uint64_t p = qhat * normalized_b.block(i);
2✔
1211
                                        diff = normalized_a.block(i + j) - static_cast<BlockType>(p) - borrow;
2✔
1212
                                        normalized_a.setblock(i + j, static_cast<BlockType>(diff));
2✔
1213
                                        borrow = (p >> bitsInBlock) - (diff >> bitsInBlock);
2✔
1214
                                }
1215
                                std::int64_t signedBorrow = static_cast<int64_t>(normalized_a.block(j + n) - borrow);
1✔
1216
                                normalized_a.setblock(j + n, static_cast<BlockType>(signedBorrow));
1✔
1217

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

1220
                                setblock(static_cast<unsigned>(j), static_cast<BlockType>(qhat));
1✔
1221
                                if (signedBorrow < 0) { // subtracted too much, add back
1✔
1222
                                        std::cout << "subtracted too much, add back\n";
×
1223
                                        _block[j] -= 1;
×
1224
                                        std::uint64_t carry{ 0 };
×
1225
                                        for (unsigned i = 0; i < n; ++i) {
×
1226
                                                carry += static_cast<std::uint64_t>(normalized_a.block(i + j)) + static_cast<std::uint64_t>(normalized_b.block(i));
×
1227
                                                normalized_a.setblock(i + j, static_cast<BlockType>(carry));
×
1228
                                                carry >>= 32;
×
1229
                                        }
1230
                                        BlockType rectified = static_cast<BlockType>(normalized_a.block(j + n) + carry);
×
1231
                                        normalized_a.setblock(j + n, rectified);
×
1232
                                }
1233
//                                std::cout << "   updated a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1234
                        }
1235
                        if (sign_q) twosComplement();
1✔
1236

1237
                        // remainder needs to be normalized
1238
                        for (unsigned i = 0; i < n - 1; ++i) {
2✔
1239
                                std::uint64_t remainder = static_cast<uint64_t>(normalized_a.block(i) >> shift);
1✔
1240
                                remainder |= static_cast<uint64_t>(normalized_a.block(i + 1) << (32 - shift));
1✔
1241
                                r.setblock(i, static_cast<BlockType>(remainder));
1✔
1242
                        }
1243
                        r.setblock(n - 1, static_cast<BlockType>(normalized_a.block(n - 1) >> shift));
1✔
1244
                }
1245
        }
1246
        // signed integer conversion
1247
        template<typename SignedInt>
1248
        constexpr integer& convert_signed(SignedInt rhs) {
32,433,293✔
1249
                clear();
32,433,293✔
1250
                if (0 == rhs) {
32,433,293✔
1251
                        if constexpr (NumberType == WholeNumber) {
1252
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1253
                                throw integer_wholenumber_cannot_be_zero();
1✔
1254
#else
1255
                                return *this;
×
1256
#endif
1257
                        }
1258
                        else {
1259
                                return *this;
7,382,167✔
1260
                        }
1261
                }
1262
                if constexpr (NumberType == WholeNumber) {
1263
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1264
                        if (rhs < 0) throw integer_wholenumber_cannot_be_negative();
5✔
1265
#else
1266
                        if (rhs < 0) return *this;
3✔
1267
#endif
1268
                }
1269
                if constexpr (NumberType == NaturalNumber) {
1270
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1271
                        if (rhs < 0) throw integer_naturalnumber_cannot_be_negative();
5✔
1272
#else
1273
                        if (rhs < 0) return *this;
6✔
1274
#endif
1275
                }
1276

1277
                int64_t v = rhs;
25,051,123✔
1278
                for (unsigned i = 0; i < nbits && v != 0; ++i) {
58,911,064✔
1279
                        if (v & 0x1ull) setbit(i);
33,859,941✔
1280
                        v >>= 1;
33,859,941✔
1281
                }
1282
                if constexpr (nbits > 64) {
1283
                        if (rhs < 0) {        // sign extend if negative
3,604,866✔
1284
                                for (unsigned i = 64; i < nbits; ++i) {
65✔
1285
                                        setbit(i);
64✔
1286
                                }
1287
                        }
1288
                }
1289
                return *this;
25,051,123✔
1290
        }
1291
        // unsigned integer conversion
1292
        template<typename UnsignedInt>
1293
        constexpr integer& convert_unsigned(UnsignedInt rhs) {
527,154✔
1294
                clear();
527,154✔
1295
                if (0 == rhs) {
527,154✔
1296
                        if constexpr (NumberType == WholeNumber) {
1297
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1298
                                throw integer_wholenumber_cannot_be_zero();
×
1299
#else
1300
                                return *this;
×
1301
#endif
1302
                        }
1303
                        else {
1304
                                return *this;
135,900✔
1305
                        }
1306
                }
1307
                uint64_t v = rhs;
391,254✔
1308
                constexpr unsigned argbits = sizeof(rhs);
391,254✔
1309
                unsigned upper = (nbits <= _nbits ? nbits : argbits);
391,254✔
1310
                for (unsigned i = 0; i < upper; ++i) {
4,352,020✔
1311
                        if (v & 0x1ull) setbit(i);
3,960,766✔
1312
                        v >>= 1;
3,960,766✔
1313
                }
1314
                return *this;
391,254✔
1315
        }
1316
        // native IEEE-754 conversion
1317
        // TODO: currently only supports integer values of 64bits or less
1318
        template<typename Real>
1319
        constexpr integer& convert_ieee(Real rhs) noexcept {
782✔
1320
                clear();
782✔
1321
                return *this = static_cast<long long>(rhs); // TODO: this clamps the IEEE range to +-2^63
782✔
1322
        }
1323

1324
        // show the binary encodings of the limbs
1325
        std::string showLimbs() const {
1326
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1327
                std::stringstream s;
1328
                unsigned i = Integer::MSU;
1329
                while (i > 0) {
1330
                        s << to_binary(_block[i], sizeof(BlockType) * 8, true) << ' ';
1331
                        --i;
1332
                }
1333
                s << to_binary(_block[0], sizeof(BlockType) * 8, true);
1334
                return s.str();
1335
        }
1336
        // show the values of the limbs as a radix-BlockType number
1337
        std::string showLimbValues() const {
1338
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1339
                std::stringstream s;
1340
                unsigned i = Integer::MSU;
1341
                while (i > 0) {
1342
                        s << std::setw(5) << unsigned(_block[i]) << ", ";
1343
                        --i;
1344
                }
1345
                s << std::setw(5) << unsigned(_block[0]);
1346
                return s.str();
1347
        }
1348

1349
protected:
1350
        // HELPER methods
1351

1352
        // to_integer converts to native signed integer
1353
        // TODO: enable_if this for integral types only
1354
        template<typename TargetInt>
1355
        TargetInt to_integer() const noexcept {
2,341,640✔
1356
                TargetInt v{ 0 };
2,341,640✔
1357
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
2,341,640✔
1358

1359
                constexpr unsigned sizeoftarget   = 8 * sizeof(TargetInt);
2,335,034✔
1360
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
2,335,034✔
1361
                unsigned upperBlock = static_cast<unsigned>(std::min(MSU, upperTargetBlock));
2,335,034✔
1362
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1363
                        for (unsigned b = 0; b <= upperBlock; ++b) {
5,720,535✔
1364
                                std::uint64_t data = _block[b];
3,385,539✔
1365
                                v |= (data << (b * bitsInBlock));
3,385,539✔
1366
                        }
1367
                        unsigned upper = nbits;
2,334,996✔
1368
                        if (sign() && upper < sizeoftarget) { // sign extend
2,334,996✔
1369
                                uint64_t mask = (1ull << upper);
1,171,045✔
1370
                                for (unsigned i = upper; i < sizeoftarget; ++i) {
65,984,283✔
1371
                                        v |= mask;
64,813,238✔
1372
                                        mask <<= 1;
64,813,238✔
1373
                                }
1374
                        }
1375
                }
1376
                else {
1377
                        for (unsigned b = 0; b <= upperBlock; ++b) {
139✔
1378
                                std::uint64_t data = _block[b];
101✔
1379
                                v |= (data << (b * bitsInBlock));
101✔
1380
                        }
1381
                }
1382

1383
                return v;
2,335,034✔
1384
        }
1385

1386
        // to_unsigned_integer converts to native unsigned integer
1387
    // TODO: enable_if this for integral types only
1388
        template<typename TargetInt>
1389
        TargetInt to_unsigned_integer() const noexcept {
48✔
1390
                TargetInt v{ 0 };
48✔
1391
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
48✔
1392

1393
                constexpr unsigned sizeoftarget = 8 * sizeof(TargetInt);
48✔
1394
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
48✔
1395
                unsigned upperBlock = std::min(MSU, upperTargetBlock);
48✔
1396
                for (unsigned b = 0; b <= upperBlock; ++b) {
159✔
1397
                        std::uint64_t data = _block[b];
111✔
1398
                        v |= (data << (b * bitsInBlock));
111✔
1399
                }
1400

1401
                return v;
48✔
1402
        }
1403

1404
        // TODO: enable_if this for native floating-point types only
1405
        template<typename Real>
1406
        constexpr Real to_real() const noexcept {
769✔
1407
                Real r = 0.0;
769✔
1408
                Real bitValue = static_cast<Real>(1.0);
769✔
1409
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1410
                        integer<nbits + 1, bt, NumberType> v{ *this }; // deal with maxneg in 2's complement
769✔
1411
                        if (isneg()) v = -v;
769✔
1412
                        for (unsigned i = 0; i < nbits; ++i) { // upper bound is nbits + 1 - 1 == nbits
35,249✔
1413
                                if (v.at(i)) r += bitValue;
34,480✔
1414
                                bitValue *= static_cast<Real>(2.0);
34,480✔
1415
                        }
1416
                        if (isneg()) r = -r;
769✔
1417
                }
1418
                else if constexpr (NumberType == IntegerNumberType::WholeNumber) {
1419
                        for (unsigned i = 0; i < nbits; ++i) {
1420
                                if (at(i)) r += bitValue;
1421
                                bitValue *= static_cast<Real>(2.0);
1422
                        }
1423
                }
1424
                else { // NaturalNumber
1425
                        if (iszero()) std::cerr << "internal error: natural number is set to 0\n";
1426
                        for (unsigned i = 0; i < nbits; ++i) {
1427
                                if (at(i)) r += bitValue;
1428
                                bitValue *= static_cast<Real>(2.0);
1429
                        }
1430
                }
1431

1432
                return r;
769✔
1433
        }
1434

1435
private:
1436
        bt _block[nrBlocks];
1437

1438
        // convert
1439
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1440
        friend std::string convert_to_decimal_string(const integer<nnbits, BBlockType, NNumberType>& value);
1441

1442
        // integer - integer logic comparisons
1443
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1444
        friend constexpr bool operator==(const integer<nnbits, BBlockType, NNumberType>& lhs, const integer<nnbits, BBlockType, NNumberType>& rhs);
1445

1446
        // find the most significant bit set
1447
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1448
        friend constexpr signed findMsb(const integer<nnbits, BBlockType, NNumberType>& v);
1449
};
1450

1451
////////////////////////    INTEGER functions   /////////////////////////////////
1452

1453
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1454
constexpr inline integer<nbits, BlockType, NumberType> abs(const integer<nbits, BlockType, NumberType>& a) {
1455
        integer<nbits, BlockType, NumberType> b(a);
1456
        return (a >= 0 ? b : b.twosComplement());
1457
}
1458

1459
// free function to create a 1's complement copy of an integer
1460
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1461
constexpr inline integer<nbits, BlockType, NumberType> onesComplement(const integer<nbits, BlockType, NumberType>& value) {
1✔
1462
        integer<nbits, BlockType, NumberType> ones(value);
1✔
1463
        return ones.flip();
1✔
1464
}
1465
// free function to create the 2's complement of an integer
1466
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1467
constexpr inline integer<nbits, BlockType, NumberType> twosComplement(const integer<nbits, BlockType, NumberType>& value) {
43✔
1468
        integer<nbits, BlockType, NumberType> twos(value);
43✔
1469
        return twos.twosComplement();;
86✔
1470
}
1471

1472
// convert integer to decimal string
1473
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1474
std::string convert_to_decimal_string(const integer<nbits, BlockType, NumberType>& value) {
3✔
1475
        if (value.iszero()) {
3✔
1476
                return std::string("0");
×
1477
        }
1478
        integer<nbits, BlockType, NumberType> number = value.sign() ? twosComplement(value) : value;
3✔
1479
        support::decimal partial, multiplier;
3✔
1480
        partial.setzero();
3✔
1481
        multiplier.setdigit(1);
3✔
1482
        // convert integer to decimal by adding and doubling multipliers
1483
        for (unsigned i = 0; i < nbits; ++i) {
579✔
1484
                if (number.at(i)) {
576✔
1485
                        support::add(partial, multiplier);
282✔
1486
                        // std::cout << partial << std::endl;
1487
                }
1488
                support::add(multiplier, multiplier);
576✔
1489
        }
1490
        std::stringstream str;
3✔
1491
        if (value.sign()) str << '-';
3✔
1492
        for (support::decimal::const_reverse_iterator rit = partial.rbegin(); rit != partial.rend(); ++rit) {
166✔
1493
                str << (int)*rit;
163✔
1494
        }
1495
        return str.str();
3✔
1496
}
3✔
1497

1498
// findMsb takes an integer<nbits, BlockType, NumberType> reference and returns the 0-based position of the most significant bit, -1 if v == 0
1499
// Index-based loop (constexpr-clean; pointer arithmetic on stack arrays is forbidden in constexpr).
1500
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1501
constexpr signed findMsb(const integer<nbits, BlockType, NumberType>& v) {
2,834,569✔
1502
        using IntegerT = integer<nbits, BlockType, NumberType>;
1503
        // Access static members via the type (clang requires this in constexpr context).
1504
        constexpr unsigned bitsInBlk = IntegerT::bitsInBlock;
2,834,569✔
1505
        constexpr unsigned nBlks = IntegerT::nrBlocks;
2,834,569✔
1506
        constexpr BlockType BlockMsb = BlockType(BlockType(1u) << (bitsInBlk - 1));
2,834,569✔
1507
        signed msb = static_cast<signed>(IntegerT::nbits - 1ull); // the case for an aligned MSB
2,834,569✔
1508
        constexpr unsigned rem = nbits % bitsInBlk;
2,834,569✔
1509

1510
        // little-endian: most significant block is at index nBlks - 1
1511
        unsigned blockIdx = nBlks - 1;
2,834,569✔
1512

1513
        // check if the blocks are aligned with the representation
1514
        if constexpr (rem > 0) {
1515
                // the top bits are unaligned: construct the right mask
1516
                BlockType mask = BlockType(BlockType(1u) << (rem - 1u));
2,834,554✔
1517
                while (mask != 0) {
47,422,871✔
1518
                        if (v._block[blockIdx] & mask) return msb;
45,908,392✔
1519
                        --msb;
44,588,317✔
1520
                        mask >>= 1;
44,588,317✔
1521
                }
1522
                if (msb < 0) return msb;
1,514,479✔
1523
                if (blockIdx == 0) return msb;
1,514,473✔
1524
                --blockIdx;
1,514,473✔
1525
        }
1526
        // invariant: msb is now aligned with the blocks
1527
        while (true) {
871,555✔
1528
                if (v._block[blockIdx] != 0) {
2,386,043✔
1529
                        BlockType mask = BlockMsb;
1,514,488✔
1530
                        while (mask != 0) {
35,436,604✔
1531
                                if (v._block[blockIdx] & mask) return msb;
35,436,604✔
1532
                                --msb;
33,922,116✔
1533
                                mask >>= 1;
33,922,116✔
1534
                        }
1535
                }
1536
                else {
1537
                        msb -= static_cast<signed>(bitsInBlk);
871,555✔
1538
                }
1539
                if (blockIdx == 0) break;
871,555✔
1540
                --blockIdx;
871,555✔
1541
        }
1542
        return msb; // == -1 if no significant bit found
×
1543
}
1544

1545
////////////////////////    INTEGER operators   /////////////////////////////////
1546

1547
// remainder returns a mod b in c
1548
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1549
void remainder(integer<nbits, BlockType, NumberType>& c, const integer<nbits, BlockType, NumberType>& a, const integer<nbits, BlockType, NumberType>& b) {
1550
        if (b == integer<nbits, BlockType, NumberType>(0)) {
1551
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1552
                throw integer_divide_by_zero{};
1553
#else
1554
                std::cerr << "integer_divide_by_zero\n";
1555
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1556
        }
1557
        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(a, b);
1558
        c = divresult.rem;
1559
}
1560

1561
// divide integer<nbits, BlockType, NumberType> a and b and return result argument
1562
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1563
constexpr idiv_t<nbits, BlockType, NumberType> idiv(const integer<nbits, BlockType, NumberType>& _a, const integer<nbits, BlockType, NumberType>& _b) {
1,692,148✔
1564
        if (_b.iszero()) {
1,692,148✔
1565
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1566
                throw integer_divide_by_zero{};
1,184✔
1567
#else
1568
                // When exceptions are disabled we still must avoid the actual
1569
                // long-division below (UB on integer div-by-zero; constexpr would
1570
                // be ill-formed). Return zeroed quot/rem and bail out.
1571
                if (!std::is_constant_evaluated()) {
×
1572
                        std::cerr << "integer_divide_by_zero\n";
×
1573
                }
1574
                idiv_t<nbits, BlockType, NumberType> zeroed;
×
1575
                return zeroed;
×
1576
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1577
        }
1578

1579
        idiv_t<nbits, BlockType, NumberType> divresult;
1,690,964✔
1580
        divresult.rem = 0;
1,690,964✔
1581
        divresult.quot = 0;
1,690,964✔
1582

1583
        // generate the absolute values to do long division
1584
        if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1585
                using Integer = integer<nbits+1, BlockType, NumberType>;
1586
                // 2's complement special case -max requires an signed int that is 1 bit bigger to represent abs()
1587
                bool a_negative = _a.sign();
1,690,964✔
1588
                bool b_negative = _b.sign();
1,690,964✔
1589
                bool result_negative = (a_negative ^ b_negative);
1,690,964✔
1590
                Integer a; a.bitcopy(a_negative ? -_a : _a);
1,690,964✔
1591
                Integer b; b.bitcopy(b_negative ? -_b : _b);
1,690,964✔
1592

1593
                if (a < b) {
1,690,964✔
1594
                        divresult.quot = 0; // a / b = 0
273,817✔
1595
                        divresult.rem = _a; // a % b = a when a / b = 0
273,817✔
1596
                        return divresult;
273,817✔
1597
                }
1598
                // initialize the long division
1599
                integer<nbits + 1, BlockType, NumberType> accumulator = a;
1,417,147✔
1600
                // prepare the subtractand
1601
                integer<nbits + 1, BlockType, NumberType> subtractand = b;
1,417,147✔
1602
                int msb_b = findMsb(b);
1,417,147✔
1603
                int msb_a = findMsb(a);
1,417,147✔
1604
                int shift = msb_a - msb_b;
1,417,147✔
1605
                subtractand <<= shift;
1,417,147✔
1606
                divresult.quot = 0;
1,417,147✔
1607
                // long division
1608
                for (int i = shift; i >= 0; --i) {
5,547,567✔
1609
                        if (subtractand <= accumulator) {
4,130,420✔
1610
                                accumulator -= subtractand;
2,550,228✔
1611
                                divresult.quot.setbit(static_cast<unsigned>(i));
2,550,228✔
1612
                        }
1613
                        else {
1614
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
1,580,192✔
1615
                        }
1616
                        subtractand >>= 1;
4,130,420✔
1617
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1618
                }
1619
                if (result_negative) {  // take 2's complement
1,417,147✔
1620
                        divresult.quot.flip();
133,369✔
1621
                        divresult.quot += 1;
133,369✔
1622
                }
1623
                if (_a.isneg()) {
1,417,147✔
1624
                        divresult.rem = -accumulator;
133,961✔
1625
                }
1626
                else {
1627
                        divresult.rem = accumulator;
1,283,186✔
1628
                }
1629
        }
1630
        else {
1631
                if (_a < _b) {
×
1632
                        divresult.rem = _a; // a % b = a when a / b = 0
×
1633
                        return divresult; // a / b = 0 when b > a
×
1634
                }
1635
                using Integer = integer<nbits, BlockType, NumberType>;
1636
                Integer accumulator(_a), subtractand(_b);
×
1637
                int msb_b = findMsb(_b);
×
1638
                int msb_a = findMsb(_a);
×
1639
                int shift = msb_a - msb_b;
×
1640
                subtractand <<= shift;
×
1641
                // long division
1642
                for (int i = shift; i >= 0; --i) {
×
1643
                        if (subtractand <= accumulator) {
×
1644
                                accumulator -= subtractand;
×
1645
                                divresult.quot.setbit(static_cast<unsigned>(i));
×
1646
                        }
1647
                        else {
1648
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
×
1649
                        }
1650
                        subtractand >>= 1;
×
1651
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1652
                }
1653
                divresult.rem = accumulator;
×
1654
        }
1655

1656
        return divresult;
1,417,147✔
1657
}
1658

1659
/// stream operators
1660

1661
// read a integer ASCII format and make a binary integer out of it
1662
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1663
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& value) {
24✔
1664
        bool bSuccess = false;
24✔
1665
        value.clear();
24✔
1666
        // check if the txt is an integer form: [0123456789]+
1667
        std::regex decimal_regex("^[-+]*[0-9]+");
24✔
1668
        std::regex octal_regex("^[-+]*0[1-7][0-7]*$");
24✔
1669
        std::regex hex_regex("^[-+]*0[xX][0-9a-fA-F']+");
24✔
1670
        // setup associative array to map chars to nibbles
1671
        static std::map<char, int> charLookup{
38✔
1672
                { '0', 0 },
1673
                { '1', 1 },
1674
                { '2', 2 },
1675
                { '3', 3 },
1676
                { '4', 4 },
1677
                { '5', 5 },
1678
                { '6', 6 },
1679
                { '7', 7 },
1680
                { '8', 8 },
1681
                { '9', 9 },
1682
                { 'a', 10 },
1683
                { 'b', 11 },
1684
                { 'c', 12 },
1685
                { 'd', 13 },
1686
                { 'e', 14 },
1687
                { 'f', 15 },
1688
                { 'A', 10 },
1689
                { 'B', 11 },
1690
                { 'C', 12 },
1691
                { 'D', 13 },
1692
                { 'E', 14 },
1693
                { 'F', 15 },
1694
        };
1695
        if (std::regex_match(number, octal_regex)) {
24✔
1696
                std::cout << "found an octal representation\n";
×
1697
                for (std::string::const_reverse_iterator r = number.rbegin();
×
1698
                        r != number.rend();
×
1699
                        ++r) {
×
1700
                        std::cout << "char = " << *r << std::endl;
×
1701
                }
1702
                bSuccess = false; // TODO
×
1703
        }
1704
        else if (std::regex_match(number, hex_regex)) {
24✔
1705
                //std::cout << "found a hexadecimal representation\n";
1706
                // each char is a nibble
1707
                int maxByteIndex = nbits / 8;
15✔
1708
                int byte = 0;
15✔
1709
                int byteIndex = 0;
15✔
1710
                bool odd = false;
15✔
1711
                for (std::string::const_reverse_iterator r = number.rbegin();
15✔
1712
                        r != number.rend() && byteIndex < maxByteIndex;
580✔
1713
                        ++r) {
565✔
1714
                        if (*r == '\'') {
569✔
1715
                                // ignore
1716
                        }
1717
                        else if (*r == 'x' || *r == 'X') {
468✔
1718
                                if (odd) {
4✔
1719
                                        // complete the most significant byte
1720
                                        value.setbyte(static_cast<unsigned>(byteIndex), static_cast<uint8_t>(byte));
×
1721
                                }
1722
                                // check that we have [-+]0[xX] format
1723
                                ++r;
4✔
1724
                                if (r != number.rend()) {
4✔
1725
                                        if (*r == '0') {
4✔
1726
                                                // check if we have a sign
1727
                                                ++r;
4✔
1728
                                                if (r == number.rend()) {
4✔
1729
                                                        // no sign, thus by definition positive
1730
                                                        bSuccess = true;
4✔
1731
                                                }
1732
                                                else if (*r == '+') {
×
1733
                                                        // optional positive sign, no further action necessary
1734
                                                        bSuccess = true;
×
1735
                                                }
1736
                                                else if (*r == '-') {
×
1737
                                                        // negative sign, invert
1738
                                                        value = -value;
×
1739
                                                        bSuccess = true;
×
1740
                                                }
1741
                                                else {
1742
                                                        // the regex will have filtered this out
1743
                                                        return false;
×
1744
                                                }
1745
                                        }
1746
                                        else {
1747
                                                // we didn't find the obligatory '0', the regex should have filtered this out
1748
                                                return false;
×
1749
                                        }
1750
                                }
1751
                                else {
1752
                                        // we are missing the obligatory '0', the regex should have filtered this out
1753
                                        return false;
×
1754
                                }
1755
                                // we have reached the end of our parse
1756
                                break;
4✔
1757
                        }
1758
                        else {
1759
                                if (odd) {
464✔
1760
                                        byte += charLookup.at(*r) << 4;
232✔
1761
                                        value.setbyte(static_cast<unsigned>(byteIndex), static_cast<uint8_t>(byte));
232✔
1762
                                        ++byteIndex;
232✔
1763
                                }
1764
                                else {
1765
                                        byte = charLookup.at(*r);
232✔
1766
                                }
1767
                                odd = !odd;
464✔
1768
                        }
1769
                }
1770
                bSuccess = true;
15✔
1771
        }
1772
        else if (std::regex_match(number, decimal_regex)) {
9✔
1773
                //std::cout << "found a decimal integer representation\n";
1774
                integer<nbits, BlockType, NumberType> scale = 1;
9✔
1775
                for (std::string::const_reverse_iterator r = number.rbegin();
9✔
1776
                        r != number.rend();
92✔
1777
                        ++r) {
83✔
1778
                        if (*r == '-') {
83✔
1779
                                value = -value;
2✔
1780
                        }
1781
                        else if (*r == '+') {
81✔
1782
                                break;
×
1783
                        }
1784
                        else {
1785
                                integer<nbits, BlockType, NumberType> digit = charLookup.at(*r);
81✔
1786
                                value += scale * digit;
81✔
1787
                                scale *= 10;
81✔
1788
                        }
1789
                }
1790
                bSuccess = true;
9✔
1791
        }
1792

1793
        return bSuccess;
24✔
1794
}
24✔
1795

1796
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1797
std::string to_string(const integer<nbits, BlockType, NumberType>& n) {
2✔
1798
        return convert_to_decimal_string(n);
2✔
1799
}
1800

1801
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1802
std::string convert_to_string(std::ios_base::fmtflags flags, const integer<nbits, BlockType, NumberType>& n) {
4,279✔
1803
        using IntegerBase = integer<nbits, BlockType, NumberType>;
1804

1805
        // set the base of the target number system to convert to
1806
        int base = 10;
4,279✔
1807
        if ((flags & std::ios_base::oct) == std::ios_base::oct) base = 8;
4,279✔
1808
        if ((flags & std::ios_base::hex) == std::ios_base::hex) base = 16;
4,279✔
1809

1810
        std::string result;
4,279✔
1811
        if (base == 8 || base == 16) {
4,279✔
1812
                if (n.sign()) return std::string("negative value: ignored");
20✔
1813

1814
                BlockType shift = static_cast<BlockType>(base == 8 ? 3 : 4);
14✔
1815
                BlockType mask = static_cast<BlockType>((1u << shift) - 1);
14✔
1816
                IntegerBase t(n);
14✔
1817
                result.assign(nbits / shift + ((nbits % shift) ? 1 : 0), '0');
14✔
1818
                std::string::size_type pos = result.size() - 1u;
14✔
1819
                for (unsigned i = 0; i < nbits / static_cast<unsigned>(shift); ++i) {
42✔
1820
                        char c = '0' + static_cast<char>(t.block(0) & mask);
28✔
1821
                        if (c > '9')
28✔
1822
                                c += 'A' - '9' - static_cast<char>(1);
×
1823
                        result[pos--] = c;
28✔
1824
                        t >>= static_cast<int>(shift);
28✔
1825
                }
1826
                if (nbits % shift) {
14✔
1827
                        mask = static_cast<BlockType>((1u << (nbits % shift)) - 1);
7✔
1828
                        char c = '0' + static_cast<char>(t.block(0) & mask);
7✔
1829
                        if (c > '9')
7✔
1830
                                c += 'A' - '9';
×
1831
                        result[pos] = c;
7✔
1832
                }
1833
                //
1834
                // Get rid of leading zeros:
1835
                //
1836
                std::string::size_type fnz = result.find_first_not_of('0');
14✔
1837
                if (!result.empty() && (fnz == std::string::npos)) fnz = result.size() - 1;
14✔
1838
                result.erase(0, fnz);
14✔
1839
                if (flags & std::ios_base::showbase) {
14✔
1840
                        const char* pp = base == 8 ? "0" : "0x";
×
1841
                        result.insert(0ull, pp);
×
1842
                }
1843
        }
14✔
1844
        else {
1845
                using Integer = integer<nbits + 1, BlockType, NumberType>;  // nbits+1 to be able to represent maxneg in 2's complement form
1846

1847
                Integer t(n);
4,263✔
1848
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1849
                        if (t.sign()) t.twosComplement();
4,263✔
1850
                }
1851

1852
                Integer block10;
1853
                unsigned digits_in_block10 = 2;
4,263✔
1854
                if constexpr (IntegerBase::bitsInBlock == 8) {
1855
                        block10 = 100u;
3,507✔
1856
                        digits_in_block10 = 2;
3,507✔
1857
                }
1858
                else if constexpr (IntegerBase::bitsInBlock == 16) {
1859
                        block10 = 10'000u;
4✔
1860
                        digits_in_block10 = 4;
4✔
1861
                }
1862
                else if constexpr (IntegerBase::bitsInBlock == 32) {
1863
                        block10 = 1'000'000'000ul;
552✔
1864
                        digits_in_block10 = 9;
552✔
1865
                }
1866
                else if constexpr (IntegerBase::bitsInBlock == 64) {
1867
                        block10 = 1'000'000'000'000'000'000ull;
200✔
1868
                        digits_in_block10 = 18;
200✔
1869
                }
1870

1871
                result.assign(nbits / 3 + 1u, '0');
4,263✔
1872
                int pos = static_cast<int>(result.size() - 1u);
4,263✔
1873
                while (!t.iszero()) {
23,801✔
1874
                        Integer t2 = t / block10;
20,646✔
1875
                        Integer r  = t % block10;
20,646✔
1876
                        BlockType v = r.block(0);
20,646✔
1877
                        for (unsigned i = 0; i < digits_in_block10; ++i) {
93,378✔
1878
                                char c = '0' + static_cast<char>(v % 10);
73,840✔
1879
                                v /= 10;
73,840✔
1880
                                result[static_cast<unsigned>(pos)] = c;
73,840✔
1881
//                                std::cout << "result : " << result << " : pos : " << pos << '\n';
1882
                                if (pos-- == 0) break;
73,840✔
1883
                        }
1884
                        t = t2;
20,646✔
1885
                        if (pos < 0) break;
20,646✔
1886
                }
1887

1888
                std::string::size_type firstDigit = result.find_first_not_of('0');
4,263✔
1889
                result.erase(0, firstDigit);
4,263✔
1890
                if (result.empty())        result = std::string("0");
4,327✔
1891
                if (n.isneg()) { // no need to specialize as isneg() will return false for Natural and Whole Number types
4,263✔
1892
                        result.insert(static_cast<std::string::size_type>(0), 1, '-');
214✔
1893
                }
1894
                else if (flags & std::ios_base::showpos) {
4,049✔
1895
                        result.insert(static_cast<std::string::size_type>(0), 1, '+');
38✔
1896
                }
1897
        }
1898
        return result;
4,277✔
1899
}
4,279✔
1900

1901
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1902
inline std::ostream& operator<<(std::ostream& ostr, const integer<nbits, BlockType, NumberType>& i) {
4,279✔
1903
        std::string s = convert_to_string(ostr.flags(), i);
4,279✔
1904
        std::streamsize width = ostr.width();
4,279✔
1905
        if (width > static_cast<std::streamsize>(s.size())) {
4,279✔
1906
                char fill = ostr.fill();
288✔
1907
                if ((ostr.flags() & std::ios_base::left) == std::ios_base::left)
288✔
1908
                        s.append(static_cast<std::string::size_type>(width - s.size()), fill);
2✔
1909
                else
1910
                        s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(width - s.size()), fill);
286✔
1911
        }
1912
        return ostr << s;
8,558✔
1913
}
4,279✔
1914

1915
// read an ASCII integer format
1916
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1917
inline std::istream& operator>>(std::istream& istr, integer<nbits, BlockType, NumberType>& p) {
4✔
1918
        std::string txt;
4✔
1919
        istr >> txt;
4✔
1920
        if (!parse(txt, p)) {
4✔
1921
                std::cerr << "unable to parse -" << txt << "- into a posit value\n";
×
1922
        }
1923
        return istr;
4✔
1924
}
4✔
1925

1926
////////////////// string operators
1927
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1928
inline std::string to_binary(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
355✔
1929
        std::stringstream s;
355✔
1930
        s << "0b";
355✔
1931
        for (int i = nbits - 1; i >= 0; --i) {
12,287✔
1932
                s << (number.at(static_cast<unsigned>(i)) ? "1" : "0");
11,932✔
1933
                if (i > 0 && (i % 4) == 0 && nibbleMarker) s << '\'';
11,932✔
1934
        }
1935
        return s.str();
710✔
1936
}
355✔
1937

1938
// native semantic representation: radix-2, delegates to to_binary
1939
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1940
inline std::string to_native(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
1941
        return to_binary(number, nibbleMarker);
1942
}
1943

1944
//////////////////////////////////////////////////////////////////////////////////////////////////////
1945
// integer - integer binary logic operators
1946

1947
// equal: precondition is that the storage is properly nulled in all arithmetic paths
1948
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1949
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,400,282✔
1950
        for (unsigned i = 0; i < lhs.nrBlocks; ++i) {
6,440,363✔
1951
                if (lhs._block[i] != rhs._block[i]) return false;
4,436,341✔
1952
        }
1953
        return true;
2,004,022✔
1954
}
1955
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1956
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,002,909✔
1957
        return !operator==(lhs, rhs);
2,002,909✔
1958
}
1959
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1960
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
7,836,349✔
1961
        if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
1962
                for (int i = static_cast<int>(lhs.nrBlocks) - 1; i >= 0; --i) {
3✔
1963
                        if (lhs.block(static_cast<unsigned>(i)) == rhs.block(static_cast<unsigned>(i))) continue;
3✔
1964
                        if (lhs.block(static_cast<unsigned>(i)) < rhs.block(static_cast<unsigned>(i))) return true;
3✔
1965
                }
1966
                return false;
×
1967
        }
1968
        else {
1969
                bool lhs_is_negative = lhs.sign();
7,836,346✔
1970
                bool rhs_is_negative = rhs.sign();
7,836,346✔
1971
                if (lhs_is_negative && !rhs_is_negative) return true;
7,836,346✔
1972
                if (rhs_is_negative && !lhs_is_negative) return false;
7,636,025✔
1973
                // arguments have the same sign
1974
                integer<nbits, BlockType, NumberType> diff;
1975
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1976
                // we need to catch and ignore the exception
1977
                try {
1978
                        diff = (lhs - rhs);
2,194,912✔
1979
                }
1980
                catch (const integer_overflow& e) {
×
1981
                        // all good as the arithmetic is modulo
1982
                        const char* p = e.what();
×
1983
                        if (p) --p;
×
1984
                }
1985
#else 
1986
                diff = (lhs - rhs);
5,375,317✔
1987
#endif
1988
                return diff.sign();
7,570,229✔
1989
        }
1990
}
1991
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1992
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,198,317✔
1993
        return operator< (rhs, lhs);
4,198,317✔
1994
}
1995
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1996
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,198,039✔
1997
        return !operator> (lhs, rhs);
4,198,039✔
1998
}
1999
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2000
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
65,792✔
2001
        return !operator< (lhs, rhs);
65,792✔
2002
}
2003

2004
//////////////////////////////////////////////////////////////////////////////////////////////////////
2005
// integer - literal binary logic operators
2006
// equal: precondition is that the byte-storage is properly nulled in all arithmetic paths
2007
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2008
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
231,464✔
2009
        return operator==(lhs, integer<nbits, BlockType, NumberType>(rhs));
231,464✔
2010
}
2011
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2012
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
305✔
2013
        return !operator==(lhs, rhs);
305✔
2014
}
2015
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2016
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
1,477,658✔
2017
        return operator<(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,477,658✔
2018
}
2019
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2020
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
9,511✔
2021
        return operator< (integer<nbits, BlockType, NumberType>(rhs), lhs);
9,511✔
2022
}
2023
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2024
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
12✔
2025
        return operator< (lhs, rhs) || operator==(lhs, rhs);
12✔
2026
}
2027
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2028
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
668✔
2029
        return !operator< (lhs, rhs);
668✔
2030
}
2031

2032
//////////////////////////////////////////////////////////////////////////////////////////////////////
2033
// literal - integer binary logic operators
2034
// precondition is that the byte-storage is properly nulled in all arithmetic paths
2035

2036
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2037
constexpr inline bool operator==(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
13✔
2038
        return operator==(integer<nbits, BlockType, NumberType>(lhs), rhs);
13✔
2039
}
2040
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2041
constexpr inline bool operator!=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2042
        return !operator==(lhs, rhs);
6✔
2043
}
2044
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2045
constexpr inline bool operator< (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
18✔
2046
        return operator<(integer<nbits, BlockType, NumberType>(lhs), rhs);
18✔
2047
}
2048
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2049
constexpr inline bool operator> (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2050
        return operator< (rhs, lhs);
6✔
2051
}
2052
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2053
constexpr inline bool operator<=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2054
        return operator< (lhs, rhs) || operator==(lhs, rhs);
6✔
2055
}
2056
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2057
constexpr inline bool operator>=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2058
        return !operator< (lhs, rhs);
6✔
2059
}
2060

2061
//////////////////////////////////////////////////////////////////////////////////////////////////////
2062

2063
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2064
constexpr inline integer<nbits, BlockType, NumberType> operator<<(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
180✔
2065
        integer<nbits, BlockType, NumberType> shifted(lhs);
180✔
2066
        return (shifted <<= shift);
360✔
2067
}
2068

2069
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2070
constexpr inline integer<nbits, BlockType, NumberType> operator>>(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
76✔
2071
        integer<nbits, BlockType, NumberType> shifted(lhs);
76✔
2072
        return (shifted >>= shift);
152✔
2073
}
2074

2075
//////////////////////////////////////////////////////////////////////////////////////////////////////
2076
// integer - integer binary arithmetic operators
2077
// BINARY ADDITION
2078
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2079
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
8,878,333✔
2080
        integer<nbits, BlockType, NumberType> sum(lhs);
8,878,333✔
2081
        sum += rhs;
8,878,333✔
2082
        return sum;
8,878,333✔
2083
}
2084
// BINARY SUBTRACTION
2085
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2086
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
16,437,017✔
2087
        integer<nbits, BlockType, NumberType> diff(lhs);
16,437,017✔
2088
        diff -= rhs;
16,437,017✔
2089
        return diff;
16,437,015✔
2090
}
2091
// BINARY MULTIPLICATION
2092
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2093
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,220,559✔
2094
        integer<nbits, BlockType, NumberType> mul(lhs);
3,220,559✔
2095
        mul *= rhs;
3,220,559✔
2096
        return mul;
3,220,559✔
2097
}
2098
// BINARY DIVISION
2099
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2100
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,847,600✔
2101
        integer<nbits, BlockType, NumberType> ratio(lhs);
4,847,600✔
2102
        ratio /= rhs;
4,847,600✔
2103
        return ratio;
4,846,238✔
2104
}
2105
// BINARY REMAINDER
2106
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2107
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,270,843✔
2108
        integer<nbits, BlockType, NumberType> ratio(lhs);
3,270,843✔
2109
        ratio %= rhs;
3,270,843✔
2110
        return ratio;
3,270,507✔
2111
}
2112
// BINARY BIT-WISE AND
2113
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2114
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2115
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2116
        bitwise &= rhs;
2117
        return bitwise;
2118
}
2119
// BINARY BIT-WISE OR
2120
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2121
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2122
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2123
        bitwise |= rhs;
2124
        return bitwise;
2125
}
2126
// BINARY BIT-WISE XOR
2127
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2128
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2129
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2130
        bitwise ^= rhs;
2131
        return bitwise;
2132
}
2133

2134
//////////////////////////////////////////////////////////////////////////////////////////////////////
2135
// integer - literal binary arithmetic operators
2136
// BINARY ADDITION
2137
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2138
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
489✔
2139
        return operator+(lhs, integer<nbits, BlockType, NumberType>(rhs));
489✔
2140
}
2141
// BINARY SUBTRACTION
2142
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2143
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
197,088✔
2144
        return operator-(lhs, integer<nbits, BlockType, NumberType>(rhs));
197,088✔
2145
}
2146
// BINARY MULTIPLICATION
2147
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2148
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4,460✔
2149
        return operator*(lhs, integer<nbits, BlockType, NumberType>(rhs));
4,460✔
2150
}
2151
// BINARY DIVISION
2152
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2153
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1,513✔
2154
        return operator/(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,513✔
2155
}
2156
// BINARY REMAINDER
2157
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2158
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4✔
2159
        return operator%(lhs, integer<nbits, BlockType, NumberType>(rhs));
4✔
2160
}
2161
// BINARY BIT-WISE AND
2162
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2163
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2164
        return operator&(lhs, integer<nbits, BlockType, NumberType>(rhs));
2165
}
2166
// BINARY BIT-WISE OR
2167
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2168
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2169
        return operator|(lhs, integer<nbits, BlockType, NumberType>(rhs));
2170
}
2171
// BINARY BIT-WISE XOR
2172
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2173
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2174
        return operator^(lhs, integer<nbits, BlockType, NumberType>(rhs));
2175
}
2176
//////////////////////////////////////////////////////////////////////////////////////////////////////
2177
// literal - integer binary arithmetic operators
2178
// BINARY ADDITION
2179
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2180
constexpr inline integer<nbits, BlockType, NumberType> operator+(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1✔
2181
        return operator+(integer<nbits, BlockType, NumberType>(lhs), rhs);
1✔
2182
}
2183
// BINARY SUBTRACTION
2184
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2185
constexpr inline integer<nbits, BlockType, NumberType> operator-(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2186
        return operator-(integer<nbits, BlockType, NumberType>(lhs), rhs);
2187
}
2188
// BINARY MULTIPLICATION
2189
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2190
constexpr inline integer<nbits, BlockType, NumberType> operator*(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4✔
2191
        return operator*(integer<nbits, BlockType, NumberType>(lhs), rhs);
4✔
2192
}
2193
// BINARY DIVISION
2194
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2195
constexpr inline integer<nbits, BlockType, NumberType> operator/(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2196
        return operator/(integer<nbits, BlockType, NumberType>(lhs), rhs);
2197
}
2198
// BINARY REMAINDER
2199
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2200
constexpr inline integer<nbits, BlockType, NumberType> operator%(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2201
        return operator%(integer<nbits, BlockType, NumberType>(lhs), rhs);
2202
}
2203
// BINARY BIT-WISE AND
2204
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2205
constexpr inline integer<nbits, BlockType, NumberType> operator&(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2206
        return operator&(integer<nbits, BlockType, NumberType>(lhs), rhs);
2207
}
2208
// BINARY BIT-WISE OR
2209
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2210
constexpr inline integer<nbits, BlockType, NumberType> operator|(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2211
        return operator|(integer<nbits, BlockType, NumberType>(lhs), rhs);
2212
}
2213
// BINARY BIT-WISE XOR
2214
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2215
constexpr inline integer<nbits, BlockType, NumberType> operator^(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2216
        return operator^(integer<nbits, BlockType, NumberType>(lhs), rhs);
2217
}
2218

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

© 2026 Coveralls, Inc