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

stillwater-sc / universal / 25962306993

16 May 2026 12:47PM UTC coverage: 83.984% (+0.06%) from 83.929%
25962306993

push

github

web-flow
feat(integer, fixpnt): migrate/implement parse() onto string_parse (Phase B1 of #835) (#839)

* feat(integer, fixpnt): migrate/implement parse() onto string_parse (Phase B1 of #835)

Phase B1 of issue #835: bring `integer` and `fixpnt` onto the shared
constexpr string-parsing foundation that landed in Phase A (#838).

integer
-------
Replaces the std::regex + std::map + reverse-iteration parser body in
parse(const std::string&, integer&) with a clean MSB-first scan that
delegates prefix/sign detection and character classification to the
`sw::universal::string_parse` primitives.

Notable functional changes:
  - The previous octal branch was a `// TODO` that always returned false
    after detecting C-style leading-zero octal. Replaced with a real
    implementation gated on the explicit `0o` / `0O` prefix.
  - Binary (`0b` / `0B`) is newly supported.
  - Hex still accepts apostrophe as a digit separator (e.g. `0xDE'AD').
  - Decimal accepts a single optional leading `+` or `-`.
  - Drops the `<regex>` and `<map>` includes from integer_impl.hpp.

fixpnt
------
`fixpnt::parse()` was previously forward-declared (fixpnt_fwd.hpp:22) and
called by `operator>>` (fixpnt_impl.hpp:2073) but had no definition --
a latent link error that nobody had hit because no test exercises stream
input on fixpnt. This PR provides the definition.

Accepted syntax:
  [+-]? ( 0[bB][01]+ | 0[oO][0-7]+ | 0[xX][0-9A-F']+ | [0-9]+ )

Bit-pattern parsing (binary / octal / hex) fills the underlying storage
MSB-first via setbit(0) + left shift -- matches the convention of
setbits(). Decimal parsing is integer-only in this phase: the digit
string is accumulated as an integer K and stored as `K << rbits`, so
parse("5") on fixpnt<8,4> yields the value 5.0. Decimal-fraction
parsing ("3.14") is deferred to Phase B2 along with the analogous
float-from-string work for posit and cfloat.

Tests
-----
- static/integer/binary/api/string_parse.cpp -- 33 assertions covering
  decimal, binary, octal... (continued)

104 of 110 new or added lines in 2 files covered. (94.55%)

1 existing line in 1 file now uncovered.

46103 of 54895 relevant lines covered (83.98%)

6455983.32 hits per line

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

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

16
// supporting types and functions
17
#include <universal/number/shared/specific_value_encoding.hpp>
18
#include <universal/number/shared/blocktype.hpp>
19
#include <universal/native/integers.hpp> // just for printing native integers in binary form
20
#include <universal/internal/blocktype/carry.hpp> // carry-detection intrinsics for uint64_t limbs
21
#include <universal/utility/string_parse.hpp>   // shared constexpr scan_prefix / scan_sign / char classifiers
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,954,111✔
135
//                static_assert(srcbits > nbits, "Source integer is bigger than target: potential loss of precision"); // TODO: do we want this?
136
                bitcopy(a);
1,954,111✔
137
                if constexpr (srcbits < nbits && NumberType == IntegerNumberType::IntegerNumber) {
138
                        if (a.sign()) { // sign extend
536,854✔
139
                                for (unsigned i = srcbits; i < nbits; ++i) {
523,664✔
140
                                        setbit(i);
261,832✔
141
                                }
142
                        }
143
                }
144
        }
1,954,111✔
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,105,881✔
150
        constexpr integer(long initial_value)               noexcept { *this = initial_value; }
14✔
151
        constexpr integer(long long initial_value)          noexcept { *this = initial_value; }
203,573✔
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; }
132✔
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,317,745✔
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,358✔
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,643✔
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,726✔
226
                integer negated(*this);
666,726✔
227
                negated.flip();
666,726✔
228
                negated += 1;
666,726✔
229
                return negated;
666,726✔
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,520,204✔
244
                *this += integer(1);
22,520,204✔
245
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
22,520,204✔
246
                return *this;
22,520,204✔
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,211,928✔
279
                if constexpr (nrBlocks == 1) {
280
                        _block[0] = static_cast<bt>(_block[0] + rhs.block(0));
34,957,620✔
281
                        // null any leading bits that fall outside of nbits
282
                        _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
34,957,620✔
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,088,312✔
317
                        for (unsigned i = 0; i < nrBlocks; ++i) {
103,755,701✔
318
                                carry += static_cast<std::uint64_t>(_block[i]) + static_cast<std::uint64_t>(rhs._block[i]);
88,667,389✔
319
                                sum._block[i] = static_cast<bt>(carry);
88,667,389✔
320
                                carry >>= bitsInBlock;
88,667,389✔
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,088,312✔
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,088,312✔
330
                }
331
                return *this;
51,211,928✔
332
        }
333
        constexpr integer& operator-=(const integer& rhs) {
19,012,878✔
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) {
353
                                if (*this == rhs) {
×
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);
19,012,869✔
380
                        operator+=(twos.twosComplement());
19,012,869✔
381
                }
382
                return *this;
19,012,876✔
383
        }
384
        constexpr integer& operator*=(const integer& rhs) {
3,220,601✔
385
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
386
                        if constexpr (nrBlocks == 1) {
387
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
3,215,875✔
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,525✔
459
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
4,525✔
460
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
4,525✔
461
                                if (base.isneg()) {
4,525✔
462
                                        base.twosComplement();
×
463
                                }
464
                                if (multiplicant.isneg()) {
4,525✔
465
                                        multiplicant.twosComplement();
×
466
                                }
467
                                clear();
4,525✔
468
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
39,512✔
469
                                        std::uint64_t segment(0);
34,987✔
470
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
427,454✔
471
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
392,467✔
472

473
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
392,467✔
474
                                                        segment += _block[i + j];
213,727✔
475
                                                        _block[i + j] = static_cast<bt>(segment);
213,727✔
476
                                                        segment >>= bitsInBlock;
213,727✔
477
                                                }
478
                                        }
479
                                }
480
                                if (resultIsNeg) twosComplement();
4,525✔
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,601✔
555
                return *this;
3,220,601✔
556
        }
557
        constexpr integer& operator*=(const BlockType& scale) noexcept {
88✔
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);
88✔
590
                        for (unsigned i = 0; i < nrBlocks; ++i) {
176✔
591
                                segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
88✔
592
                                _block[i] = static_cast<BlockType>(segment);
88✔
593
                                segment >>= bitsInBlock;
88✔
594
                        }
595
                }
596
                return *this;
88✔
597
        }
598
        constexpr integer& operator/=(const integer& rhs) {
4,847,732✔
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,572✔
643
                        *this = divresult.quot;
1,631,468✔
644
                }
645
                return *this;
4,846,369✔
646
        }
647
        constexpr integer& operator%=(const integer& rhs) {
3,270,919✔
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,654✔
679
                        *this = divresult.rem;
59,574✔
680
                }
681

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

685
        // arithmetic shift right operator
686
        constexpr integer& operator<<=(int bitsToShift) {
1,418,200✔
687
                if (bitsToShift == 0) return *this;
1,418,200✔
688
                if (bitsToShift < 0) return operator>>=(-bitsToShift);
278,361✔
689
                if (bitsToShift > static_cast<int>(nbits)) {
278,321✔
690
                        setzero();
×
691
                        return *this;
×
692
                }
693
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
278,321✔
694
                        int blockShift = bitsToShift / static_cast<int>(bitsInBlock);
92,380✔
695
                        for (int i = static_cast<int>(MSU); i >= blockShift; --i) {
679,318✔
696
                                _block[i] = bt(_block[i - blockShift]);
586,938✔
697
                        }
698
                        for (int i = blockShift - 1; i >= 0; --i) {
291,951✔
699
                                _block[i] = bt(0);
199,571✔
700
                        }
701
                        // adjust the shift
702
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
92,380✔
703
                        if (bitsToShift == 0) {
92,380✔
704
                                _block[MSU] &= MSU_MASK;
5,398✔
705
                                return *this;
5,398✔
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);
183,178✔
711
                        for (unsigned i = MSU; i > 0; --i) {
1,017,611✔
712
                                _block[i] <<= bitsToShift;
834,433✔
713
                                // mix in the bits from the right
714
                                bt bits = bt(mask & _block[i - 1]);
834,433✔
715
                                _block[i] |= (bits >> (bitsInBlock - bitsToShift));
834,433✔
716
                        }
717
                }
718
                _block[0] <<= bitsToShift;        
272,923✔
719
                _block[MSU] &= MSU_MASK; // null any leading bits that fall outside of nbits
272,923✔
720
                return *this;
272,923✔
721
        }
722
        constexpr integer& operator>>=(int bitsToShift) {
4,156,264✔
723
                if (bitsToShift == 0) return *this;
4,156,264✔
724
                if (bitsToShift < 0) return operator<<=(-bitsToShift);
4,156,260✔
725
                if (bitsToShift >= static_cast<int>(nbits)) {
4,156,260✔
726
                        setzero();
4✔
727
                        return *this;
4✔
728
                }
729
                bool signext = sign();
4,156,256✔
730
                unsigned blockShift = 0;
4,156,256✔
731
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
4,156,256✔
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,324,096✔
762
                        mask >>= (bitsInBlock - bitsToShift); // this is a mask for the lower bits in the block that need to move to the lower word
3,324,096✔
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
29,294,867✔
764
                                _block[i] >>= bitsToShift;
25,970,771✔
765
                                // mix in the bits from the left
766
                                bt bits = bt(mask & _block[i + 1]);
25,970,771✔
767
                                _block[i] |= (bits << (bitsInBlock - bitsToShift));
25,970,771✔
768
                        }
769
                }
770
                _block[MSU] >>= bitsToShift;
4,156,249✔
771

772
                // fix up the leading zeros if we have a negative number
773
                if (signext) {
4,156,249✔
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,156,188✔
783
                        for (unsigned i = nbits - bitsToShift; i < nbits; ++i) {
8,312,670✔
784
                                setbit(i, false);
4,156,482✔
785
                        }
786
                }
787

788
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
789
                _block[MSU] &= MSU_MASK;
4,156,249✔
790
                return *this;
4,156,249✔
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,385,551✔
832
                bt* p = _block;
33,385,551✔
833
                if constexpr (0 == nrBlocks) {
834
                        return;
835
                }
836
                else if constexpr (1 == nrBlocks) {
837
                        *p = bt(0);
19,625,828✔
838
                }
839
                else if constexpr (2 == nrBlocks) {
840
                        *p++ = bt(0);
8,615,899✔
841
                        *p = bt(0);
8,615,899✔
842
                }
843
                else if constexpr (3 == nrBlocks) {
844
                        *p++ = bt(0);
73,191✔
845
                        *p++ = bt(0);
73,191✔
846
                        *p   = bt(0);
73,191✔
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) {
61,127,550✔
856
                                *p++ = bt(0);
56,260,300✔
857
                        }
858
                }
859
        }
33,385,551✔
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,640,154✔
887
                unsigned blockIndex = i / bitsInBlock;
40,640,154✔
888
                if (blockIndex < nrBlocks) {
40,640,154✔
889
                        bt block = _block[blockIndex];
40,640,154✔
890
                        bt null = ~(1ull << (i % bitsInBlock));
40,640,154✔
891
                        bt bit = bt(v ? 1 : 0);
40,640,154✔
892
                        bt mask = bt(bit << (i % bitsInBlock));
40,640,154✔
893
                        _block[blockIndex] = bt((block & null) | mask);
40,640,154✔
894
                }
895
                // nop if out of bounds
896
        }
40,640,154✔
897
        constexpr void setbyte(unsigned byteIndex, uint8_t data) {
898
                uint8_t mask = 0x1u;
899
                unsigned start = byteIndex * 8;
900
                unsigned end = start + 8;
901
                for (unsigned i = start; i < end; ++i) {
902
                        setbit(i, static_cast<bool>(mask & data));
903
                        mask <<= 1;
904
                }
905
        }
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,336,195✔
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,905,075✔
989
                        _block[i] = src.block(i);
10,568,880✔
990
                }
991
                _block[MSU] &= MSU_MASK; // assert precondition of properly nulled leading non-bits
5,336,195✔
992
        }
5,336,195✔
993
        // in-place one's complement
994
        constexpr integer& flip() {
20,140,502✔
995
                for (unsigned i = 0; i < nrBlocks; ++i) {
85,703,159✔
996
                        _block[i] = static_cast<bt>(~_block[i]);
65,562,657✔
997
                }
998
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
20,140,502✔
999
                return *this;
20,140,502✔
1000
        }
1001
        // in-place 2's complement
1002
        constexpr integer& twosComplement() {
19,340,341✔
1003
                flip();
19,340,341✔
1004
                return ++(*this);
19,340,341✔
1005
        }
1006

1007
        // selectors
1008
        constexpr bool iszero() const noexcept {
5,247,747✔
1009
                for (unsigned i = 0; i < nrBlocks; ++i) {
5,298,570✔
1010
                        if (_block[i] != 0) return false;
5,282,185✔
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,269✔
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,229,957✔
1030
        constexpr bool at(unsigned bitIndex) const noexcept {
34,299,861✔
1031
                if (bitIndex < nbits) {
34,299,861✔
1032
                        bt word = _block[bitIndex / bitsInBlock];
34,299,861✔
1033
                        bt mask = bt(1ull << (bitIndex % bitsInBlock));
34,299,861✔
1034
                        return (word & mask);
34,299,861✔
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,388,852✔
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,458,774✔
1249
                clear();
32,458,774✔
1250
                if (0 == rhs) {
32,458,774✔
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,606✔
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,076,165✔
1278
                for (unsigned i = 0; i < nbits && v != 0; ++i) {
58,961,294✔
1279
                        if (v & 0x1ull) setbit(i);
33,885,129✔
1280
                        v >>= 1;
33,885,129✔
1281
                }
1282
                if constexpr (nbits > 64) {
1283
                        if (rhs < 0) {        // sign extend if negative
3,629,762✔
1284
                                for (unsigned i = 64; i < nbits; ++i) {
65✔
1285
                                        setbit(i);
64✔
1286
                                }
1287
                        }
1288
                }
1289
                return *this;
25,076,165✔
1290
        }
1291
        // unsigned integer conversion
1292
        template<typename UnsignedInt>
1293
        constexpr integer& convert_unsigned(UnsignedInt rhs) {
527,274✔
1294
                clear();
527,274✔
1295
                if (0 == rhs) {
527,274✔
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,940✔
1305
                        }
1306
                }
1307
                uint64_t v = rhs;
391,334✔
1308
                constexpr unsigned argbits = sizeof(rhs);
391,334✔
1309
                unsigned upper = (nbits <= _nbits ? nbits : argbits);
391,334✔
1310
                for (unsigned i = 0; i < upper; ++i) {
4,357,732✔
1311
                        if (v & 0x1ull) setbit(i);
3,966,398✔
1312
                        v >>= 1;
3,966,398✔
1313
                }
1314
                return *this;
391,334✔
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,029✔
1370
                                for (unsigned i = upper; i < sizeoftarget; ++i) {
65,983,323✔
1371
                                        v |= mask;
64,812,294✔
1372
                                        mask <<= 1;
64,812,294✔
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,789✔
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,789✔
1505
        constexpr unsigned nBlks = IntegerT::nrBlocks;
2,834,789✔
1506
        constexpr BlockType BlockMsb = BlockType(BlockType(1u) << (bitsInBlk - 1));
2,834,789✔
1507
        signed msb = static_cast<signed>(IntegerT::nbits - 1ull); // the case for an aligned MSB
2,834,789✔
1508
        constexpr unsigned rem = nbits % bitsInBlk;
2,834,789✔
1509

1510
        // little-endian: most significant block is at index nBlks - 1
1511
        unsigned blockIdx = nBlks - 1;
2,834,789✔
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,774✔
1517
                while (mask != 0) {
47,423,387✔
1518
                        if (v._block[blockIdx] & mask) return msb;
45,908,752✔
1519
                        --msb;
44,588,613✔
1520
                        mask >>= 1;
44,588,613✔
1521
                }
1522
                if (msb < 0) return msb;
1,514,635✔
1523
                if (blockIdx == 0) return msb;
1,514,629✔
1524
                --blockIdx;
1,514,629✔
1525
        }
1526
        // invariant: msb is now aligned with the blocks
1527
        while (true) {
875,975✔
1528
                if (v._block[blockIdx] != 0) {
2,390,619✔
1529
                        BlockType mask = BlockMsb;
1,514,644✔
1530
                        while (mask != 0) {
35,440,773✔
1531
                                if (v._block[blockIdx] & mask) return msb;
35,440,773✔
1532
                                --msb;
33,926,129✔
1533
                                mask >>= 1;
33,926,129✔
1534
                        }
1535
                }
1536
                else {
1537
                        msb -= static_cast<signed>(bitsInBlk);
875,975✔
1538
                }
1539
                if (blockIdx == 0) break;
875,975✔
1540
                --blockIdx;
875,975✔
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,226✔
1564
        if (_b.iszero()) {
1,692,226✔
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,691,042✔
1580
        divresult.rem = 0;
1,691,042✔
1581
        divresult.quot = 0;
1,691,042✔
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,691,042✔
1588
                bool b_negative = _b.sign();
1,691,042✔
1589
                bool result_negative = (a_negative ^ b_negative);
1,691,042✔
1590
                Integer a; a.bitcopy(a_negative ? -_a : _a);
1,691,042✔
1591
                Integer b; b.bitcopy(b_negative ? -_b : _b);
1,691,042✔
1592

1593
                if (a < b) {
1,691,042✔
1594
                        divresult.quot = 0; // a / b = 0
273,785✔
1595
                        divresult.rem = _a; // a % b = a when a / b = 0
273,785✔
1596
                        return divresult;
273,785✔
1597
                }
1598
                // initialize the long division
1599
                integer<nbits + 1, BlockType, NumberType> accumulator = a;
1,417,257✔
1600
                // prepare the subtractand
1601
                integer<nbits + 1, BlockType, NumberType> subtractand = b;
1,417,257✔
1602
                int msb_b = findMsb(b);
1,417,257✔
1603
                int msb_a = findMsb(a);
1,417,257✔
1604
                int shift = msb_a - msb_b;
1,417,257✔
1605
                subtractand <<= shift;
1,417,257✔
1606
                divresult.quot = 0;
1,417,257✔
1607
                // long division
1608
                for (int i = shift; i >= 0; --i) {
5,564,122✔
1609
                        if (subtractand <= accumulator) {
4,146,865✔
1610
                                accumulator -= subtractand;
2,558,558✔
1611
                                divresult.quot.setbit(static_cast<unsigned>(i));
2,558,558✔
1612
                        }
1613
                        else {
1614
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
1,588,307✔
1615
                        }
1616
                        subtractand >>= 1;
4,146,865✔
1617
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1618
                }
1619
                if (result_negative) {  // take 2's complement
1,417,257✔
1620
                        divresult.quot.flip();
133,401✔
1621
                        divresult.quot += 1;
133,401✔
1622
                }
1623
                if (_a.isneg()) {
1,417,257✔
1624
                        divresult.rem = -accumulator;
133,961✔
1625
                }
1626
                else {
1627
                        divresult.rem = accumulator;
1,283,296✔
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,257✔
1657
}
1658

1659
/// stream operators
1660

1661
// read an integer ASCII format and make a binary integer out of it
1662
//
1663
// Accepted syntax (Phase B1 of issue #835 -- shared string_parse foundation):
1664
//
1665
//   [+-]? ( 0[bB][01]+      |    // binary bit-pattern
1666
//           0[oO][0-7]+     |    // octal bit-pattern
1667
//           0[xX][0-9A-F']+ |    // hex bit-pattern (apostrophe allowed as digit separator)
1668
//           [0-9]+          )    // decimal integer
1669
//
1670
// Notes vs. the historical regex-based parser:
1671
//   - Octal now requires the explicit 0o/0O prefix (the previous code accepted
1672
//     C-style leading-zero octal but the conversion path was a `// TODO` that
1673
//     always returned false, so no real behavior change).
1674
//   - Binary 0b/0B is newly supported.
1675
//   - Decimal accepts a single optional leading +/- (the previous regex
1676
//     accepted multiple sign chars; functional difference is nil).
1677
//
1678
// All scanning is delegated to the constexpr primitives in
1679
// `<universal/utility/string_parse.hpp>`; the parser itself uses only
1680
// `integer`'s own arithmetic.
1681
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1682
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& value) {
62✔
1683
        namespace sp = sw::universal::string_parse;
1684
        using Int = integer<nbits, BlockType, NumberType>;
1685

1686
        // Build into a local temporary and only commit to `value` on a fully
1687
        // successful parse. This keeps malformed input from leaving the caller's
1688
        // object in a partially-mutated state.
1689
        Int tmp;
1690
        tmp.clear();
62✔
1691

1692
        std::string_view s{number};
62✔
1693

1694
        // Strip leading sign (if any).
1695
        auto sg = sp::scan_sign(s);
62✔
1696
        const bool negative = sg.negative;
62✔
1697
        s = sg.rest;
62✔
1698
        if (s.empty()) return false;
62✔
1699

1700
        // Detect base prefix; no prefix -> decimal.
1701
        auto pfx = sp::scan_prefix(s);
60✔
1702
        std::string_view body = pfx.body;
60✔
1703
        if (body.empty()) return false;
60✔
1704

1705
        // Track whether any real digit was consumed so payloads of only separators
1706
        // (e.g. "0x'") are rejected rather than silently yielding zero.
1707
        bool digit_found = false;
58✔
1708

1709
        switch (pfx.base) {
58✔
1710
        case sp::number_base::binary: {
7✔
1711
                // MSB-first: shift the accumulator left by 1 per character, OR in the bit.
1712
                for (char c : body) {
62✔
1713
                        if (!sp::is_binary_digit(c)) return false;
56✔
1714
                        tmp <<= 1;
55✔
1715
                        if (c == '1') tmp.setbit(0, true);
55✔
1716
                        digit_found = true;
55✔
1717
                }
1718
                if (!digit_found) return false;
6✔
1719
                break;
6✔
1720
        }
1721
        case sp::number_base::octal: {
5✔
1722
                // MSB-first: shift by 3, OR in the 3-bit digit.
1723
                for (char c : body) {
14✔
1724
                        if (!sp::is_octal_digit(c)) return false;
10✔
1725
                        tmp <<= 3;
9✔
1726
                        unsigned digit = static_cast<unsigned>(c - '0');
9✔
1727
                        for (unsigned b = 0; b < 3; ++b) {
36✔
1728
                                if ((digit >> b) & 1u) tmp.setbit(b, true);
27✔
1729
                        }
1730
                        digit_found = true;
9✔
1731
                }
1732
                if (!digit_found) return false;
4✔
1733
                break;
4✔
1734
        }
1735
        case sp::number_base::hex: {
27✔
1736
                // MSB-first: shift by 4, OR in the nibble. Apostrophe is a separator.
1737
                for (char c : body) {
626✔
1738
                        if (c == '\'') continue;
601✔
1739
                        if (!sp::is_hex_digit(c)) return false;
493✔
1740
                        tmp <<= 4;
491✔
1741
                        unsigned digit = sp::hex_digit_value(c);
491✔
1742
                        for (unsigned b = 0; b < 4; ++b) {
2,455✔
1743
                                if ((digit >> b) & 1u) tmp.setbit(b, true);
1,964✔
1744
                        }
1745
                        digit_found = true;
491✔
1746
                }
1747
                if (!digit_found) return false;
25✔
1748
                break;
22✔
1749
        }
1750
        case sp::number_base::decimal: {
19✔
1751
                // MSB-first: multiply accumulator by 10, add digit. is_decimal_digit
1752
                // gates the loop body so digit_found tracking is redundant here, but
1753
                // kept for symmetry.
1754
                Int ten{10};
19✔
1755
                for (char c : body) {
136✔
1756
                        if (!sp::is_decimal_digit(c)) return false;
119✔
1757
                        tmp *= ten;
117✔
1758
                        Int digit{static_cast<unsigned>(c - '0')};
117✔
1759
                        tmp += digit;
117✔
1760
                        digit_found = true;
117✔
1761
                }
1762
                if (!digit_found) return false;
17✔
1763
                break;
17✔
1764
        }
NEW
1765
        default:
×
NEW
1766
                return false;
×
1767
        }
1768

1769
        if (negative) tmp = -tmp;
49✔
1770
        value = tmp;
49✔
1771
        return true;
49✔
1772
}
1773

1774
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1775
std::string to_string(const integer<nbits, BlockType, NumberType>& n) {
2✔
1776
        return convert_to_decimal_string(n);
2✔
1777
}
1778

1779
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1780
std::string convert_to_string(std::ios_base::fmtflags flags, const integer<nbits, BlockType, NumberType>& n) {
4,279✔
1781
        using IntegerBase = integer<nbits, BlockType, NumberType>;
1782

1783
        // set the base of the target number system to convert to
1784
        int base = 10;
4,279✔
1785
        if ((flags & std::ios_base::oct) == std::ios_base::oct) base = 8;
4,279✔
1786
        if ((flags & std::ios_base::hex) == std::ios_base::hex) base = 16;
4,279✔
1787

1788
        std::string result;
4,279✔
1789
        if (base == 8 || base == 16) {
4,279✔
1790
                if (n.sign()) return std::string("negative value: ignored");
20✔
1791

1792
                BlockType shift = static_cast<BlockType>(base == 8 ? 3 : 4);
14✔
1793
                BlockType mask = static_cast<BlockType>((1u << shift) - 1);
14✔
1794
                IntegerBase t(n);
14✔
1795
                result.assign(nbits / shift + ((nbits % shift) ? 1 : 0), '0');
14✔
1796
                std::string::size_type pos = result.size() - 1u;
14✔
1797
                for (unsigned i = 0; i < nbits / static_cast<unsigned>(shift); ++i) {
42✔
1798
                        char c = '0' + static_cast<char>(t.block(0) & mask);
28✔
1799
                        if (c > '9')
28✔
1800
                                c += 'A' - '9' - static_cast<char>(1);
×
1801
                        result[pos--] = c;
28✔
1802
                        t >>= static_cast<int>(shift);
28✔
1803
                }
1804
                if (nbits % shift) {
14✔
1805
                        mask = static_cast<BlockType>((1u << (nbits % shift)) - 1);
7✔
1806
                        char c = '0' + static_cast<char>(t.block(0) & mask);
7✔
1807
                        if (c > '9')
7✔
1808
                                c += 'A' - '9';
×
1809
                        result[pos] = c;
7✔
1810
                }
1811
                //
1812
                // Get rid of leading zeros:
1813
                //
1814
                std::string::size_type fnz = result.find_first_not_of('0');
14✔
1815
                if (!result.empty() && (fnz == std::string::npos)) fnz = result.size() - 1;
14✔
1816
                result.erase(0, fnz);
14✔
1817
                if (flags & std::ios_base::showbase) {
14✔
1818
                        const char* pp = base == 8 ? "0" : "0x";
×
1819
                        result.insert(0ull, pp);
×
1820
                }
1821
        }
14✔
1822
        else {
1823
                using Integer = integer<nbits + 1, BlockType, NumberType>;  // nbits+1 to be able to represent maxneg in 2's complement form
1824

1825
                Integer t(n);
4,263✔
1826
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1827
                        if (t.sign()) t.twosComplement();
4,263✔
1828
                }
1829

1830
                Integer block10;
1831
                unsigned digits_in_block10 = 2;
4,263✔
1832
                if constexpr (IntegerBase::bitsInBlock == 8) {
1833
                        block10 = 100u;
3,507✔
1834
                        digits_in_block10 = 2;
3,507✔
1835
                }
1836
                else if constexpr (IntegerBase::bitsInBlock == 16) {
1837
                        block10 = 10'000u;
4✔
1838
                        digits_in_block10 = 4;
4✔
1839
                }
1840
                else if constexpr (IntegerBase::bitsInBlock == 32) {
1841
                        block10 = 1'000'000'000ul;
552✔
1842
                        digits_in_block10 = 9;
552✔
1843
                }
1844
                else if constexpr (IntegerBase::bitsInBlock == 64) {
1845
                        block10 = 1'000'000'000'000'000'000ull;
200✔
1846
                        digits_in_block10 = 18;
200✔
1847
                }
1848

1849
                result.assign(nbits / 3 + 1u, '0');
4,263✔
1850
                int pos = static_cast<int>(result.size() - 1u);
4,263✔
1851
                while (!t.iszero()) {
23,804✔
1852
                        Integer t2 = t / block10;
20,649✔
1853
                        Integer r  = t % block10;
20,649✔
1854
                        BlockType v = r.block(0);
20,649✔
1855
                        for (unsigned i = 0; i < digits_in_block10; ++i) {
93,408✔
1856
                                char c = '0' + static_cast<char>(v % 10);
73,867✔
1857
                                v /= 10;
73,867✔
1858
                                result[static_cast<unsigned>(pos)] = c;
73,867✔
1859
//                                std::cout << "result : " << result << " : pos : " << pos << '\n';
1860
                                if (pos-- == 0) break;
73,867✔
1861
                        }
1862
                        t = t2;
20,649✔
1863
                        if (pos < 0) break;
20,649✔
1864
                }
1865

1866
                std::string::size_type firstDigit = result.find_first_not_of('0');
4,263✔
1867
                result.erase(0, firstDigit);
4,263✔
1868
                if (result.empty())        result = std::string("0");
4,327✔
1869
                if (n.isneg()) { // no need to specialize as isneg() will return false for Natural and Whole Number types
4,263✔
1870
                        result.insert(static_cast<std::string::size_type>(0), 1, '-');
198✔
1871
                }
1872
                else if (flags & std::ios_base::showpos) {
4,065✔
1873
                        result.insert(static_cast<std::string::size_type>(0), 1, '+');
38✔
1874
                }
1875
        }
1876
        return result;
4,277✔
1877
}
4,279✔
1878

1879
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1880
inline std::ostream& operator<<(std::ostream& ostr, const integer<nbits, BlockType, NumberType>& i) {
4,279✔
1881
        std::string s = convert_to_string(ostr.flags(), i);
4,279✔
1882
        std::streamsize width = ostr.width();
4,279✔
1883
        if (width > static_cast<std::streamsize>(s.size())) {
4,279✔
1884
                char fill = ostr.fill();
288✔
1885
                if ((ostr.flags() & std::ios_base::left) == std::ios_base::left)
288✔
1886
                        s.append(static_cast<std::string::size_type>(width - s.size()), fill);
2✔
1887
                else
1888
                        s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(width - s.size()), fill);
286✔
1889
        }
1890
        return ostr << s;
8,558✔
1891
}
4,279✔
1892

1893
// read an ASCII integer format.
1894
// On parse failure: log a diagnostic to std::cerr AND set failbit on the stream
1895
// so callers (loops with `while (in >> x)`, etc.) can detect the error without
1896
// scraping stderr. Symmetric with fixpnt's operator>>.
1897
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1898
inline std::istream& operator>>(std::istream& istr, integer<nbits, BlockType, NumberType>& p) {
4✔
1899
        std::string txt;
4✔
1900
        istr >> txt;
4✔
1901
        if (!parse(txt, p)) {
4✔
NEW
1902
                std::cerr << "unable to parse -" << txt << "- into an integer value\n";
×
NEW
1903
                istr.setstate(std::ios::failbit);
×
1904
        }
1905
        return istr;
4✔
1906
}
4✔
1907

1908
////////////////// string operators
1909
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1910
inline std::string to_binary(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
355✔
1911
        std::stringstream s;
355✔
1912
        s << "0b";
355✔
1913
        for (int i = nbits - 1; i >= 0; --i) {
12,287✔
1914
                s << (number.at(static_cast<unsigned>(i)) ? "1" : "0");
11,932✔
1915
                if (i > 0 && (i % 4) == 0 && nibbleMarker) s << '\'';
11,932✔
1916
        }
1917
        return s.str();
710✔
1918
}
355✔
1919

1920
// native semantic representation: radix-2, delegates to to_binary
1921
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1922
inline std::string to_native(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
1923
        return to_binary(number, nibbleMarker);
1924
}
1925

1926
//////////////////////////////////////////////////////////////////////////////////////////////////////
1927
// integer - integer binary logic operators
1928

1929
// equal: precondition is that the storage is properly nulled in all arithmetic paths
1930
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1931
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,400,381✔
1932
        for (unsigned i = 0; i < lhs.nrBlocks; ++i) {
6,440,493✔
1933
                if (lhs._block[i] != rhs._block[i]) return false;
4,436,444✔
1934
        }
1935
        return true;
2,004,049✔
1936
}
1937
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1938
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,002,936✔
1939
        return !operator==(lhs, rhs);
2,002,936✔
1940
}
1941
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1942
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
7,853,034✔
1943
        if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
1944
                for (int i = static_cast<int>(lhs.nrBlocks) - 1; i >= 0; --i) {
3✔
1945
                        if (lhs.block(static_cast<unsigned>(i)) == rhs.block(static_cast<unsigned>(i))) continue;
3✔
1946
                        if (lhs.block(static_cast<unsigned>(i)) < rhs.block(static_cast<unsigned>(i))) return true;
3✔
1947
                }
1948
                return false;
×
1949
        }
1950
        else {
1951
                bool lhs_is_negative = lhs.sign();
7,853,031✔
1952
                bool rhs_is_negative = rhs.sign();
7,853,031✔
1953
                if (lhs_is_negative && !rhs_is_negative) return true;
7,853,031✔
1954
                if (rhs_is_negative && !lhs_is_negative) return false;
7,652,726✔
1955
                // arguments have the same sign
1956
                integer<nbits, BlockType, NumberType> diff;
1957
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1958
                // we need to catch and ignore the exception
1959
                try {
1960
                        diff = (lhs - rhs);
2,211,613✔
1961
                }
1962
                catch (const integer_overflow& e) {
×
1963
                        // all good as the arithmetic is modulo
1964
                        const char* p = e.what();
×
1965
                        if (p) --p;
×
1966
                }
1967
#else 
1968
                diff = (lhs - rhs);
5,375,317✔
1969
#endif
1970
                return diff.sign();
7,586,930✔
1971
        }
1972
}
1973
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1974
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,214,762✔
1975
        return operator< (rhs, lhs);
4,214,762✔
1976
}
1977
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1978
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,214,484✔
1979
        return !operator> (lhs, rhs);
4,214,484✔
1980
}
1981
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1982
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
65,792✔
1983
        return !operator< (lhs, rhs);
65,792✔
1984
}
1985

1986
//////////////////////////////////////////////////////////////////////////////////////////////////////
1987
// integer - literal binary logic operators
1988
// equal: precondition is that the byte-storage is properly nulled in all arithmetic paths
1989
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1990
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
231,536✔
1991
        return operator==(lhs, integer<nbits, BlockType, NumberType>(rhs));
231,536✔
1992
}
1993
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1994
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
305✔
1995
        return !operator==(lhs, rhs);
305✔
1996
}
1997
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
1998
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
1,477,820✔
1999
        return operator<(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,477,820✔
2000
}
2001
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2002
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
9,511✔
2003
        return operator< (integer<nbits, BlockType, NumberType>(rhs), lhs);
9,511✔
2004
}
2005
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2006
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
12✔
2007
        return operator< (lhs, rhs) || operator==(lhs, rhs);
12✔
2008
}
2009
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2010
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
668✔
2011
        return !operator< (lhs, rhs);
668✔
2012
}
2013

2014
//////////////////////////////////////////////////////////////////////////////////////////////////////
2015
// literal - integer binary logic operators
2016
// precondition is that the byte-storage is properly nulled in all arithmetic paths
2017

2018
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2019
constexpr inline bool operator==(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
13✔
2020
        return operator==(integer<nbits, BlockType, NumberType>(lhs), rhs);
13✔
2021
}
2022
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2023
constexpr inline bool operator!=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2024
        return !operator==(lhs, rhs);
6✔
2025
}
2026
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2027
constexpr inline bool operator< (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
18✔
2028
        return operator<(integer<nbits, BlockType, NumberType>(lhs), rhs);
18✔
2029
}
2030
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2031
constexpr inline bool operator> (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2032
        return operator< (rhs, lhs);
6✔
2033
}
2034
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2035
constexpr inline bool operator<=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2036
        return operator< (lhs, rhs) || operator==(lhs, rhs);
6✔
2037
}
2038
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2039
constexpr inline bool operator>=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2040
        return !operator< (lhs, rhs);
6✔
2041
}
2042

2043
//////////////////////////////////////////////////////////////////////////////////////////////////////
2044

2045
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2046
constexpr inline integer<nbits, BlockType, NumberType> operator<<(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
180✔
2047
        integer<nbits, BlockType, NumberType> shifted(lhs);
180✔
2048
        return (shifted <<= shift);
360✔
2049
}
2050

2051
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2052
constexpr inline integer<nbits, BlockType, NumberType> operator>>(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
76✔
2053
        integer<nbits, BlockType, NumberType> shifted(lhs);
76✔
2054
        return (shifted >>= shift);
152✔
2055
}
2056

2057
//////////////////////////////////////////////////////////////////////////////////////////////////////
2058
// integer - integer binary arithmetic operators
2059
// BINARY ADDITION
2060
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2061
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
8,878,333✔
2062
        integer<nbits, BlockType, NumberType> sum(lhs);
8,878,333✔
2063
        sum += rhs;
8,878,333✔
2064
        return sum;
8,878,333✔
2065
}
2066
// BINARY SUBTRACTION
2067
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2068
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
16,453,718✔
2069
        integer<nbits, BlockType, NumberType> diff(lhs);
16,453,718✔
2070
        diff -= rhs;
16,453,718✔
2071
        return diff;
16,453,716✔
2072
}
2073
// BINARY MULTIPLICATION
2074
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2075
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,220,478✔
2076
        integer<nbits, BlockType, NumberType> mul(lhs);
3,220,478✔
2077
        mul *= rhs;
3,220,478✔
2078
        return mul;
3,220,478✔
2079
}
2080
// BINARY DIVISION
2081
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2082
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,847,603✔
2083
        integer<nbits, BlockType, NumberType> ratio(lhs);
4,847,603✔
2084
        ratio /= rhs;
4,847,603✔
2085
        return ratio;
4,846,241✔
2086
}
2087
// BINARY REMAINDER
2088
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2089
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,270,918✔
2090
        integer<nbits, BlockType, NumberType> ratio(lhs);
3,270,918✔
2091
        ratio %= rhs;
3,270,918✔
2092
        return ratio;
3,270,582✔
2093
}
2094
// BINARY BIT-WISE AND
2095
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2096
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2097
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2098
        bitwise &= rhs;
2099
        return bitwise;
2100
}
2101
// BINARY BIT-WISE OR
2102
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2103
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2104
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2105
        bitwise |= rhs;
2106
        return bitwise;
2107
}
2108
// BINARY BIT-WISE XOR
2109
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2110
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2111
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2112
        bitwise ^= rhs;
2113
        return bitwise;
2114
}
2115

2116
//////////////////////////////////////////////////////////////////////////////////////////////////////
2117
// integer - literal binary arithmetic operators
2118
// BINARY ADDITION
2119
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2120
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
489✔
2121
        return operator+(lhs, integer<nbits, BlockType, NumberType>(rhs));
489✔
2122
}
2123
// BINARY SUBTRACTION
2124
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2125
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
197,088✔
2126
        return operator-(lhs, integer<nbits, BlockType, NumberType>(rhs));
197,088✔
2127
}
2128
// BINARY MULTIPLICATION
2129
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2130
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4,460✔
2131
        return operator*(lhs, integer<nbits, BlockType, NumberType>(rhs));
4,460✔
2132
}
2133
// BINARY DIVISION
2134
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2135
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1,513✔
2136
        return operator/(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,513✔
2137
}
2138
// BINARY REMAINDER
2139
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2140
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4✔
2141
        return operator%(lhs, integer<nbits, BlockType, NumberType>(rhs));
4✔
2142
}
2143
// BINARY BIT-WISE AND
2144
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2145
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2146
        return operator&(lhs, integer<nbits, BlockType, NumberType>(rhs));
2147
}
2148
// BINARY BIT-WISE OR
2149
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2150
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2151
        return operator|(lhs, integer<nbits, BlockType, NumberType>(rhs));
2152
}
2153
// BINARY BIT-WISE XOR
2154
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2155
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2156
        return operator^(lhs, integer<nbits, BlockType, NumberType>(rhs));
2157
}
2158
//////////////////////////////////////////////////////////////////////////////////////////////////////
2159
// literal - integer binary arithmetic operators
2160
// BINARY ADDITION
2161
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2162
constexpr inline integer<nbits, BlockType, NumberType> operator+(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1✔
2163
        return operator+(integer<nbits, BlockType, NumberType>(lhs), rhs);
1✔
2164
}
2165
// BINARY SUBTRACTION
2166
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2167
constexpr inline integer<nbits, BlockType, NumberType> operator-(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2168
        return operator-(integer<nbits, BlockType, NumberType>(lhs), rhs);
2169
}
2170
// BINARY MULTIPLICATION
2171
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2172
constexpr inline integer<nbits, BlockType, NumberType> operator*(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4✔
2173
        return operator*(integer<nbits, BlockType, NumberType>(lhs), rhs);
4✔
2174
}
2175
// BINARY DIVISION
2176
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2177
constexpr inline integer<nbits, BlockType, NumberType> operator/(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2178
        return operator/(integer<nbits, BlockType, NumberType>(lhs), rhs);
2179
}
2180
// BINARY REMAINDER
2181
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2182
constexpr inline integer<nbits, BlockType, NumberType> operator%(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2183
        return operator%(integer<nbits, BlockType, NumberType>(lhs), rhs);
2184
}
2185
// BINARY BIT-WISE AND
2186
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2187
constexpr inline integer<nbits, BlockType, NumberType> operator&(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2188
        return operator&(integer<nbits, BlockType, NumberType>(lhs), rhs);
2189
}
2190
// BINARY BIT-WISE OR
2191
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2192
constexpr inline integer<nbits, BlockType, NumberType> operator|(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2193
        return operator|(integer<nbits, BlockType, NumberType>(lhs), rhs);
2194
}
2195
// BINARY BIT-WISE XOR
2196
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2197
constexpr inline integer<nbits, BlockType, NumberType> operator^(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2198
        return operator^(integer<nbits, BlockType, NumberType>(lhs), rhs);
2199
}
2200

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

© 2026 Coveralls, Inc