1 /// Multiple precision integers (Z).
2 module gmp.z;
3 
4 import std.algorithm.mutation : move, moveEmplace;
5 import std.traits : isInstanceOf, Unsigned, Unqual, isIntegral, isUnsigned; // used by expression templates
6 
7 import gmp.traits;
8 
9 /// Call unittests taking long to execute.
10 enum unittestLong = false;
11 
12 /// Is `true` if type `T` can be evaluated to a `MpZ` value.
13 enum isMpZExpr(T) = (is(Unqual!(typeof(T.eval())) == MpZ)); // which returns an `MpZ`
14 /// Is `true` if type `T` is lazy (not yet evaluated) `MpZ`-expression.
15 enum isLazyMpZExpr(T) = (!is(Unqual!T == MpZ) &&            // exclude direct value
16                          isMpZExpr!T);
17 
18 /** Endianess of serialization in `MpZ.serialize` and
19  * unserialization-construction from integer array.
20  */
21 enum Endianess
22 {
23     host,
24     bigEndian,
25     littleEndian,
26 }
27 
28 /** Word-order of serialization in `MpZ.serialize` and
29  * unserialization-construction from integer array.
30  */
31 enum WordOrder
32 {
33     mostSignificantWordFirst,
34     leastSignificantWordFirst,
35 }
36 
37 
38 // TODO use these imports instead of the ones below
39 // import deimos.gmp.gmp;
40 // import deimos.gmp.integer;
41 
42 /** Arbitrary (multi) precision signed integer (Z).
43     Wrapper for GNU MP (GMP)'s type `mpz_t` and functions `__gmpz_.*`.
44  */
45 private struct _MpZ(bool copyable = false)
46 {
47     pure nothrow:
48 
49     /// Convert to `string` in base `base`.
50     string toString(uint base = defaultBase,
51                     bool upperCaseDigits = false) const @trusted
52     {
53         if (isZero) { return `0`; }
54 
55         assert((base >= -2 && base <= -36) ||
56                (base >= 2 && base <= 62));
57 
58         immutable size = sizeInBase(base); // NOTE: one too much for some values
59 
60         string str = new string(size + 1); // one extra for minus sign
61         __gmpz_get_str(cast(char*)str.ptr, base, _ptr); // fill it
62 
63         // skip trailing garbage
64         import std.ascii : isAlphaNum;
65         while (str.length &&
66                !str[$ - 1].isAlphaNum)
67         {
68             str.length -= 1;
69         }
70 
71         if (upperCaseDigits)
72         {
73             foreach (ref e; cast(char[])str)
74             {
75                 import std.ascii : isLower, toUpper;
76                 if (e.isLower)
77                 {
78                     e = e.toUpper;
79                 }
80             }
81         }
82 
83         return str;
84     }
85 
86     /// Returns: A unique hash of the `_MpZ` value suitable for use in a hash table.
87     size_t toHash() const @trusted
88     {
89         version(LDC) pragma(inline, true);
90         import core.internal.hash : hashOf;
91         typeof(return) hash = _limbCount;
92         foreach (immutable i; 0 .. _limbCount)
93         {
94             hash ^= _limbs[i].hashOf;
95         }
96         return hash;
97     }
98 
99     /** Serialize `this` into a new GC-allocated slice of words, each word of
100      * type `Word`.
101      *
102      * It's format defined by:
103      * - `order`: the most significant word `first` or `last` for least significant first
104      * - `endian` can be `bigEndian`, `littleEndian` or `host` default
105      * - the most significant `nails` bits of each word are unused and set to zero, this can be 0 to produce full words
106      *
107      * Returns: a new GC-allocated slice containing the words produced.
108      */
109     Word[] serialize(Word)(WordOrder order, Endianess endian, size_t nails) const @trusted
110     if (isUnsigned!Word)
111     {
112         auto numb = 8 * Word.sizeof - nails;
113         size_t count = (__gmpz_sizeinbase(_ptr, 2) + numb-1) / numb;
114         return serialize(new Word[count], order, Word.sizeof, endian, nails);
115     }
116 
117     @nogc:
118 
119     /** No default construction for now, because `mpz_init` initialize
120         `__mpz_struct`-fields to non-zero values.
121 
122         TODO Allow default construction by delaying call to initialize().
123     */
124     // @disable this();
125 
126     /// Construct empty (undefined) from explicit `null`.
127     pragma(inline, true)
128     this(typeof(null)) @trusted
129     {
130         initialize();             // TODO is there a faster way?
131         assert(this == _MpZ.init); // if this is same as default
132     }
133 
134     /// Construct from expression `expr`.
135     this(Expr)(Expr expr)
136     if (isLazyMpZExpr!Expr)
137     {
138         version(LDC) pragma(inline, true);
139         // TODO ok to just assume zero-initialized contents at `_z` before...
140         this = expr;            // ...calling this.opAssign ?x
141     }
142 
143     /** Construct from `value`. */
144     pragma(inline, true)
145     this(T)(T value) @trusted
146     if (isArithmetic!T)
147     {
148         version(ccc) { ++_ccc; }
149         static      if (isUnsigned!T)
150             __gmpz_init_set_ui(_ptr, value);
151         else static if (isFloating!T)
152             __gmpz_init_set_d(_ptr, value);
153         else                    // isSigned integral
154             __gmpz_init_set_si(_ptr, value);
155     }
156 
157     /** Construct from `value` in base `base`.
158         If `base` is 0 it's guessed from contents of `value`.
159         */
160     pragma(inline, false)
161     this(in string value, uint base = 0) @trusted // TODO Use Optional/Nullable when value is nan, or inf
162     {
163         assert(base == 0 || (base >= 2 && base <= 62));
164         char* stringz = _allocStringzCopyOf(value);
165         immutable int status = __gmpz_init_set_str(_ptr, stringz, base); version(ccc) { ++_ccc; }
166         qualifiedFree(stringz);
167         assert(status == 0, "Parameter `value` does not contain an integer");
168     }
169 
170     /** Constucts number from serialized binary array. Arguments:
171      * - `rop` : array of unsinged values
172      * - `order`: the most significant word `first` or `last` for least significant first
173      * - `size` in bytes of each word
174      * - `endian` can be `bigEndian`, `littleEndian` or `host` default
175      * - the most significant `nails` bits of each word are unused and set to zero, this can be 0 to produce full words
176     */
177     this(T)(const T[] rop, WordOrder order, size_t size, Endianess endian, size_t nails)
178     if (isUnsigned!T)
179     {
180 
181         int realOrder;
182         final switch(order)
183         {
184             case WordOrder.mostSignificantWordFirst:  realOrder = 1;  break;
185             case WordOrder.leastSignificantWordFirst: realOrder = -1; break;
186         }
187 
188         int realEndian;
189         final switch(endian)
190         {
191             case Endianess.littleEndian: realEndian = -1; break;
192             case Endianess.bigEndian:    realEndian =  1; break;
193             case Endianess.host:         realEndian =  0; break;
194         }
195 
196         __gmpz_init(_ptr);
197         __gmpz_import(_ptr, rop.length, realOrder, size, realEndian, nails, rop.ptr);
198     }
199 
200     /// Returns: the Mersenne prime, M(p) = 2 ^^ p - 1
201     static _MpZ mersennePrime(Integral)(Integral p)
202     if (isIntegral!Integral)
203     {
204         version(LDC) pragma(inline, true);
205         return typeof(this).pow(2UL, p) - 1;
206     }
207 
208     static if (copyable)
209     {
210         /// Construct copy of `value`.
211         pragma(inline, true)
212         this(this) @trusted
213         {
214             if (_z._mp_d)
215             {
216                 // TODO this might be made faster
217                 __mpz_struct _z_copy = _z;
218                 __gmpz_init_set(&_z_copy, _ptr); version(ccc) { ++_ccc; }
219                 _z = _z_copy;
220             }
221         }
222 
223         // /// Construct copy of `value`.
224         // this(ref const _MpZ value) @trusted
225         // {
226         //     __gmpz_init_set(_ptr, value._ptr); version(ccc) { ++_ccc; }
227         // }
228 
229         // /// Construct copy of `value`.
230         // this(_MpZ value) @trusted
231         // {
232         //     moveEmplace(value, this); // fast
233         // }
234     }
235     else
236     {
237         /// No copy construction.
238         @disable this(this);
239     }
240 
241     /// Swap content of `this` with `rhs`.
242     pragma(inline, true)
243     void swap(ref _MpZ rhs) @safe
244     {
245         import std.algorithm.mutation : swap;
246         swap(this, rhs); // faster than __gmpz_swap(_ptr, rhs._ptr); version(ccc) { ++_ccc; }
247     }
248 
249     /// Returns: (duplicate) copy of `this`.
250     _MpZ dup() const @trusted
251     {
252         version(LDC) pragma(inline, true);
253         typeof(return) y = void;
254         __gmpz_init_set(y._ptr, _ptr); version(ccc) ++y._ccc;
255         return y;
256     }
257 
258     /// Assign from `rhs`.
259     ref _MpZ opAssign()(auto ref const _MpZ rhs) @trusted return scope
260     {
261         version(LDC) pragma(inline, true);
262         __gmpz_set(_ptr, rhs._ptr); version(ccc) { ++_ccc; }
263         return this;
264     }
265     /// ditto
266     ref _MpZ opAssign(Expr)(auto ref Expr rhs) @trusted return scope
267     if (isLazyMpZExpr!Expr)
268     {
269         version(LDC) pragma(inline, true);
270         static      if (isInstanceOf!(MpzAddExpr, Expr))
271         {
272             __gmpz_add(this._ptr,
273                        rhs.e1.eval()._ptr,
274                        rhs.e2.eval()._ptr); version(ccc) { ++_ccc; }
275         }
276         else static if (isInstanceOf!(MpzSubExpr, Expr))
277         {
278             __gmpz_sub(this._ptr,
279                        rhs.e1.eval()._ptr,
280                        rhs.e2.eval()._ptr); version(ccc) { ++_ccc; }
281         }
282         else static if (isInstanceOf!(MpzMulExpr, Expr))
283         {
284             __gmpz_mul(this._ptr,
285                        rhs.e1.eval()._ptr,
286                        rhs.e2.eval()._ptr); version(ccc) { ++_ccc; }
287         }
288         else static if (isInstanceOf!(MpzDivExpr, Expr))
289         {
290             __gmpz_tdiv_q(this._ptr,
291                           rhs.e1.eval()._ptr,
292                           rhs.e2.eval()._ptr); version(ccc) { ++_ccc; }
293         }
294         else static if (isInstanceOf!(MpzModExpr, Expr))
295         {
296             __gmpz_tdiv_r(this._ptr,
297                           rhs.e1.eval()._ptr,
298                           rhs.e2.eval()._ptr); version(ccc) { ++_ccc; }
299         }
300         else static if (isInstanceOf!(MpzNegExpr, Expr))
301         {
302             __gmpz_neg(this._ptr,
303                        rhs.e1.eval()._ptr); version(ccc) { ++_ccc; }
304         }
305         else
306         {
307             this = rhs.eval();     // evaluate and move
308         }
309         return this;
310     }
311     /// ditto
312     ref _MpZ opAssign(T)(T rhs) @trusted return scope
313     if (isArithmetic!T)
314     {
315         version(LDC) pragma(inline, true);
316         assertInitialized();
317         static if      (isUnsigned!T)
318         {
319             __gmpz_set_ui(_ptr, rhs);
320         }
321         else static if (isFloating!T)
322         {
323             __gmpz_set_d(_ptr, rhs);
324         }
325         else static if (isSigned!T)
326         {
327             __gmpz_set_si(_ptr, rhs);
328         }
329         else
330         {
331             static assert(false);
332         }
333         version(ccc) { ++_ccc; }
334         return this;
335     }
336 
337     /** Assign `this` from `string` `rhs` interpreted in base `base`.
338         If `base` is 0 it's guessed from contents of `value`.
339     */
340     ref _MpZ fromString(in string rhs, uint base = 0) @trusted return
341     {
342         assert(base == 0 || (base >= 2 && base <= 62));
343         char* stringz = _allocStringzCopyOf(rhs);
344         immutable int status = __gmpz_set_str(_ptr, stringz, base); version(ccc) { ++_ccc; }
345         qualifiedFree(stringz);
346         assert(status == 0, "Parameter `rhs` does not contain an integer");
347         return this;
348     }
349 
350     /// Destruct `this`.
351     pragma(inline, true)
352     ~this() @trusted
353     {
354         if (_z._mp_d)
355         {
356             __gmpz_clear(_ptr); version(ccc) { ++_ccc; }
357             _z._mp_d = null;    // prevent GC from scanning this memory
358         }
359     }
360 
361     /// Returns: `true` iff `this` equals `rhs`.
362     bool opEquals()(auto ref const _MpZ rhs) const @trusted
363     {
364         version(LDC) pragma(inline, true);
365         if (_ptr == rhs._ptr)   // fast equality
366         {
367             return true;        // fast bailout
368         }
369         return __gmpz_cmp(_ptr, rhs._ptr) == 0;
370     }
371     /// ditto
372     pragma(inline, true)
373     bool opEquals(Rhs)(Rhs rhs) const @trusted
374     if (isArithmetic!Rhs)
375     {
376         if (rhs == 0)
377         {
378             return isZero;      // optimization
379         }
380         static      if (isUnsigned!Rhs)
381         {
382             return __gmpz_cmp_ui(_ptr, cast(ulong)rhs) == 0;
383         }
384         else static if (isFloating!Rhs)
385         {
386             return __gmpz_cmp_d(_ptr, cast(double)rhs) == 0; // TODO correct to do this cast here?
387         }
388         else                    // isSigned integral
389         {
390             return __gmpz_cmp_si(_ptr, cast(long)rhs) == 0;
391         }
392     }
393 
394     /// Compare `this` to `rhs`.
395     int opCmp()(auto ref const _MpZ rhs) const @trusted
396     {
397         version(LDC) pragma(inline, true);
398         if (rhs == 0)
399         {
400             return sgn();       // optimization
401         }
402         return __gmpz_cmp(_ptr, rhs._ptr);
403     }
404     /// ditto
405     pragma(inline, true)
406     int opCmp(T)(T rhs) const @trusted
407     if (isArithmetic!T)
408     {
409         if (rhs == 0)
410         {
411             return sgn();       // optimization
412         }
413         static      if (isUnsigned!T)
414         {
415             return __gmpz_cmp_ui(_ptr, rhs);
416         }
417         else static if (isFloating!T)
418         {
419             return __gmpz_cmp_d(_ptr, rhs);
420         }
421         else                    // isSigned integral
422         {
423             return __gmpz_cmp_si(_ptr, rhs);
424         }
425     }
426 
427     /// Cast to `bool`.
428     pragma(inline, true)
429     bool opCast(T : bool)() const
430     {
431         return !isZero;
432     }
433 
434     /// Cast to arithmetic type `T`.
435     pragma(inline, true)
436     T opCast(T)() const @trusted
437     if (isArithmetic!T)
438     {
439         static      if (isUnsigned!T)
440         {
441             return cast(T)__gmpz_get_ui(_ptr);
442         }
443         else static if (isFloating!T)
444         {
445             return cast(T)__gmpz_get_d(_ptr);
446         }
447         else                    // isSigned integral
448         {
449             return cast(T)__gmpz_get_si(_ptr);
450         }
451     }
452 
453     /** Returns: The value of this as a `long`, or +/- `long.max` if outside
454         the representable range.
455     */
456     long toLong() const @trusted
457     {
458         version(LDC) pragma(inline, true);
459         // TODO can probably be optimized
460         if (this <= long.min)
461         {
462             return long.min;
463         }
464         else if (this >= long.max)
465         {
466             return long.max;
467         }
468         else
469         {
470             return cast(long)__gmpz_get_si(_ptr);
471         }
472     }
473 
474     /** Returns: The value of this as a `int`, or +/- `int.max` if outside
475         the representable range.
476     */
477     int toInt() const @trusted
478     {
479         version(LDC) pragma(inline, true);
480         // TODO can probably be optimized
481         if (this <= int.min)
482         {
483             return int.min;
484         }
485         else if (this >= int.max)
486         {
487             return int.max;
488         }
489         else
490         {
491             return cast(int)__gmpz_get_si(_ptr);
492         }
493     }
494 
495     /** Returns: `this` `s` `rhs`. */
496     _MpZ opBinary(string s)(auto ref const _MpZ rhs) const @trusted // direct value
497     if ((s == "+" || s == "-" ||
498          s == "*" || s == "/" || s == "%" ||
499          s == "&" || s == "|" || s == "^"))
500     {
501         version(LDC) pragma(inline, true);
502         static if (!__traits(isRef, rhs)) // r-value `rhs`
503         {
504             _MpZ* mut_rhs = (cast(_MpZ*)(&rhs)); // @trusted because `_MpZ` has no aliased indirections
505             static      if (s == "+")
506             {
507                 __gmpz_add(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
508             }
509             else static if (s == "-")
510             {
511                 __gmpz_sub(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
512             }
513             else static if (s == "*")
514             {
515                 __gmpz_mul(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
516             }
517             else static if (s == "/")
518             {
519                 assert(rhs != 0, "Divison by zero");
520                 __gmpz_tdiv_q(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
521             }
522             else static if (s == "%")
523             {
524                 assert(rhs != 0, "Divison by zero");
525                 __gmpz_tdiv_r(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
526             }
527             else static if (s == "&")
528             {
529                 __gmpz_and(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
530             }
531             else static if (s == "|")
532             {
533                 __gmpz_ior(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
534             }
535             else static if (s == "^")
536             {
537                 __gmpz_xor(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
538             }
539             else
540             {
541                 static assert(false);
542             }
543             return move(*mut_rhs); // TODO shouldn't have to call `move` here
544         }
545         else
546         {
547             typeof(return) y = null;
548             static      if (s == "+")
549             {
550                 __gmpz_add(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
551             }
552             else static if (s == "-")
553             {
554                 __gmpz_sub(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
555             }
556             else static if (s == "*")
557             {
558                 __gmpz_mul(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
559             }
560             else static if (s == "/")
561             {
562                 assert(rhs != 0, "Divison by zero");
563                 __gmpz_tdiv_q(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
564             }
565             else static if (s == "%")
566             {
567                 assert(rhs != 0, "Divison by zero");
568                 __gmpz_tdiv_r(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
569             }
570             else static if (s == "&")
571             {
572                 __gmpz_and(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
573             }
574             else static if (s == "|")
575             {
576                 __gmpz_ior(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
577             }
578             else static if (s == "^")
579             {
580                 __gmpz_xor(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
581             }
582             else
583             {
584                 static assert(false);
585             }
586             return y;
587         }
588     }
589 
590     /// ditto
591     pragma(inline, true)
592     _MpZ opBinary(string s, Rhs)(auto ref const Rhs rhs) const
593     if (isLazyMpZExpr!Rhs && // lazy value
594         (s == "+" || s == "-" || s == "*" || s == "/" || s == "%"))
595     {
596         static assert(false, "TODO");
597     }
598 
599     /// ditto
600     _MpZ opBinary(string s, Rhs)(Rhs rhs) const @trusted
601     if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "^^") &&
602         isUnsigned!Rhs)
603     {
604         version(LDC) pragma(inline, true);
605         typeof(return) y = null;
606         version(ccc) ++y._ccc;
607         static      if (s == "+")
608         {
609             __gmpz_add_ui(y._ptr, _ptr, rhs);
610         }
611         else static if (s == "-")
612         {
613             __gmpz_sub_ui(y._ptr, _ptr, rhs);
614         }
615         else static if (s == "*")
616         {
617             __gmpz_mul_ui(y._ptr, _ptr, rhs);
618         }
619         else static if (s == "/")
620         {
621             assert(rhs != 0, "Divison by zero");
622             __gmpz_tdiv_q_ui(y._ptr, _ptr, rhs);
623         }
624         else static if (s == "^^")
625         {
626             __gmpz_pow_ui(y._ptr, _ptr, rhs);
627         }
628         else
629         {
630             static assert(false);
631         }
632         return y;
633     }
634 
635     /// ditto
636     _MpZ opBinary(string s, Rhs)(Rhs rhs) const @trusted
637     if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "^^") &&
638         isSigned!Rhs)
639     {
640         version(LDC) pragma(inline, true);
641         typeof(return) y = null;
642         version(ccc) ++y._ccc;
643         static      if (s == "+")
644         {
645             if (rhs < 0)        // TODO handle `rhs == rhs.min`
646             {
647                 immutable ulong pos_rhs = -rhs; // make it positive
648                 __gmpz_sub_ui(y._ptr, _ptr, pos_rhs);
649             }
650             else
651             {
652                 __gmpz_add_ui(y._ptr, _ptr, rhs);
653             }
654         }
655         else static if (s == "-")
656         {
657             if (rhs < 0)        // TODO handle `rhs == rhs.min`
658             {
659                 __gmpz_add_ui(y._ptr, _ptr, -rhs); // x - (-y) == x + y
660             }
661             else
662             {
663                 __gmpz_sub_ui(y._ptr, _ptr, rhs); // rhs is positive
664             }
665         }
666         else static if (s == "*")
667         {
668             __gmpz_mul_si(y._ptr, _ptr, rhs);
669         }
670         else static if (s == "/")
671         {
672             assert(rhs != 0, "Divison by zero");
673             if (rhs < 0)        // TODO handle `rhs == rhs.min`
674             {
675                 immutable ulong pos_rhs = -rhs; // make it positive
676                 __gmpz_tdiv_q_ui(y._ptr, _ptr, pos_rhs);
677                 y.negate();     // negate result
678             }
679             else
680             {
681                 __gmpz_tdiv_q_ui(y._ptr, _ptr, rhs);
682             }
683         }
684         else static if (s == "^^")
685         {
686             assert(rhs >= 0, "TODO Negative power exponent needs MpQ return");
687             __gmpz_pow_ui(y._ptr, _ptr, rhs);
688         }
689         else
690         {
691             static assert(false);
692         }
693         return y;
694     }
695 
696     /// Remainer propagates modulus type.
697     Unqual!Rhs opBinary(string s, Rhs)(Rhs rhs) const @trusted
698     if ((s == "%") &&
699         isIntegral!Rhs)
700     {
701         version(LDC) pragma(inline, true);
702         assert(rhs != 0, "Divison by zero");
703         _MpZ y = null;
704         version(ccc) ++y._ccc;
705         static if (isSigned!Rhs)
706         {
707             if (rhs < 0)        // TODO handle `rhs == rhs.min`
708             {
709                 immutable ulong pos_rhs = -cast(int)rhs; // make it positive
710                 return cast(typeof(return))-__gmpz_tdiv_r_ui(y._ptr, _ptr, pos_rhs);
711             }
712             else
713             {
714                 return cast(typeof(return))__gmpz_tdiv_r_ui(y._ptr, _ptr, rhs);
715             }
716         }
717         else static if (isUnsigned!Rhs)
718         {
719             return cast(typeof(return))__gmpz_tdiv_r_ui(y._ptr, _ptr, rhs);
720         }
721         else
722         {
723             static assert(false);
724         }
725     }
726 
727     /// Returns: an unsigned type `lhs` divided by `this`.
728     _MpZ opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
729     if ((s == "+" || s == "-" || s == "*" || s == "%") &&
730         isUnsigned!Lhs)
731     {
732         version(LDC) pragma(inline, true);
733         typeof(return) y = null;
734         version(ccc) ++y._ccc;
735         static      if (s == "+")
736         {
737             __gmpz_add_ui(y._ptr, _ptr, lhs); // commutative
738         }
739         else static if (s == "-")
740         {
741             __gmpz_ui_sub(y._ptr, lhs, _ptr);
742         }
743         else static if (s == "*")
744         {
745             __gmpz_mul_ui(y._ptr, _ptr, lhs); // commutative
746         }
747         else static if (s == "%")
748         {
749             assert(this != 0, "Divison by zero");
750             __gmpz_tdiv_r(y._ptr, _MpZ(lhs)._ptr, _ptr); // convert `lhs` to _MpZ
751         }
752         else
753         {
754             static assert(false);
755         }
756         return y;
757     }
758 
759     /// Returns: a signed type `lhs` divided by `this`.
760     _MpZ opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
761     if ((s == "+" || s == "-" || s == "*" || s == "%") &&
762         isSigned!Lhs)
763     {
764         version(LDC) pragma(inline, true);
765         static if (s == "+" || s == "*")
766         {
767             return opBinary!s(lhs); // commutative reuse
768         }
769         else static if (s == "-")
770         {
771             typeof(return) y = null;
772             version(ccc) ++y._ccc;
773             if (lhs < 0)        // TODO handle `lhs == lhs.min`
774             {
775                 immutable ulong pos_rhs = -lhs; // make it positive
776                 __gmpz_add_ui(y._ptr, _ptr, pos_rhs);
777             }
778             else
779             {
780                 __gmpz_sub_ui(y._ptr, _ptr, lhs);
781             }
782             y.negate();
783             return y;
784         }
785         else static if (s == "%")
786         {
787             typeof(return) y = null;
788             version(ccc) ++y._ccc;
789             assert(this != 0, "Divison by zero");
790             __gmpz_tdiv_r(y._ptr, _MpZ(lhs)._ptr, _ptr); // convert `lhs` to _MpZ
791             return y;
792         }
793         else
794         {
795             static assert(false);
796         }
797     }
798 
799     /// Dividend propagates quotient type to signed.
800     Unqual!Lhs opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
801     if ((s == "/") &&
802         isIntegral!Lhs)
803     {
804         version(LDC) pragma(inline, true);
805         _MpZ y = null; // TODO avoid if !__traits(isRef, this)
806         version(ccc) ++y._ccc;
807         assert(this != 0, "Divison by zero");
808         __gmpz_tdiv_q(y._ptr, _MpZ(lhs)._ptr, _ptr);
809         static      if (isSigned!Lhs)
810         {
811             return cast(typeof(return))y;
812         }
813         else static if (isUnsigned!Lhs)
814         {
815             import std.traits : Signed;
816             return cast(Signed!(typeof(return)))y;
817         }
818         else
819         {
820             static assert(false);
821         }
822     }
823 
824     /// Exponentation.
825     pragma(inline, true)
826     _MpZ opBinaryRight(string s, Base)(Base base) const
827     if ((s == "^^") &&
828         isIntegral!Base)
829     {
830         static assert(false, "Convert `this _MpZ` exponent to `ulong` and calculate power via static method `pow()`");
831         // _MpZ exp = null;
832         // __gmpz_pow();
833         // return exp;
834     }
835 
836     /// Operate-assign to `this` from `rhs`.
837     ref _MpZ opOpAssign(string s)(auto ref const _MpZ rhs) @trusted return scope
838     if ((s == "+" || s == "-" ||
839          s == "*" || s == "/" || s == "%" ||
840          s == "&" || s == "|" || s == "^"))
841     {
842         version(LDC) pragma(inline, true);
843         static      if (s == "+")
844         {
845             __gmpz_add(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
846         }
847         else static if (s == "-")
848         {
849             __gmpz_sub(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
850         }
851         else static if (s == "*")
852         {
853             if (rhs == -1)
854             {
855                 negate();
856             }
857             else
858             {
859                 __gmpz_mul(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
860             }
861         }
862         else static if (s == "/")
863         {
864             assert(rhs != 0, "Divison by zero");
865             if (rhs == -1)
866             {
867                 negate();
868             }
869             else
870             {
871                 __gmpz_tdiv_q(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
872             }
873         }
874         else static if (s == "%")
875         {
876             assert(rhs != 0, "Divison by zero");
877             __gmpz_tdiv_r(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
878         }
879         else static if (s == "&")
880         {
881             __gmpz_and(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
882         }
883         else static if (s == "|")
884         {
885             __gmpz_ior(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
886         }
887         else static if (s == "^")
888         {
889             __gmpz_xor(_ptr, _ptr, rhs._ptr); version(ccc) { ++_ccc; }
890         }
891         else
892         {
893             static assert(false);
894         }
895         return this;
896     }
897 
898     /// ditto
899     ref _MpZ opOpAssign(string s, Rhs)(Rhs rhs) @trusted return scope
900     if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "%" || s == "^^") &&
901         isUnsigned!Rhs)
902     {
903         version(LDC) pragma(inline, true);
904         static      if (s == "+")
905         {
906             __gmpz_add_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
907         }
908         else static if (s == "-")
909         {
910             __gmpz_sub_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
911         }
912         else static if (s == "*")
913         {
914             __gmpz_mul_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
915         }
916         else static if (s == "/")
917         {
918             assert(rhs != 0, "Divison by zero");
919             __gmpz_tdiv_q_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
920         }
921         else static if (s == "%")
922         {
923             assert(rhs != 0, "Divison by zero");
924             __gmpz_tdiv_r_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
925         }
926         else static if (s == "^^")
927         {
928             __gmpz_pow_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
929         }
930         else
931         {
932             static assert(false);
933         }
934         return this;
935     }
936 
937     /// ditto
938     ref _MpZ opOpAssign(string s, Rhs)(Rhs rhs) @trusted return scope
939     if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "%" || s == "^^") &&
940         isSigned!Rhs)
941     {
942         version(LDC) pragma(inline, true);
943         static      if (s == "+")
944         {
945             if (rhs < 0)        // TODO handle `rhs == rhs.min`
946             {
947                 assert(rhs != rhs.min);
948                 immutable ulong pos_rhs = -rhs; // make it positive
949                 __gmpz_sub_ui(_ptr, _ptr, pos_rhs); version(ccc) { ++_ccc; }
950             }
951             else
952             {
953                 __gmpz_add_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
954             }
955         }
956         else static if (s == "-")
957         {
958             if (rhs < 0)        // TODO handle `rhs == rhs.min`
959             {
960                 assert(rhs != rhs.min);
961 
962                 immutable ulong pos_rhs = -rhs; // make it positive
963                 __gmpz_add_ui(_ptr, _ptr, pos_rhs); version(ccc) { ++_ccc; }
964             }
965             else
966             {
967                 __gmpz_sub_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
968             }
969         }
970         else static if (s == "*")
971         {
972             if (rhs == -1)
973             {
974                 negate();       // optimization
975             }
976             else
977             {
978                 __gmpz_mul_si(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
979             }
980         }
981         else static if (s == "/")
982         {
983             assert(rhs != 0, "Divison by zero");
984             if (rhs < 0)        // TODO handle `rhs == rhs.min`
985             {
986                 immutable ulong pos_rhs = -rhs; // make it positive
987                 __gmpz_tdiv_q_ui(_ptr, _ptr, pos_rhs); version(ccc) { ++_ccc; }
988                 negate();
989             }
990             else
991             {
992                 __gmpz_tdiv_q_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
993             }
994         }
995         else static if (s == "%")
996         {
997             assert(rhs != 0, "Divison by zero");
998             __gmpz_tdiv_r_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
999         }
1000         else static if (s == "^^")
1001         {
1002             assert(rhs >= 0, "Negative exponent");
1003             __gmpz_pow_ui(_ptr, _ptr, rhs); version(ccc) { ++_ccc; }
1004         }
1005         else
1006         {
1007             static assert(false);
1008         }
1009         return this;
1010     }
1011 
1012     /// Returns: `this`.
1013     pragma(inline, true)
1014     ref inout(_MpZ) opUnary(string s)() inout
1015     if (s == "+")
1016     {
1017         return this;
1018     }
1019 
1020     /// Returns: negation of `this`.
1021     _MpZ opUnary(string s)() const
1022     if (s == "-")
1023     {
1024         version(LDC) pragma(inline, true);
1025         typeof(return) y = this.dup;
1026         y.negate();
1027         return y;
1028     }
1029 
1030     /// Returns: negation of `this`.
1031     _MpZ unaryMinus() const @safe
1032     {
1033         version(LDC) pragma(inline, true);
1034         // pragma(msg, "memberFun:", __traits(isRef, this) ? "ref" : "non-ref", " this");
1035         typeof(return) y = this.dup;
1036         y.negate();
1037         return y;
1038     }
1039 
1040     /** Negate `this` in-place.
1041         Returns: `void` to make it obvious that `this` is mutated.
1042      */
1043     pragma(inline, true)
1044     void negate() @safe
1045     {
1046         _z._mp_size = -_z._mp_size; // fast C macro `mpz_neg` in gmp.h
1047     }
1048 
1049     /** Make `this` the absolute value of itself in-place.
1050         Returns: `void` to make it obvious that `this` is mutated.
1051      */
1052     void absolute() @trusted
1053     {
1054         version(LDC) pragma(inline, true);
1055         if (isZero) { return; } // `__gmpz_abs` cannot handle default-constructed `this`
1056         __gmpz_abs(_ptr, _ptr); version(ccc) { ++_ccc; }
1057     }
1058 
1059     /** Make `this` the one's complement value of itself in-place.
1060         Returns: `void` to make it obvious that `this` is mutated.
1061     */
1062     void onesComplement() @trusted
1063     {
1064         version(LDC) pragma(inline, true);
1065         if (isZero) { return; } // `__gmpz_co` cannot handle default-constructed `this`
1066         __gmpz_com(_ptr, _ptr); version(ccc) { ++_ccc; }
1067     }
1068 
1069     /// Increase `this` by one.
1070     ref _MpZ opUnary(string s)() @trusted return scope
1071     if (s == "++")
1072     {
1073         version(LDC) pragma(inline, true);
1074         if (isDefaultConstructed) // `__gmpz_add_ui` cannot handle default-constructed `this`
1075         {
1076             __gmpz_init_set_si(_ptr, 1);
1077         }
1078         else
1079         {
1080             __gmpz_add_ui(_ptr, _ptr, 1); version(ccc) { ++_ccc; }
1081         }
1082         return this;
1083     }
1084 
1085     /// Decrease `this` by one.
1086     ref _MpZ opUnary(string s)() @trusted return scope
1087     if (s == "--")
1088     {
1089         version(LDC) pragma(inline, true);
1090         if (isDefaultConstructed) // `__gmpz_sub_ui` cannot handle default-constructed `this`
1091         {
1092             __gmpz_init_set_si(_ptr, -1);
1093         }
1094         else
1095         {
1096             __gmpz_sub_ui(_ptr, _ptr, 1); version(ccc) { ++_ccc; }
1097         }
1098         return this;
1099     }
1100 
1101     /// Returns: `base` raised to the power of `exp`.
1102     static typeof(this) pow(Base, Exp)(Base base, Exp exp) @trusted
1103     if (isIntegral!Base &&
1104         isIntegral!Exp)
1105     {
1106         version(LDC) pragma(inline, true);
1107         static if (isSigned!Base)
1108         {
1109             immutable bool negate = base < 0;
1110             immutable ubase = cast(ulong)(negate ? -base : base);
1111         }
1112         else
1113         {
1114             immutable bool negate = false;
1115             immutable ubase = base;
1116         }
1117 
1118         static if (isSigned!Exp)
1119         {
1120             assert(exp >= 0, "Negative exponent"); // TODO return mpq?
1121             immutable uexp = cast(ulong)exp;
1122         }
1123         else
1124         {
1125             immutable uexp = exp;
1126         }
1127 
1128         typeof(return) y = null;
1129         __gmpz_ui_pow_ui(y._ptr, ubase, uexp); version(ccc) ++y._ccc;
1130         if (negate && exp & 1)  // if negative odd exponent
1131         {
1132             y.negate();
1133         }
1134 
1135         return y;
1136     }
1137 
1138     /// Returns: number of digits in base `base`.
1139     pragma(inline, true)
1140     size_t sizeInBase(uint base) const @trusted
1141     {
1142         if (isZero)
1143         {
1144             return 1;
1145         }
1146         else
1147         {
1148             return __gmpz_sizeinbase(_ptr, base);
1149         }
1150     }
1151 
1152     /** Serialize `this` into an existing pre-allocated slice of words `words`,
1153      * each word of type `Word`.
1154      *
1155      * It's format defined by:
1156      * - `order`: the most significant word `first` or `last` for least significant first
1157      * - `size` in bytes of each word
1158      * - `endian` can be `bigEndian`, `littleEndian` or `host` default
1159      * - the most significant `nails` bits of each word are unused and set to zero, this can be 0 to produce full words
1160      *
1161      * Returns: a (sub-)slice of `words` containing only the words produced.
1162      */
1163     Word[] serialize(Word)(return scope Word[] words,
1164                                    WordOrder order, size_t size, Endianess endian, size_t nails) const @trusted
1165     if (isUnsigned!Word)
1166     {
1167         assert(words, "words is empty");
1168 
1169         size_t count;
1170         debug
1171         {
1172             const numb = 8 * size - nails;
1173             size_t items = (__gmpz_sizeinbase(_ptr, 2) + numb-1) / numb;
1174             assert(Word.sizeof * words.length >= items * size , "words has no enough space pre-allocated");
1175         }
1176 
1177         int realOrder;
1178         final switch(order)
1179         {
1180             case WordOrder.mostSignificantWordFirst:  realOrder = 1;  break;
1181             case WordOrder.leastSignificantWordFirst: realOrder = -1; break;
1182         }
1183 
1184         int realEndian;
1185         final switch(endian)
1186         {
1187             case Endianess.littleEndian: realEndian = -1; break;
1188             case Endianess.bigEndian:    realEndian =  1; break;
1189             case Endianess.host:         realEndian =  0; break;
1190         }
1191 
1192         __gmpz_export(words.ptr, &count, realOrder, size, realEndian, nails, _ptr);
1193         return words[0 .. count];
1194     }
1195 
1196 
1197     /// Returns: `true` iff `this` fits in a `T`.
1198     pragma(inline, true)
1199     bool fitsIn(T)() const @trusted
1200     if (isIntegral!T)
1201     {
1202         if (isZero) { return true; } // default-constructed `this`
1203         static      if (is(T == ulong))  { return __gmpz_fits_ulong_p(_ptr) != 0; }
1204         else static if (is(T ==  long))  { return __gmpz_fits_slong_p(_ptr) != 0; }
1205         else static if (is(T ==  uint))  { return __gmpz_fits_uint_p(_ptr) != 0; }
1206         else static if (is(T ==   int))  { return __gmpz_fits_sint_p(_ptr) != 0; }
1207         else static if (is(T == ushort)) { return __gmpz_fits_ushort_p(_ptr) != 0; }
1208         else static if (is(T ==  short)) { return __gmpz_fits_sshort_p(_ptr) != 0; }
1209         else { static assert(false, "Unsupported type " ~ T.stringof); }
1210     }
1211 
1212     /** Returns: population count of `this`. If
1213         - `this` >= 0, number of 1 bits in the binary representation
1214         - otherwise, ???
1215      */
1216     pragma(inline, true)
1217     @property mp_bitcnt_t populationCount() const @trusted
1218     {
1219         if (isZero) { return 0; } // default-constructed `this`
1220         return __gmpz_popcount(this._ptr); // TODO use core.bitop `popcnt` inline here instead?
1221     }
1222     alias countOnes = populationCount;
1223 
1224     /// Set bit at 0-offset index `bitIndex` (to one).
1225     pragma(inline, true)
1226     void setBit(mp_bitcnt_t bitIndex) @trusted
1227     {
1228         __gmpz_setbit(_ptr, bitIndex);
1229     }
1230 
1231     /// Clear bit at 0-offset index `bitIndex` (to zero).
1232     pragma(inline, true)
1233     void clearBit(mp_bitcnt_t bitIndex) @trusted
1234     {
1235         __gmpz_clrbit(_ptr, bitIndex);
1236     }
1237 
1238     /// Complement bit at 0-offset index `bitIndex` (to zero).
1239     pragma(inline, true)
1240     void complementBit(mp_bitcnt_t bitIndex) @trusted
1241     {
1242         __gmpz_combit(_ptr, bitIndex);
1243     }
1244 
1245     /// Test/Get bit at 0-offset index `bitIndex`.
1246     pragma(inline, true)
1247     bool testBit(mp_bitcnt_t bitIndex) const @trusted
1248     {
1249         return __gmpz_tstbit(_ptr, bitIndex) != 0;
1250     }
1251     alias getBit = testBit;
1252 
1253     /** Check if `this` is default-constructed (in constrast to having been
1254         initialized via `__gmpz_...`-operations).
1255 
1256         Used to specially prepare avoid some `__gmpz_`-functions that cannot
1257         handle the case when the membere `_mp_alloc` is zero and, in turn,
1258         `_mp_d` is `null`.
1259      */
1260     pragma(inline, true)
1261     @property bool isDefaultConstructed() const @safe
1262     {
1263         return _z._mp_alloc == 0; // fast, actually enough to just test this
1264     }
1265 
1266     /// Check if `this` is zero (either via default-construction or `__gmpz_...`-operations).
1267     pragma(inline, true)
1268     @property bool isZero() const @safe
1269     {
1270         return _z._mp_size == 0; // fast
1271     }
1272 
1273     /// Check if `this` is odd.
1274     pragma(inline, true)
1275     @property bool isOdd() const @safe
1276     {
1277         return ((_z._mp_alloc != 0) && // this is needed for default (zero) initialized `__mpz_structs`
1278                 ((_z._mp_size != 0) & cast(int)(_z._mp_d[0]))); // fast C macro `mpz_odd_p` in gmp.h
1279     }
1280 
1281     /// Check if `this` is odd.
1282     pragma(inline, true)
1283     @property bool isEven() const @safe
1284     {
1285         return !isOdd;            // fast C macro `mpz_even_p` in gmp.h
1286     }
1287 
1288     /// Check if `this` is negative.
1289     pragma(inline, true)
1290     @property bool isNegative() const @safe
1291     {
1292         return _z._mp_size < 0; // fast
1293     }
1294 
1295     /// Check if `this` is positive.
1296     pragma(inline, true)
1297     @property bool isPositive() const @safe
1298     {
1299         return !isNegative;     // fast
1300     }
1301 
1302     /** Returns: sign as either
1303         - -1 (`this` < 0),
1304         -  0 (`this` == 0), or
1305         - +1 (`this` > 0).
1306      */
1307     pragma(inline, true)
1308     @property int sgn() const @safe
1309     {
1310         return _z._mp_size < 0 ? -1 : _z._mp_size > 0; // fast C macro `mpz_sgn` in gmp.h
1311     }
1312 
1313     /// Number of significant `uint`s used for storing `this`.
1314     pragma(inline, true)
1315     @property size_t uintLength() const
1316     {
1317         assert(false, "TODO use mpz_size");
1318     }
1319 
1320     /// Number of significant `ulong`s used for storing `this`.
1321     pragma(inline, true)
1322     @property size_t uintLong() const
1323     {
1324         assert(false, "TODO use mpz_size");
1325     }
1326 
1327 private:
1328 
1329     /** Initialize internal struct. */
1330     pragma(inline, true)
1331     void initialize() // cannot be called `init` as that will override builtin type property
1332     {
1333         __gmpz_init(_ptr); version(ccc) { ++_ccc; }
1334     }
1335 
1336     /** Initialize internal struct if needed. */
1337     pragma(inline, true)
1338     void assertInitialized()
1339     {
1340         if (isDefaultConstructed)
1341         {
1342             __gmpz_init(_ptr); version(ccc) { ++_ccc; }
1343         }
1344     }
1345 
1346     /// Default conversion base.
1347     enum defaultBase = 10;
1348 
1349     /// Returns: evaluation of `this` expression which in this is a no-op.
1350     pragma(inline, true)
1351     ref inout(_MpZ) eval() @safe inout return { return this; }
1352 
1353     /// Type of limb in internal representation.
1354     alias Limb = __mp_limb_t;   // GNU MP alias
1355 
1356     /** Returns: limbs. */
1357     pragma(inline, true)
1358     inout(Limb)[] _limbs() inout return @system
1359     {
1360         // import std.math : abs;
1361         return _z._mp_d[0 .. _limbCount];
1362     }
1363 
1364     /// Get number of limbs in internal representation.
1365     pragma(inline, true)
1366     @property uint _limbCount() const @safe
1367     {
1368         return _integralAbs(_z._mp_size);
1369     }
1370 
1371     /// Returns: pointer to internal C struct.
1372     pragma(inline, true)
1373     inout(__mpz_struct)* _ptr() inout return @system
1374     {
1375         return &_z;
1376     }
1377 
1378     __mpz_struct _z;            // internal libgmp C struct
1379 
1380     version(ccc)
1381     {
1382 
1383         /** Number of calls made to `__gmpz`--functions that construct or changes
1384             this value. Used to verify correct lowering and evaluation of template
1385             expressions.
1386 
1387             For instance the `x` in `x = y + z` should be assigned only once inside
1388             a call to `mpz_add`.
1389         */
1390         pragma(inline, true)
1391         @property size_t mutatingCallCount() const @safe { return _ccc; }
1392         size_t _ccc;  // C mutation call count. number of calls to C GMP function calls that mutate this object
1393     }
1394 
1395     /// @nogc-variant of `toStringz` with heap allocation of null-terminated C-string `stringz`.
1396     pragma(inline, false)
1397     char* _allocStringzCopyOf(in char[] value) @trusted @nogc
1398     {
1399         import core.memory : pureMalloc;
1400         char* stringz = cast(char*)pureMalloc(value.length + 1); // maximum this many characters
1401         size_t i = 0;
1402         foreach (immutable char ch; value[])
1403         {
1404             if (ch != '_')
1405             {
1406                 stringz[i] = ch;
1407                 i += 1;
1408             }
1409         }
1410         stringz[i] = '\0'; // set C null terminator
1411         return stringz;
1412     }
1413 
1414     // qualified C memory managment
1415     pragma(inline, false)
1416     static @trusted extern(C) // locally `@trusted`
1417     {
1418         pragma(mangle, "free")
1419         void qualifiedFree(void* ptr);
1420     }
1421 }
1422 
1423 /** Non-copyable MpZ.
1424 
1425     For reference counting semantics, use `RefCounted` as
1426 
1427     import std.typecons : RefCounted;
1428     alias RcMpZ = RefCounted!MpZ;
1429     RcMpZ x;
1430  */
1431 alias MpZ = _MpZ!false;
1432 
1433 /** Copyable MpZ. */
1434 alias CopyableMpZ = _MpZ!true;
1435 
1436 version(unittest) static assert(isMpZExpr!(MpZ));
1437 
1438 pure nothrow:
1439 
1440 /** Instantiator for `MpZ`. */
1441 _MpZ!copyable mpz(bool copyable = false, Args...)(Args args) @safe
1442 {
1443     version(LDC) pragma(inline, true);
1444     return typeof(return)(args);
1445 }
1446 
1447 /// Swap contents of `x` with contents of `y`.
1448 pragma(inline, true)
1449 void swap(bool copyable)(ref _MpZ!copyable x,
1450                          ref _MpZ!copyable y)
1451 {
1452     import std.algorithm.mutation : swap;
1453     swap(x, y); // x.swap(y);
1454 }
1455 
1456 /// Returns: `x` as a `string` in decimal base.
1457 string toDecimalString(bool copyable)(auto ref const _MpZ!copyable x) // for `std.bigint.BigInt` compatibility
1458 {
1459     version(LDC) pragma(inline, true);
1460     return x.toString(10);
1461 }
1462 
1463 /// Returns: `x` as a uppercased `string` in hexadecimal base without any base prefix (0x).
1464 string toHex(bool copyable)(auto ref const _MpZ!copyable x) // for `std.bigint.BigInt` compatibility
1465 {
1466     version(LDC) pragma(inline, true);
1467     return x.toString(16, true);
1468 }
1469 
1470 /// Returns: the absolute value of `x` converted to the corresponding unsigned type.
1471 Unsigned!T absUnsign(T, bool copyable)(auto ref const _MpZ!copyable x) // for `std.bigint.BigInt` compatibility
1472 if (isIntegral!T)
1473 {
1474     version(LDC) pragma(inline, true);
1475     return _integralAbs(cast(T)x);
1476 }
1477 
1478 /** Returns: absolute value of `x`.
1479     Written as a free function instead of `MpZ`-member because `__traits(isRef, this)` cannot be used.
1480  */
1481 _MpZ!copyable abs(bool copyable)(auto ref const _MpZ!copyable x) @trusted @nogc
1482 {
1483     version(LDC) pragma(inline, true);
1484     static if (__traits(isRef, x)) // l-value `x`
1485     {
1486         typeof(return) y = null; // must use temporary
1487         __gmpz_abs(y._ptr, x._ptr); version(ccc) ++y._ccc;
1488         return y;
1489     }
1490     else                        // r-value `x`
1491     {
1492         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1493         mut_x.absolute();
1494         return move(*mut_x);    // TODO shouldn't have to call `move` here
1495     }
1496 }
1497 
1498 /** Returns: one's complement of value of `x`.
1499     Written as a free function instead of `MpZ`-member because `__traits(isRef, this)` cannot be used.
1500 */
1501 _MpZ!copyable onesComplement(bool copyable)(auto ref const _MpZ!copyable x) @trusted @nogc
1502 {
1503     version(LDC) pragma(inline, true);
1504     static if (__traits(isRef, x)) // l-value `x`
1505     {
1506         typeof(return) y = null; // must use temporary
1507         __gmpz_com(y._ptr, x._ptr); version(ccc) ++y._ccc;
1508         return y;
1509     }
1510     else                        // r-value `x`
1511     {
1512         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1513         mut_x.onesComplement();
1514         return move(*mut_x);    // TODO shouldn't have to call `move` here
1515     }
1516 }
1517 
1518 /// Returns: comparison of the absolute values of `x` and `y`.
1519 int cmpabs(bool copyable)(auto ref const _MpZ!copyable x,
1520                           auto ref const _MpZ!copyable y) @trusted @nogc
1521 {
1522     version(LDC) pragma(inline, true);
1523     return __gmpz_cmpabs(x._ptr, y._ptr);
1524 }
1525 /// ditto
1526 int cmpabs(bool copyable)(auto ref const _MpZ!copyable x, double y) @trusted @nogc
1527 {
1528     version(LDC) pragma(inline, true);
1529     return __gmpz_cmpabs_d(x._ptr, y);
1530 }
1531 /// ditto
1532 int cmpabs(bool copyable)(auto ref const _MpZ!copyable x, ulong y) @trusted @nogc
1533 {
1534     version(LDC) pragma(inline, true);
1535     return __gmpz_cmpabs_ui(x._ptr, y);
1536 }
1537 
1538 /** Returns: next prime greater than `x`.
1539     Written as a free function instead of `MpZ`-member because `__traits(isRef, this)` cannot be used.
1540 */
1541 _MpZ!copyable nextPrime(bool copyable)(auto ref const _MpZ!copyable x) @trusted @nogc
1542 {
1543     version(LDC) pragma(inline, true);
1544     static if (__traits(isRef, x)) // l-value `x`
1545     {
1546         typeof(return) y = null; // must use temporary
1547         __gmpz_nextprime(y._ptr, x._ptr); version(ccc) ++y._ccc;
1548         return y;
1549     }
1550     else                        // r-value `x`
1551     {
1552         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1553         __gmpz_nextprime(mut_x._ptr, x._ptr); version(ccc) ++mut_x._ccc;
1554         return move(*mut_x);    // TODO shouldn't have to call `move` here
1555     }
1556 }
1557 
1558 /// Returns: greatest common divisor (gcd) of `x` and `y`.
1559 _MpZ!copyable gcd(bool copyable)(auto ref const _MpZ!copyable x,
1560                                  auto ref const _MpZ!copyable y) @trusted @nogc
1561 {
1562     version(LDC) pragma(inline, true);
1563     static      if (!__traits(isRef, x)) // r-value `x`
1564     {
1565         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1566         __gmpz_gcd(mut_x._ptr, x._ptr, y._ptr); version(ccc) ++mut_x._ccc;
1567         return move(*mut_x);    // TODO shouldn't have to call `move` here
1568     }
1569     else static if (!__traits(isRef, y)) // r-value `y`
1570     {
1571         typeof(return)* mut_y = (cast(typeof(return)*)(&y)); // @trusted because `MpZ` has no aliased indirections
1572         __gmpz_gcd(mut_y._ptr, x._ptr, y._ptr); version(ccc) ++mut_y._ccc;
1573         return move(*mut_y);    // TODO shouldn't have to call `move` here
1574     }
1575     else                        // l-value `x` and `y`
1576     {
1577         typeof(return) z = null;
1578         __gmpz_gcd(z._ptr, x._ptr, y._ptr); version(ccc) ++z._ccc;
1579         return z;
1580     }
1581 }
1582 /// ditto
1583 _MpZ!copyable gcd(bool copyable)(auto ref const _MpZ!copyable x,
1584                                  ulong y) @trusted @nogc
1585 {
1586     version(LDC) pragma(inline, true);
1587     static if (__traits(isRef, x)) // l-value `x`
1588     {
1589         typeof(return) z = null;
1590         const z_ui = __gmpz_gcd_ui(z._ptr, x._ptr, y); version(ccc) ++z._ccc;
1591         return z;
1592     }
1593     else
1594     {
1595         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1596         const z_ui = __gmpz_gcd_ui(mut_x._ptr, x._ptr, y); version(ccc) ++mut_x._ccc;
1597         return move(*mut_x);    // TODO shouldn't have to call `move` here
1598     }
1599 }
1600 
1601 /// Returns: least common multiple (lcm) of `x` and `y`.
1602 _MpZ!copyable lcm(bool copyable)(auto ref const _MpZ!copyable x,
1603                                  auto ref const _MpZ!copyable y) @trusted @nogc
1604 {
1605     version(LDC) pragma(inline, true);
1606     static      if (!__traits(isRef, x)) // r-value `x`
1607     {
1608         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1609         __gmpz_lcm(mut_x._ptr, x._ptr, y._ptr); version(ccc) ++mut_x._ccc;
1610         return move(*mut_x);    // TODO shouldn't have to call `move` here
1611     }
1612     else static if (!__traits(isRef, y)) // r-value `y`
1613     {
1614         typeof(return)* mut_y = (cast(typeof(return)*)(&y)); // @trusted because `MpZ` has no aliased indirections
1615         __gmpz_lcm(mut_y._ptr, x._ptr, y._ptr); version(ccc) ++mut_y._ccc;
1616         return move(*mut_y);    // TODO shouldn't have to call `move` here
1617     }
1618     else                        // l-value `x` and `y`
1619     {
1620         typeof(return) z = null;
1621         __gmpz_lcm(z._ptr, x._ptr, y._ptr); version(ccc) ++z._ccc;
1622         return z;
1623     }
1624 }
1625 /// ditto
1626 _MpZ!copyable lcm(bool copyable)(auto ref const _MpZ!copyable x,
1627                                  ulong y) @trusted @nogc
1628 {
1629     version(LDC) pragma(inline, true);
1630     static if (__traits(isRef, x)) // l-value `x`
1631     {
1632         typeof(return) z = null;
1633         __gmpz_lcm_ui(z._ptr, x._ptr, y);
1634         return z;
1635     }
1636     else
1637     {
1638         typeof(return)* mut_x = (cast(typeof(return)*)(&x)); // @trusted because `MpZ` has no aliased indirections
1639         __gmpz_lcm_ui(mut_x._ptr, x._ptr, y); version(ccc) ++mut_x._ccc;
1640         return move(*mut_x);    // TODO shouldn't have to call `move` here
1641     }
1642 }
1643 
1644 /** Returns: `base` ^^ `exp` (modulo `mod`).
1645  *
1646  * Parameter `exp` must be positive.
1647  */
1648 _MpZ!copyable powm(bool copyable)(auto ref const _MpZ!copyable base,
1649                                   auto ref const _MpZ!copyable exp,
1650                                   auto ref const _MpZ!copyable mod) @trusted
1651 {
1652     version(LDC) pragma(inline, true);
1653     assert(mod != 0, "Zero modulus");
1654     typeof(return) y = 0; // result, TODO reuse `exp` or `mod` if any is an r-value
1655     assert(exp >= 0, "Negative exponent");
1656     __gmpz_powm(y._ptr, base._ptr, exp._ptr, mod._ptr); version(ccc) ++y._ccc;
1657     return y;
1658 }
1659 /// ditto
1660 _MpZ!copyable powm(bool copyable)(auto ref const _MpZ!copyable base,
1661                                   ulong exp,
1662                                   auto ref const _MpZ!copyable mod) @trusted
1663 {
1664     version(LDC) pragma(inline, true);
1665     assert(mod != 0, "Zero modulus");
1666     typeof(return) y = 0;       // result, TODO reuse `exp` or `mod` if any is an r-value
1667     __gmpz_powm_ui(y._ptr, base._ptr, exp, mod._ptr); version(ccc) ++y._ccc;
1668     return y;
1669 }
1670 
1671 /** Returns: `base` ^^ `-1` (modulo `mod`).
1672  *
1673  * Parameter `mod` must be positive.
1674  */
1675 _MpZ!copyable invert(bool copyable)(auto ref const _MpZ!copyable base,
1676                                     auto ref const _MpZ!copyable mod) @trusted
1677 {
1678     version(LDC) pragma(inline, true);
1679     assert(base != 0, "Zero base");
1680     assert(mod != 0, "Zero modulus");
1681     static if (!__traits(isRef, base)) // r-value `base`
1682     {
1683         typeof(return)* mut_base = (cast(typeof(return)*)(&base)); // @trusted because `MpZ` has no aliased indirections
1684         auto success = __gmpz_invert(mut_base._ptr, base._ptr, mod._ptr); version(ccc) ++y._ccc;
1685         assert(success >= 0, "Cannot invert");
1686         return move(*mut_base);    // TODO shouldn't have to call `move` here
1687     }
1688     else static if (!__traits(isRef, mod)) // r-value `mod`
1689     {
1690         typeof(return)* mut_mod = (cast(typeof(return)*)(&mod)); // @trusted because `MpZ` has no aliased indirections
1691         auto success = __gmpz_invert(mut_mod._ptr, base._ptr, mod._ptr); version(ccc) ++y._ccc;
1692         assert(success >= 0, "Cannot invert");
1693         return move(*mut_mod);  // TODO shouldn't have to call `move` here
1694     }
1695     else                        // l-value `base` and l-value `mod`
1696     {
1697         typeof(return) y = 0; // result, TODO reuse `exp` or `mod` if any is an r-value
1698         auto success = __gmpz_invert(y._ptr, base._ptr, mod._ptr); version(ccc) ++y._ccc;
1699         assert(success >= 0, "Cannot invert");
1700         return y;
1701     }
1702 }
1703 
1704 /// default construction
1705 @safe nothrow @nogc unittest
1706 {
1707     Z x;
1708     Z y;
1709     assert(x == y);
1710     assert(x is y);             // TODO is this correct behaviour?
1711     x = y;
1712     y = x;
1713 
1714     Z z = 42;
1715     x = z;
1716 
1717     assert(Z.init.dup == Z.init);
1718     assert(Z.init.dup == Z.init.dup);
1719 
1720     assert(Z.init.dup !is Z.init);
1721     assert(Z.init.dup !is Z.init.dup);
1722 
1723     Z w;
1724     w = 42;
1725 }
1726 
1727 /// operate on default-constructed instances
1728 @safe nothrow unittest
1729 {
1730     Z w;
1731 
1732     // should be zeroed
1733     assert(w._z._mp_alloc == 0);
1734     assert(w._z._mp_size == 0);
1735     assert(w._z._mp_d is null);
1736 
1737     assert(w == 0);
1738     assert(w == 0L);
1739     assert(w == 0UL);
1740     assert(w == 0.0f);
1741     assert(w == 0.0);
1742 
1743     assert(w.toString == `0`);
1744     assert(w.toHash == 0);
1745     assert(w.sizeInBase(10) == 1);
1746     assert(w.countOnes == 0);
1747     assert(w.isZero);
1748     assert(-w == w);
1749     assert(abs(w) == w);
1750 
1751     assert(w.fitsIn!ulong);
1752     assert(w.fitsIn!long);
1753     assert(w.fitsIn!uint);
1754     assert(w.fitsIn!int);
1755     assert(w.fitsIn!ushort);
1756     assert(w.fitsIn!short);
1757 
1758     assert(!w.isOdd);
1759     assert(w.isEven);
1760     assert(!w.isNegative);
1761     assert(w.isPositive);
1762     assert(w.sgn == 0);
1763 
1764     w.negate();
1765     assert(w is Z.init);        // should be unchanged
1766     w.negate();
1767     assert(w is Z.init);        // should be unchanged
1768 
1769     w = -w;
1770     assert(w is Z.init);        // should be unchanged
1771 
1772     w = +w;
1773     assert(w is Z.init);        // should be unchanged
1774 
1775     w.absolute();
1776     assert(w is Z.init);        // should be unchanged
1777 
1778     w.onesComplement();
1779     assert(w is Z.init);        // should be unchanged
1780     w.onesComplement();
1781     assert(w is Z.init);        // should be unchanged
1782 
1783     assert(w^^10 == 0);
1784     assert(w^^0 == 1);          // TODO correct?
1785 
1786     // change it and check its contents
1787     w = 42;
1788     assert(w.toString == `42`);
1789     assert(w.toHash != 0);      // should at least be non-zero
1790 
1791     {
1792         Z p;
1793         p.setBit(5);
1794         assert(p == 32);
1795     }
1796     {
1797         Z p;
1798         p.clearBit(5);
1799         assert(p == 0);
1800     }
1801     {
1802         Z p;
1803         p.complementBit(5);
1804         assert(p == 32);
1805     }
1806     {
1807         Z p;
1808         assert(p.testBit(5) == 0);
1809     }
1810     {
1811         Z p;
1812         ++p;
1813         assert(p == 1);
1814     }
1815     {
1816         Z p;
1817         --p;
1818         assert(p == -1);
1819     }
1820 
1821     assert(Z.init + Z.init == Z.init);
1822     assert(Z.init - Z.init == Z.init);
1823     assert(Z.init * Z.init == Z.init);
1824 
1825     assert(Z.init + 1 == 1);
1826     assert(Z.init - 1 == -1);
1827 
1828     assert(Z.init * 1 == 0);
1829     assert(Z.init / 1 == 0);
1830     assert(Z.init ^^ 1 == Z.init);
1831     assert(Z.init ^^ 0 == 1);
1832 
1833     assert(1 + Z.init == 1);
1834     assert(1 - Z.init == 1);
1835     assert(1 * Z.init == 0);
1836 }
1837 
1838 /// null construction
1839 @safe nothrow @nogc unittest
1840 {
1841     Z x = null;
1842     Z y = null;
1843     assert(x == y);
1844     assert(x !is y);
1845 }
1846 
1847 ///
1848 @safe @nogc unittest
1849 {
1850     const x = 42.Z;
1851     assert(x.unaryMinus() == -42);   // l-value `this`
1852     assert(42.Z.unaryMinus() == -42); // r-value `this`
1853 }
1854 
1855 /// convert to string
1856 @safe unittest
1857 {
1858     assert(mpz(    42).toString ==   `42`);
1859     assert(mpz(   -42).toString ==  `-42`);
1860     assert(mpz(`-101`).toString == `-101`);
1861 
1862     assert(mpz(-42).toDecimalString == `-42`);
1863     assert(mpz( 42).toDecimalString ==  `42`);
1864 
1865     assert(mpz( 0).toHex == `0`);
1866     assert(mpz( 1).toHex == `1`);
1867     assert(mpz( 9).toHex == `9`);
1868     assert(mpz(10).toHex == `A`);
1869     assert(mpz(14).toHex == `E`);
1870     assert(mpz(15).toHex == `F`);
1871     assert(mpz(16).toHex == `10`);
1872 
1873     assert(mpz(-42).absUnsign!ulong == 42);
1874     assert(mpz( 42).absUnsign!ulong == 42);
1875 }
1876 
1877 ///
1878 @nogc unittest
1879 {
1880     ubyte[int.sizeof] storage;
1881     ubyte[1] expected = [2];
1882     assert(storage[0] == 0);
1883     auto storage2 =  2.Z.serialize(storage, WordOrder.mostSignificantWordFirst, 1, Endianess.littleEndian, 0);
1884     assert(storage2.ptr == storage.ptr);
1885     assert(storage2 == expected);
1886 }
1887 
1888 unittest
1889 {
1890     ubyte[int.sizeof] storage;
1891     ubyte[1] expected = [2];
1892     ubyte[] storage2 = 2.Z.serialize!(ubyte)(WordOrder.mostSignificantWordFirst, Endianess.littleEndian, 0);
1893     assert(storage2 == expected);
1894 }
1895 
1896 unittest
1897 {
1898     auto prime = 33391.Z;
1899     for (int i = 0; i < 20; ++i)
1900     {
1901         prime = nextPrime(prime);
1902         for (auto order = WordOrder.min; order < WordOrder.max; ++order)
1903         {
1904             for (auto endianess = Endianess.min; endianess < Endianess.max; ++endianess)
1905             {
1906                 ubyte[] data = prime.serialize!(ubyte)(order, endianess, 0);
1907                 auto samePrime = Z(data, order, 1, endianess, 0);
1908                 assert(prime == samePrime);
1909             }
1910         }
1911     }
1912 }
1913 
1914 
1915 
1916 /// opBinary with r-value right-hand-side
1917 @safe @nogc unittest
1918 {
1919     Z a = 42;
1920     {
1921         Z b = a + 1.Z;              // r-value `rhs`
1922         version(ccc) assert(b.mutatingCallCount == 2);
1923         assert(b == 43);
1924     }
1925 
1926     {
1927         Z b = a - 1.Z;              // r-value `rhs`
1928         version(ccc) assert(b.mutatingCallCount == 2);
1929         assert(b == 41);
1930     }
1931 
1932     {
1933         Z b = a * 2.Z;              // r-value `rhs`
1934         version(ccc) assert(b.mutatingCallCount == 2);
1935         assert(b == 84);
1936     }
1937 
1938     {
1939         Z b = a / 2.Z;              // r-value `rhs`
1940         version(ccc) assert(b.mutatingCallCount == 2);
1941         assert(b == 21);
1942     }
1943 
1944     {
1945         Z b = a % 10.Z;              // r-value `rhs`
1946         version(ccc) assert(b.mutatingCallCount == 2);
1947         assert(b == 2);
1948     }
1949 }
1950 
1951 ///
1952 @safe @nogc unittest
1953 {
1954     const _ = (cast(uint)42).Z;
1955     const a = 42.Z;
1956     const b = 43UL.Z;
1957     const c = 43.0.Z;
1958     const z = 0.Z;
1959 
1960     // `opOpAssign` with `Unsigned`
1961     auto w = 42.Z;
1962     assert(w == 42);
1963 
1964     w += 100UL;
1965     assert(w == 142);
1966 
1967     w -= 100.Z;
1968     assert(w == 42);
1969 
1970     w += 100UL;
1971     assert(w == 142);
1972 
1973     w -= 100UL;
1974     assert(w == 42);
1975 
1976     w *= 100UL;
1977     assert(w == 4200);
1978 
1979     w /= 100UL;
1980     assert(w == 42);
1981 
1982     w %= 10UL;
1983     assert(w == 2);
1984 
1985     w ^^= 6UL;
1986     assert(w == 64);
1987 
1988     w = 42;
1989     assert(w == 42);
1990 
1991     w += 100;
1992     assert(w == 142);
1993 
1994     w -= 100;
1995     assert(w == 42);
1996 
1997     w *= 100;
1998     assert(w == 4200);
1999 
2000     w /= 100;
2001     assert(w == 42);
2002 
2003     w *= 100;
2004     assert(w == 4200);
2005 
2006     w /= -100;
2007     assert(w == -42);
2008 
2009     w *= -1;
2010     assert(w == 42);
2011 
2012     w %= 10;
2013     assert(w == 2);
2014 
2015     w = 2;
2016     w ^^= 6;
2017     assert(w == 64);
2018 
2019     w = 32.0;
2020     assert(w == 32);
2021 
2022     w = 42UL;
2023     assert(w == 42);
2024 
2025     w /= 2.Z;
2026     assert(w == 21);
2027 
2028     w /= -2.Z;
2029     assert(w == -10);
2030 
2031     w *= -2.Z;
2032     assert(w == 20);
2033 
2034     w %= 3.Z;
2035     assert(w == 2);
2036 
2037     w *= -1.Z;
2038     assert(w == -2);
2039 
2040     w /= -1.Z;
2041     assert(w == 2);
2042 
2043     // equality
2044     assert(z == 0);
2045     assert(z == cast(uint)0);
2046     assert(z == 0L);
2047     assert(z == 0UL);
2048     assert(z == 0.0f);
2049     assert(z == 0.0);
2050 
2051     // eval cast
2052 
2053     assert(a);
2054     assert(cast(ulong)a == a);
2055     assert(cast(ulong)a == 42);
2056     assert(cast(long)a == a);
2057     assert(cast(long)a == 42);
2058     assert(cast(double)a == 42.0);
2059 
2060     // binary
2061 
2062     assert(`0b11`.Z == 3);
2063     assert(`0B11`.Z == 3);
2064 
2065     // octal
2066 
2067     assert(`07`.Z == 7);
2068     assert(`010`.Z == 8);
2069 
2070     // hexadecimal
2071 
2072     assert(`0x10`.Z == 16);
2073     assert(`0X10`.Z == 16);
2074 
2075     // decimal
2076 
2077     assert(`101`.Z == 101);
2078     assert(`101`.Z == 101);
2079 
2080     immutable ic = 101UL.Z;
2081 
2082     assert(a == a.dup);
2083     assert(ic == ic.dup);
2084 
2085     // equality
2086 
2087     assert(a == a);
2088     assert(a == 42.Z);
2089     assert(a == 42.0);
2090     assert(a == 42);
2091     assert(a == cast(uint)42);
2092     assert(a == 42UL);
2093     assert(_ == 42);
2094     assert(c == 43.0);
2095 
2096     // non-equality
2097 
2098     assert(a != b);
2099 
2100     // less than
2101 
2102     assert(a < b);
2103     assert(a < 43.Z);
2104     assert(a < 43);
2105     assert(a < cast(uint)43);
2106     assert(a < 43UL);
2107     assert(a < 43.0);
2108 
2109     assert(-1.Z < 0.Z);
2110     assert(-1.Z < 0L);
2111     assert(-1.Z < 0UL);
2112     assert(-1.Z < 0.0);
2113 
2114     // greater than
2115 
2116     assert(b > a);
2117     assert(b > 42.Z);
2118     assert(b > 42);
2119     assert(b > cast(uint)42);
2120     assert(b > 42UL);
2121     assert(b > 42.0);
2122 
2123     assert(+1.Z > 0.Z);
2124     assert(+1.Z > 0L);
2125     assert(+1.Z > 0UL);
2126     assert(+1.Z > 0.0);
2127 
2128     // absolute value
2129 
2130     assert(abs(a) == a);        // free function
2131     assert(a.abs == a);         // UFCS
2132     assert(abs(-42.Z) == 42);
2133     assert(abs(-a) == a);
2134 
2135     // absolute value comparison
2136 
2137     assert(cmpabs(-43.Z,  44.Z) == -1);
2138     assert(cmpabs(-43.Z, -44.Z) == -1);
2139     assert(cmpabs(-44.Z, -43.Z) == +1);
2140     assert(cmpabs(-43.Z, -43.Z) ==  0);
2141 
2142     assert(cmpabs(-43.Z,  44.0) == -1);
2143     assert(cmpabs(-43.Z, -44.0) == -1);
2144     assert(cmpabs(-44.Z, -43.0) == +1);
2145     assert(cmpabs(-43.Z, -43.0) ==  0);
2146 
2147     assert(cmpabs(-43.Z, 44) == -1);
2148     assert(cmpabs( 43.Z, 44) == -1);
2149     assert(cmpabs(-44.Z, 43) == +1);
2150     assert(cmpabs( 44.Z, 43) == +1);
2151     assert(cmpabs(-43.Z, 43) ==  0);
2152 
2153     Z _43 = 43;
2154     Z _4 = 4;
2155     Z _24 = 24;
2156 
2157     // next prime
2158     assert(nextPrime(_4) == 5);
2159     assert(nextPrime(24.Z) == 29);
2160 
2161     assert(nextPrime(_24) == 29);
2162     assert(nextPrime(24.Z) == 29);
2163     assert(24.Z.nextPrime() == 29);
2164 
2165     assert(nextPrime(_43) == 47);
2166     assert(nextPrime(43.Z) == 47);
2167     assert(43.Z.nextPrime() == 47);
2168 
2169     // greatest common divisor
2170 
2171     assert(gcd(43.Z,  44.Z) == 1);
2172     assert(gcd(4.Z, 24.Z) == 4);
2173     assert(gcd(6.Z, 24.Z) == 6);
2174     assert(gcd(10.Z, 100.Z) == 10);
2175 
2176     assert(gcd(43.Z,  44) == 1);
2177     assert(gcd(4.Z, 24) == 4);
2178     assert(gcd(6.Z, 24) == 6);
2179     assert(gcd(10.Z, 100) == 10);
2180 
2181     assert(gcd(_43,  44) == 1);
2182     assert(gcd(_4, 24) == 4);
2183     assert(gcd(_4, _24) == 4);
2184     assert(gcd(_4, 24.Z) == 4);
2185 
2186     // least common multiple
2187 
2188     assert(lcm(43.Z,  44.Z) == 1892);
2189     assert(lcm(4.Z, 24.Z) == 24);
2190     assert(lcm(6.Z, 24.Z) == 24);
2191     assert(lcm(10.Z, 100.Z) == 100);
2192 
2193     assert(lcm(43.Z,  44) == 1892);
2194     assert(lcm(4.Z, 24) == 24);
2195     assert(lcm(6.Z, 24) == 24);
2196     assert(lcm(10.Z, 100) == 100);
2197 
2198     assert(lcm(_43,  44) == 1892);
2199     assert(lcm(_4, 24) == 24);
2200     assert(lcm(_4, _24) == 24);
2201     assert(lcm(_4, 24.Z) == 24);
2202 
2203     // negated value
2204 
2205     assert(-a == -42);
2206     assert(-(-a) == a);
2207 
2208     auto n = 42.Z;
2209     n.negate();
2210     assert(n == -42);
2211     n.negate();
2212     assert(n == 42);
2213     n.negate();
2214     assert(n == -42);
2215     n.absolute();
2216     assert(n == 42);
2217     n.absolute();
2218     assert(n == 42);
2219 
2220     n.onesComplement();
2221     assert(n == -43);
2222     assert(onesComplement(n) == 42);
2223     assert(onesComplement(-43.Z) == 42);
2224 
2225     // addition
2226 
2227     assert(a + b == b + a);     // commutative
2228     assert(a + 43.Z == b + a);
2229     assert(a - 43.Z == -(43.Z - a));
2230     assert(a + 0 == a);
2231     assert(a + 1 != a);
2232     assert(0 + a == a);
2233     assert(1 + a != a);
2234     assert(a + 0UL == a);
2235     assert(a + 1UL != a);
2236     assert(a + b == 42 + 43);
2237     assert(1 + a == 43);
2238     assert(a + (-1) == 41);
2239     assert(1UL + a == 43);
2240     assert(a + 1 == 1 + a);       // commutative
2241     assert(a + (-1) == (-1) + a); // commutative
2242     assert(1UL + a == a + 1UL);   // commutative
2243 
2244     // subtraction
2245 
2246     assert(a - 2 == 40);
2247     assert(2 - a == -40);
2248     assert(-2 - a == -44);
2249     assert(a - 2 == -(2 - a));     // commutative
2250     assert(a - (-2) == 44);
2251     assert(44UL - 42.Z == 2);
2252 
2253     // multiplication
2254 
2255     assert(a * 1UL == a);
2256     assert(a * 1 == a);
2257     assert(1 * a == a);
2258     assert(1UL * a == a);
2259     assert((-1) * a == -a);
2260     assert(a * 2 != a);
2261     assert(a * -2 == -(2*a));
2262     assert(a * b == b * a);
2263     assert(a * b == 42UL * 43UL);
2264 
2265     // division
2266 
2267     assert(27.Z / 3.Z == 9);
2268     assert(27.Z /   3  == 9);
2269 
2270     assert(27.Z / 10.Z  == 2);
2271     assert(27.Z /   10   == 2);
2272     assert(27.Z /   10UL == 2);
2273 
2274     assert(27.Z / -3   == -9);
2275     assert(27.Z /  3UL ==  9);
2276 
2277     assert(27.Z / -10   == -2);
2278 
2279     assert(28   /  3.Z ==  9);
2280     assert(28UL /  3.Z ==  9);
2281 
2282     assert(28   / -3.Z == -9);
2283     assert(28UL / -3.Z == -9);
2284 
2285     // modulo/remainder
2286 
2287     assert(27.Z % 3.Z == 0);
2288     assert(27.Z % 10.Z == 7);
2289 
2290     assert(27.Z % 3 == 0);
2291     assert(-27.Z % 3 == 0);
2292 
2293     assert(27.Z % 10 == 7);
2294     assert(27.Z % 10 == 7);
2295 
2296     assert(28   % 3.Z == 1);
2297     assert(28UL % 3.Z == 1);
2298 
2299     assert( 28.Z  % -3 == -1); // negative divisor gives negative remainder according to https://en.wikipedia.org/wiki/Remainder
2300     assert(-28.Z  %  3 == 1);  // dividend sign doesn't affect remainder
2301 
2302     //
2303     assert( 28.Z  % -3.Z == 1);  // TODO should be -1
2304     assert(-28.Z  %  3.Z == -1);  // TODO should be 1
2305     assert( 28  % -3.Z == 1);      // TODO should be -1
2306     assert(-28  %  3.Z == -1);     // TODO should be 1
2307 
2308     // modulo/remainder
2309 
2310     immutable one = 1.Z;
2311     const two = 2.Z;
2312     immutable three = 3.Z;
2313     const four = 4.Z;
2314     immutable five = 5.Z;
2315     const six = 6.Z;
2316     assert(six % one == 0);
2317     assert(six % two == 0);
2318     assert(six % three == 0);
2319     assert(six % four == 2);
2320     assert(six % five == 1);
2321     assert(six % six == 0);
2322 
2323     // subtraction
2324 
2325     assert(six - one == 5);
2326     assert(six - 1UL == 5);
2327     assert(six - 1 == 5);
2328     assert(1 - six == -5);
2329     assert(1L - six == -5);
2330     assert(1UL - six == -5);
2331 
2332     // exponentiation
2333 
2334     assert(0.Z^^0 == 1);
2335     assert(3.Z^^3 == 27);
2336     assert(3.Z^^3L == 27);
2337     assert(2.Z^^8 == 256);
2338     assert(2.Z^^8L == 256);
2339     assert(2.Z^^8UL == 256);
2340 
2341     assert(Z.pow(2UL, 8UL) == 256);
2342     assert(Z.pow(2UL, 8) == 256);
2343     assert(Z.pow(2UL, 8) == 256);
2344     assert(Z.pow(2, 8) == 256);
2345     assert(Z.pow(-2, 8) == 256);
2346     assert(Z.pow(-2, 7) == -128);
2347 
2348     // disallow power exponent to be an `MpZ`
2349     assert(!__traits(compiles, 2^^8.Z == 256));
2350     assert(!__traits(compiles, 2L^^8.Z == 256));
2351     assert(!__traits(compiles, 2UL^^8.Z == 256));
2352 
2353     // exponentiation plus modulus
2354 
2355     assert(2.Z.powm(8.Z, 8.Z) == 0.Z);
2356     assert(2.Z.powm(3.Z, 16.Z) == 8.Z);
2357     assert(3.Z.powm(3.Z, 16.Z) == 11.Z);
2358 
2359     assert(2.Z.powm(8, 8.Z) == 0.Z);
2360     assert(2.Z.powm(3, 16.Z) == 8.Z);
2361     assert(3.Z.powm(3, 16.Z) == 11.Z);
2362 
2363     // modular multiplicative inverse
2364     assert(3.Z.invert(26.Z) == 9.Z); // r-value `base`
2365     assert(3.Z.invert(-26.Z) == 9.Z); // r-value `base`
2366     {
2367         auto base = 3.Z;
2368         assert(base.invert(26.Z) == 9.Z); // l-value `base` and r-value `mod`
2369     }
2370     {
2371         auto base = 3.Z;
2372         auto mod = 26.Z;
2373         assert(base.invert(mod) == 9.Z); // l-value `base` and l-value `mod
2374     }
2375 
2376     // bitwise and, or and xor
2377 
2378     {
2379         foreach (immutable i; 0 .. 10)
2380         {
2381             foreach (immutable j; 0 .. 10)
2382             {
2383                 assert((i.Z & j.Z) == (i & j));
2384                 assert((i.Z | j.Z) == (i | j));
2385                 assert((i.Z ^ j.Z) == (i ^ j));
2386 
2387                 Z x = null;
2388 
2389                 x = i.Z;
2390                 x &= j.Z;
2391                 assert(x == (i & j));
2392 
2393                 x = i.Z;
2394                 x |= j.Z;
2395                 assert(x == (i | j));
2396 
2397                 x = i.Z;
2398                 x ^= j.Z;
2399                 assert(x == (i ^ j));
2400             }
2401         }
2402     }
2403 
2404     // swap
2405 
2406     auto x = 42.Z;
2407     auto y = 43.Z;
2408 
2409     assert(x == 42);
2410     assert(y == 43);
2411 
2412     x.swap(y);
2413 
2414     assert(y == 42);
2415     assert(x == 43);
2416 
2417     swap(x, y);
2418 
2419     assert(x == 42);
2420     assert(y == 43);
2421 
2422     assert(null.Z.fromString("42") == 42.Z);
2423     assert(null.Z.fromString("42") < 43.Z);
2424     assert(null.Z.fromString("42") > 41.Z);
2425     assert(null.Z.fromString("42") == 42);
2426     assert(null.Z.fromString("11", 2) == 3);
2427     assert(null.Z.fromString("7", 8) == 7);
2428     assert(null.Z.fromString("7") == 7);
2429     assert(null.Z.fromString("e", 16) == 14);
2430     assert(null.Z.fromString("f", 16) == 15);
2431     assert(null.Z.fromString("0xe") == 14);
2432     assert(null.Z.fromString("0xf") == 15);
2433     assert(null.Z.fromString("10", 16) == 16);
2434     assert(null.Z.fromString("10", 32) == 32);
2435 
2436     // odd and even
2437 
2438     assert(0.Z.isEven);
2439     assert(1.Z.isOdd);
2440     assert(2.Z.isEven);
2441     assert(3.Z.isOdd);
2442 
2443     assert((-1).Z.isOdd);
2444     assert((-2).Z.isEven);
2445     assert((-3).Z.isOdd);
2446 
2447     assert("300000000000000000000000000000000000000".Z.isEven);
2448     assert("300000000000000000000000000000000000001".Z.isOdd);
2449     assert("300000000000000000000000000000000000002".Z.isEven);
2450     assert("300000000000000000000000000000000000003".Z.isOdd);
2451 
2452     // negative and positive
2453 
2454     assert(0.Z.isPositive);
2455     assert(1.Z.isPositive);
2456     assert(2.Z.isPositive);
2457     assert(3.Z.isPositive);
2458 
2459     assert((-1).Z.isNegative);
2460     assert((-2).Z.isNegative);
2461     assert((-3).Z.isNegative);
2462 
2463     // sign function (sgn)
2464 
2465     assert(long.min.Z.sgn == -1);
2466     assert(int.min.Z.sgn  == -1);
2467     assert(-2.Z.sgn == -1);
2468     assert(-1.Z.sgn == -1);
2469     assert( 0.Z.sgn ==  0);
2470     assert( 1.Z.sgn ==  1);
2471     assert( 2.Z.sgn ==  1);
2472     assert(int.max.Z.sgn  == 1);
2473     assert(long.max.Z.sgn == 1);
2474 
2475     assert(!long.min.Z.isZero);
2476     assert(!int.min.Z.isZero);
2477     assert(!(-2).Z.isZero);
2478     assert(!(-1).Z.isZero);
2479     assert( 0.Z.isZero);
2480     assert(! 1.Z.isZero);
2481     assert(! 2.Z.isZero);
2482     assert(!int.max.Z.isZero);
2483     assert(!long.max.Z.isZero);
2484 
2485     assert(1.Z.populationCount == 1);
2486     assert(2.Z.populationCount == 1);
2487     assert(3.Z.populationCount == 2);
2488     assert(4.Z.populationCount == 1);
2489     assert(5.Z.populationCount == 2);
2490     assert(6.Z.populationCount == 2);
2491     assert(7.Z.populationCount == 3);
2492 
2493     // TODO
2494     // {
2495     //     Z g = null;
2496     //     assert(!b.testBit(0));
2497     //     g.setBit(0);
2498     //     assert(b.testBit(0));
2499     //     g.clearBit(0);
2500     //     assert(!b.testBit(0));
2501     // }
2502 
2503     // fits in type
2504 
2505     foreach (Integral; AliasSeq!(short, int, long,
2506                                  ushort, uint, ulong))
2507     {
2508         assert(Integral.min.Z.fitsIn!Integral);
2509         assert(Integral.max.Z.fitsIn!Integral);
2510     }
2511 
2512     // TODO
2513     // assert(short.min.Z.fitsIn!short);
2514     // assert(short.max.Z.fitsIn!short);
2515     // assert(ushort.min.Z.fitsIn!ushort);
2516     // assert(ushort.max.Z.fitsIn!ushort);
2517 
2518     // internal limb count
2519 
2520     assert(0.Z._limbCount == 0);
2521     assert(1.Z._limbCount == 1);
2522     assert(2.Z._limbCount == 1);
2523 
2524     assert(Z.pow(2UL, 32UL)._limbCount == 1);
2525 
2526     assert(Z.pow(2UL, 63UL)._limbCount == 1);
2527     assert(Z.pow(2UL, 63UL + 1)._limbCount == 2);
2528 
2529     assert(Z.pow(2UL, 127UL)._limbCount == 2);
2530     assert(Z.pow(2UL, 127UL + 1)._limbCount == 3);
2531 
2532     assert(Z.pow(2UL, 255UL)._limbCount == 4);
2533     assert(Z.pow(2UL, 255UL + 1)._limbCount == 5);
2534 }
2535 
2536 /// generators
2537 @safe @nogc unittest
2538 {
2539     assert(Z.mersennePrime(15) == 2^^15 - 1);
2540     assert(Z.mersennePrime(15UL) == 2^^15 - 1);
2541 }
2542 
2543 /// Phobos unittests
2544 @safe @nogc unittest
2545 {
2546     alias bigInt = mpz;
2547     alias BigInt = Z;     // Phobos naming convention
2548 
2549     {
2550         const BigInt a = "9588669891916142";
2551         const BigInt b = "7452469135154800";
2552         const c = a * b;
2553         assert(c == BigInt("71459266416693160362545788781600"));
2554         auto d = b * a;
2555         assert(d == BigInt("71459266416693160362545788781600"));
2556         assert(d == c);
2557         d = c * BigInt("794628672112");
2558         assert(d == BigInt("56783581982794522489042432639320434378739200"));
2559         auto e = c + d;
2560         assert(e == BigInt("56783581982865981755459125799682980167520800"));
2561         const f = d + c;
2562         assert(f == e);
2563         auto g = f - c;
2564         assert(g == d);
2565         g = f - d;
2566         assert(g == c);
2567         e = 12_345_678;
2568         g = c + e;
2569         immutable h = g / b;
2570         const i = g % b;
2571         assert(h == a);
2572         assert(i == e);
2573         BigInt j = "-0x9A56_57f4_7B83_AB78";
2574         j ^^= 11UL;
2575         j ^^= 2L;
2576         j ^^= 2;
2577     }
2578 
2579     {
2580         auto b = BigInt("1_000_000_000");
2581 
2582         b += 12_345;
2583         assert(b == 1_000_012_345);
2584         b += -12_345;
2585         assert(b == 1_000_000_000);
2586 
2587         b -= -12_345;
2588         assert(b == 1_000_012_345);
2589         b -= +12_345;
2590         assert(b == 1_000_000_000);
2591 
2592         b += 12_345;
2593         assert(b == 1_000_012_345);
2594 
2595         b /= 5UL;
2596         assert(b == 200_002_469);
2597     }
2598 
2599     {
2600         auto x = BigInt("123");
2601         const y = BigInt("321");
2602         x += y;
2603         assert(x == 444);
2604     }
2605 
2606     {
2607         const x = BigInt("123");
2608         const y = BigInt("456");
2609         const BigInt z = x * y;
2610         assert(z == 56_088);
2611     }
2612 
2613     {
2614         auto x = BigInt("123");
2615         x *= 300;
2616         assert(x == 36_900);
2617     }
2618 
2619     {
2620         auto x = BigInt("123");
2621         x *= -1;
2622         assert(x == -123);
2623     }
2624 
2625     {
2626         const x  = BigInt("1_000_000_500");
2627 
2628         immutable ulong ul  = 2_000_000UL;
2629         immutable uint ui   = 500_000;
2630         immutable ushort us = 30_000;
2631         immutable ubyte ub  = 50;
2632 
2633         immutable long  l = 1_000_000L;
2634         immutable int   i = 500_000;
2635         immutable short s = 30_000;
2636         immutable byte b  = 50;
2637 
2638         static assert(is(typeof(x % ul)  == ulong));
2639         static assert(is(typeof(x % ui)  == uint));
2640         static assert(is(typeof(x % us)  == ushort));
2641         static assert(is(typeof(x % ub)  == ubyte));
2642 
2643         static assert(is(typeof(x % l)  == long));
2644         static assert(is(typeof(x % i)  == int));
2645         // TODO static assert(is(typeof(x % s)  == short));
2646         // TODO static assert(is(typeof(x % b)  == byte));
2647 
2648         assert(x % ul == 500);
2649         assert(x % ui == 500);
2650         assert(x % us  == 10_500);
2651         assert(x % ub == 0);
2652 
2653         assert(x % l  == 500L);
2654         assert(x % i  == 500);
2655         assert(x % s  == 10_500);
2656         assert(x % b == 0);
2657     }
2658 
2659     {
2660         const x = BigInt("100");
2661         const BigInt y = 123 + x;
2662         assert(y == BigInt("223"));
2663 
2664         const BigInt z = 123 - x;
2665         assert(z == BigInt("23"));
2666 
2667         // Dividing a built-in integer type by BigInt always results in
2668         // something that fits in a built-in type, so the built-in type is
2669         // returned, not BigInt.
2670         static assert(is(typeof(1000 / x) == int));
2671         assert(1000 / x == 10);
2672     }
2673 
2674     {
2675         auto x = BigInt("1234");
2676         assert(+x  == BigInt(" 1234"));
2677         assert(-x  == BigInt("-1234"));
2678         ++x;
2679         assert(x == BigInt("1235"));
2680         --x;
2681         assert(x == BigInt("1234"));
2682     }
2683 
2684     {
2685         const x = BigInt("12345");
2686         const y = BigInt("12340");
2687         immutable int z = 12_345;
2688         immutable int w = 54_321;
2689         assert(x == x);
2690         assert(x != y);
2691         assert(x == y + 5);
2692         assert(x == z);
2693         assert(x != w);
2694     }
2695 
2696     {
2697         // non-zero values are regarded as `true`
2698         const x = BigInt("1");
2699         const y = BigInt("10");
2700         assert(x);
2701         assert(y);
2702 
2703         // zero value is regarded as `false`
2704         const z = BigInt("0");
2705         assert(!z);
2706     }
2707 
2708     {
2709         assert(cast(int)BigInt("0") == 0);
2710         assert(cast(ubyte)BigInt("0") == 0);
2711 
2712         assert(cast(ubyte)BigInt(255) == 255);
2713         assert(cast(ushort)BigInt(65_535) == 65_535);
2714         assert(cast(uint)BigInt(uint.max) == uint.max);
2715         assert(cast(ulong)BigInt(ulong.max) == ulong.max);
2716 
2717         assert(cast(byte)BigInt(-128) == -128);
2718         assert(cast(short)BigInt(-32_768) == -32_768);
2719         assert(cast(int)BigInt(int.min) == int.min);
2720         assert(cast(long)BigInt(long.min) == long.min);
2721 
2722         assert(cast(byte)BigInt(127) == 127);
2723         assert(cast(short)BigInt(32_767) == 32_767);
2724         assert(cast(int)BigInt(int.max) == int.max);
2725         assert(cast(long)BigInt(long.max) == long.max);
2726 
2727         // TODO:
2728         // import std.conv : to, ConvOverflowException;
2729         // import std.exception : assertThrown;
2730         // assertThrown!ConvOverflowException(BigInt("256").to!ubyte);
2731         // assertThrown!ConvOverflowException(BigInt("-1").to!ubyte);
2732     }
2733 
2734     {
2735         // TODO
2736         // segfaults because with double free
2737         // const(BigInt) x = BigInt("123");
2738         // BigInt y = cast()x;    // cast away const
2739         // assert(y == x);
2740     }
2741 
2742     {
2743         const x = BigInt("100");
2744         const y = BigInt("10");
2745         const int z = 50;
2746         const int w = 200;
2747         assert(y < x);
2748         assert(x > z);
2749         assert(z > y);
2750         assert(x < w);
2751     }
2752 
2753     {
2754         assert(BigInt("12345").toLong() == 12_345);
2755         assert(BigInt("-123450000000000000000000000000").toLong() == long.min);
2756         assert(BigInt("12345000000000000000000000000000").toLong() == long.max);
2757     }
2758 
2759     {
2760         assert(BigInt("12345").toInt() == 12_345);
2761         assert(BigInt("-123450000000000000000000000000").toInt() == int.min);
2762         assert(BigInt("12345000000000000000000000000000").toInt() == int.max);
2763     }
2764 }
2765 
2766 // Fermats Little Theorem
2767 @safe @nogc unittest
2768 {
2769     if (unittestLong) // compile but not run unless flagged for because running is slow
2770     {
2771         /*
2772           Fermats little theorem: a ^ p ≡ a (mod p) ∀ prime p check Fermats
2773           little theorem for a ≤ 100000 and all mersene primes M(p) : p ≤ 127
2774         */
2775         foreach (immutable ulong i; [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127])
2776         {
2777             foreach (immutable ulong j; 2 .. 100_000)
2778             {
2779                 const p = Z.mersennePrime(i); // power
2780                 const a = Z(j); // base
2781                 const amp = a % p;
2782                 const b = a.powm(p, p); // result
2783                 assert(b == amp);
2784             }
2785         }
2786     }
2787 }
2788 
2789 // Euler's Sum of Powers Conjecture counter example
2790 pure @nogc unittest
2791 {
2792     /*
2793       a^5 + b^5 + c^5 + d^5 = e^5 Lander & Parkin, 1966 found the first counter
2794       example: 27^5 + 84^5 + 110^5 + 133^5 = 144^5. This test searches for this
2795       counter example by brute force for all positive a, b, c, d ≤ 144
2796     */
2797 
2798     enum LIMIT = 144 + 1;
2799     enum POWER = 5;
2800 
2801     if (unittestLong) // compile but not run unless flagged for because running is slow
2802     {
2803         bool found = false;
2804         Z r1 = 0;
2805     outermost:
2806         foreach (immutable ulong a; 1 .. LIMIT)
2807         {
2808             foreach (immutable ulong b; a .. LIMIT)
2809             {
2810                 foreach (immutable ulong c; b .. LIMIT)
2811                 {
2812                     foreach (immutable ulong d; c .. LIMIT)
2813                     {
2814                         r1 = ((Z(a) ^^ POWER) +
2815                               (Z(b) ^^ POWER) +
2816                               (Z(c) ^^ POWER) +
2817                               (Z(d) ^^ POWER));
2818                         Z rem = 0;
2819                         __gmpz_rootrem(r1._ptr, rem._ptr, r1._ptr, POWER); version(ccc) ++r1._ccc;
2820                         if (rem == 0UL)
2821                         {
2822                             debug printf("Counter Example Found: %lu^5 + %lu^5 + %lu^5 + %lu^5 = %lu^5\n",
2823                                          a, b, c, d, cast(ulong)r1);
2824                             found = true;
2825                             break outermost;
2826                         }
2827                     }
2828                 }
2829             }
2830         }
2831         assert(found);
2832     }
2833 }
2834 
2835 /// expression template types
2836 
2837 /// `MpZ`-`MpZ` adding expression.
2838 struct MpzAddExpr(T1, T2)
2839 if (isMpZExpr!T1 &&
2840     isMpZExpr!T2)
2841 {
2842     T1 e1;                      // first term
2843     T2 e2;                      // second term
2844     MpZ eval() const @trusted
2845     {
2846         version(LDC) pragma(inline, true);
2847         typeof(return) y = null;
2848         __gmpz_add(y._ptr, e1.eval()._ptr, e2.eval()._ptr); version(ccc) ++y._ccc;
2849         return y;
2850     }
2851 }
2852 version(unittest) static assert(isMpZExpr!(MpzAddExpr!(MpZ, MpZ)));
2853 
2854 /// Instantiator for `MpzAddExpr`.
2855 pragma(inline, true)
2856 MpzAddExpr!(T1, T2) mpzAddExpr(T1, T2)(T1 t1, T2 t2)
2857 if (isMpZExpr!T1 &&
2858     isMpZExpr!T2)
2859 {
2860     // TODO don't eval certain type combinations of t1 and t2
2861     return MpzAddExpr!(T1, T2)(t1.eval(), t2.eval());
2862 }
2863 
2864 @safe @nogc unittest
2865 {
2866     assert(MpzAddExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 + 4);
2867 
2868     const Z x = MpzAddExpr!(Z, Z)(3.Z, 4.Z);
2869     version(ccc) assert(x.mutatingCallCount == 1); // lower to `mpz_add`
2870     assert(x == 7);
2871 
2872     Z y = null;
2873     y = MpzAddExpr!(Z, Z)(3.Z, 4.Z);
2874     version(ccc) assert(y.mutatingCallCount == 2); // lowers to `mpz_init`, `mpz_add`
2875     assert(y == 7);
2876 
2877 }
2878 
2879 /// `MpZ`-`MpZ` subtraction expression.
2880 struct MpzSubExpr(T1, T2)
2881 if (isMpZExpr!T1 &&
2882     isMpZExpr!T2)
2883 {
2884     T1 e1;                      // first term
2885     T2 e2;                      // second term
2886     MpZ eval() const @trusted
2887     {
2888         version(LDC) pragma(inline, true);
2889         typeof(return) y = null;
2890         __gmpz_sub(y._ptr, e1.eval()._ptr, e2.eval()._ptr); version(ccc) ++y._ccc;
2891         return y;
2892     }
2893 }
2894 version(unittest) static assert(isMpZExpr!(MpzSubExpr!(MpZ, MpZ)));
2895 
2896 @safe @nogc unittest
2897 {
2898     assert(MpzSubExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 - 4);
2899     const Z x = MpzSubExpr!(Z, Z)(3.Z, 4.Z);
2900     version(ccc) assert(x.mutatingCallCount == 1); // lowers to `mpz_sub`
2901     assert(x == -1);
2902 }
2903 
2904 /// `MpZ`-`MpZ` multiplication expression.
2905 struct MpzMulExpr(F1, F2)
2906 if (isMpZExpr!F1 &&
2907     isMpZExpr!F2)
2908 {
2909     F1 e1;                      // first factor
2910     F2 e2;                      // second factor
2911     MpZ eval() const @trusted
2912     {
2913         version(LDC) pragma(inline, true);
2914         typeof(return) y = null;
2915         __gmpz_mul(y._ptr, e1.eval()._ptr, e2.eval()._ptr); version(ccc) ++y._ccc;
2916         return y;
2917     }
2918 }
2919 version(unittest) static assert(isMpZExpr!(MpzMulExpr!(MpZ, MpZ)));
2920 
2921 @safe @nogc unittest
2922 {
2923     assert(MpzMulExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 * 4);
2924 
2925     const Z x = MpzMulExpr!(Z, Z)(3.Z, 4.Z);
2926     assert(x == 12);
2927     version(ccc) assert(x.mutatingCallCount == 1); // lowers to `mpz_mul`
2928 }
2929 
2930 /// `MpZ`-`MpZ` division expression.
2931 struct MpzDivExpr(P, Q)
2932 if (isMpZExpr!P &&
2933     isMpZExpr!Q)
2934 {
2935     P e1;                       // divisor
2936     Q e2;                       // dividend
2937     MpZ eval() const @trusted
2938     {
2939         version(LDC) pragma(inline, true);
2940         typeof(return) y = null;
2941         __gmpz_tdiv_q(y._ptr, e1.eval()._ptr, e2.eval()._ptr); version(ccc) ++y._ccc;
2942         return y;
2943     }
2944 }
2945 version(unittest) static assert(isMpZExpr!(MpzDivExpr!(MpZ, MpZ)));
2946 
2947 @safe @nogc unittest
2948 {
2949     assert(MpzDivExpr!(Z, Z)(27.Z, 3.Z).eval() == 27 / 3);
2950     assert(MpzDivExpr!(Z, Z)(28.Z, 3.Z).eval() == 28 / 3);
2951     assert(MpzDivExpr!(Z, Z)(29.Z, 3.Z).eval() == 29 / 3);
2952     assert(MpzDivExpr!(Z, Z)(30.Z, 3.Z).eval() == 30 / 3);
2953 
2954     const Z x = MpzDivExpr!(Z, Z)(28.Z, 3.Z);
2955     assert(x == 9);
2956     version(ccc) assert(x.mutatingCallCount == 1); // lowers to `mpz_tdiv_q`
2957 }
2958 
2959 /// `MpZ`-`MpZ` modulus expression.
2960 struct MpzModExpr(P, Q)
2961 if (isMpZExpr!P &&
2962     isMpZExpr!Q)
2963 {
2964     P e1;                       // divisor
2965     Q e2;                       // dividend
2966     MpZ eval() const @trusted
2967     {
2968         version(LDC) pragma(inline, true);
2969         typeof(return) y = null;
2970         __gmpz_tdiv_r(y._ptr, e1.eval()._ptr, e2.eval()._ptr); version(ccc) ++y._ccc;
2971         return y;
2972     }
2973 }
2974 version(unittest) static assert(isMpZExpr!(MpzModExpr!(MpZ, MpZ)));
2975 
2976 @safe @nogc unittest
2977 {
2978     assert(MpzModExpr!(Z, Z)(27.Z, 3.Z).eval() == 27 % 3);
2979     assert(MpzModExpr!(Z, Z)(28.Z, 3.Z).eval() == 28 % 3);
2980     assert(MpzModExpr!(Z, Z)(29.Z, 3.Z).eval() == 29 % 3);
2981     assert(MpzModExpr!(Z, Z)(30.Z, 3.Z).eval() == 30 % 3);
2982 
2983     const Z x = MpzModExpr!(Z, Z)(29.Z, 3.Z);
2984     assert(x == 2);
2985     version(ccc) assert(x.mutatingCallCount == 1); // lowers to `mpz_tdiv_r`
2986 }
2987 
2988 /// `MpZ`-`ulong` power expression.
2989 struct MpzPowUExpr(P, Q)
2990 if (isMpZExpr!P &&
2991     isUnsigned!Q)
2992 {
2993     P e1;                       // base
2994     Q e2;                       // exponent
2995     MpZ eval() const @trusted
2996     {
2997         version(LDC) pragma(inline, true);
2998         typeof(return) y = null;
2999         __gmpz_pow_ui(y._ptr, e1.eval()._ptr, e2); version(ccc) ++y._ccc;
3000         return y;
3001     }
3002 }
3003 version(unittest) static assert(isMpZExpr!(MpzPowUExpr!(MpZ, ulong)));
3004 
3005 @safe @nogc unittest
3006 {
3007     assert(MpzPowUExpr!(Z, ulong)(3.Z, 3).eval() == 3^^3);
3008 }
3009 
3010 /// `MpZ`-`ulong`-`MpZ` power-modulo expression.
3011 struct MpzPowMUExpr(P, Q, M)
3012 if (isMpZExpr!P &&
3013     isUnsigned!Q &&
3014     isMpZExpr!M)
3015 {
3016     P base;                     // base
3017     Q exp;                      // exponent
3018     M mod;                      // modulo
3019     MpZ eval() const @trusted
3020     {
3021         version(LDC) pragma(inline, true);
3022         typeof(return) y = null;
3023         __gmpz_powm_ui(y._ptr, base.eval()._ptr, exp, mod._ptr); version(ccc) ++y._ccc;
3024         return y;
3025     }
3026 }
3027 version(unittest) static assert(isMpZExpr!(MpzPowMUExpr!(MpZ, ulong, MpZ)));
3028 
3029 @safe @nogc unittest
3030 {
3031     assert(MpzPowMUExpr!(Z, ulong, Z)(3.Z, 3, 20.Z).eval() == 3^^3 % 20);
3032 }
3033 
3034 /// `MpZ` negation expression.
3035 struct MpzNegExpr(A)
3036 if (isMpZExpr!A)
3037 {
3038     A e1;
3039     MpZ eval() const @trusted
3040     {
3041         version(LDC) pragma(inline, true);
3042         typeof(return) y = null;
3043         __gmpz_neg(y._ptr, e1.eval()._ptr); version(ccc) ++y._ccc;
3044         return y;
3045     }
3046 }
3047 version(unittest) static assert(isMpZExpr!(MpzNegExpr!(MpZ)));
3048 
3049 @safe @nogc unittest
3050 {
3051     assert(MpzNegExpr!(Z)(27.Z).eval() == -27);
3052 
3053     const Z x = MpzNegExpr!(Z)(27.Z);
3054     version(ccc) assert(x.mutatingCallCount == 1); // lowers to `mpz_neg`
3055     assert(x == -27);
3056 }
3057 
3058 /// Copied from `std.numeric` to prevent unnecessary Phobos deps.
3059 pragma(inline, true)
3060 T _integralAbs(T)(T x)
3061 if (isIntegral!T)
3062 {
3063     return x >= 0 ? x : -x;
3064 }
3065 
3066 /// as hash table key
3067 @safe unittest
3068 {
3069     // TODO disabled until non-copyable types work in AA's
3070     // string[Z] aa;
3071     // aa[123.Z] = "abc";
3072     // aa[456.Z] = "def";
3073     // assert(aa[123.Z] == "abc");
3074     // assert(aa[456.Z] == "def");
3075 }
3076 
3077 /// copyable integer
3078 @trusted unittest
3079 {
3080     alias CZ = CopyableMpZ;
3081 
3082     CZ a = 42;
3083 
3084     CZ b = a;                   // copy
3085     assert(a == b);             // should equal
3086     assert(a !is b);            // but not the same
3087 
3088     CZ c = null;                // other value
3089     assert(a != c);             // should diff
3090 }
3091 
3092 /// to string conversion
3093 @safe pure nothrow unittest
3094 {
3095     for (int i = -100; i < 100; ++i)
3096     {
3097         import std.conv : to;
3098         assert(i.Z.toString == i.to!string);
3099     }
3100 }
3101 
3102 version(unittest)
3103 {
3104     import dbgio : dln;
3105     alias Z = MpZ;
3106     debug import core.stdc.stdio : printf;
3107     // version = ccc;              // do C mutation call count
3108     static assert(!isMpZExpr!int);
3109     import std.meta : AliasSeq;
3110 }
3111 
3112 version(unittest)
3113 {
3114     alias CZ = _MpZ!true;
3115 }
3116 
3117 // C API
3118 extern(C) pragma(inline, false)
3119 {
3120     alias __mp_limb_t = ulong;    // see `mp_limb_t` gmp.h. TODO detect when it is `uint` instead
3121     struct __mpz_struct
3122     {
3123         int _mp_alloc;		/* Number of *limbs* allocated and pointed to by
3124                                    the _mp_d field.  */
3125         int _mp_size;           /* abs(_mp_size) is the number of limbs the last
3126                                    field points to.  If _mp_size is negative
3127                                    this is a negative number.  */
3128         __mp_limb_t* _mp_d;       /* Pointer to the limbs. */
3129     }
3130     static assert(__mpz_struct.sizeof == 16); // fits in two 64-bit words
3131 
3132     alias mpz_srcptr = const(__mpz_struct)*;
3133     alias mpz_ptr = __mpz_struct*;
3134     alias mp_bitcnt_t = ulong;
3135 
3136     pure nothrow @nogc:
3137 
3138     void __gmpz_init (mpz_ptr);
3139     void __gmpz_init_set (mpz_ptr, mpz_srcptr);
3140 
3141     void __gmpz_init_set_d (mpz_ptr, double);
3142     void __gmpz_init_set_si (mpz_ptr, long);
3143     void __gmpz_init_set_ui (mpz_ptr, ulong);
3144     int __gmpz_init_set_str (mpz_ptr, const char*, int);
3145 
3146     void __gmpz_set (mpz_ptr rop, mpz_srcptr op);
3147     void __gmpz_set_ui (mpz_ptr rop, ulong op);
3148     void __gmpz_set_si (mpz_ptr rop, long op);
3149     void __gmpz_set_d (mpz_ptr rop, double op);
3150     int __gmpz_set_str (mpz_ptr, const char*, int);
3151 
3152     void __gmpz_clear (mpz_ptr);
3153 
3154     void __gmpz_abs (mpz_ptr, mpz_srcptr);
3155     void __gmpz_neg (mpz_ptr, mpz_srcptr);
3156 
3157     void __gmpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
3158     void __gmpz_add_ui (mpz_ptr, mpz_srcptr, ulong);
3159     void __gmpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
3160     void __gmpz_addmul_ui (mpz_ptr, mpz_srcptr, ulong);
3161 
3162     void __gmpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
3163     void __gmpz_sub_ui (mpz_ptr, mpz_srcptr, ulong);
3164     void __gmpz_ui_sub (mpz_ptr, ulong, mpz_srcptr);
3165 
3166     void __gmpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
3167     void __gmpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
3168     void __gmpz_mul_si (mpz_ptr, mpz_srcptr, long);
3169     void __gmpz_mul_ui (mpz_ptr, mpz_srcptr, ulong);
3170 
3171     void __gmpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
3172     ulong __gmpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
3173     void __gmpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
3174     void __gmpz_cdiv_ui (mpz_srcptr, ulong);
3175 
3176     void __gmpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
3177     ulong __gmpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
3178     void __gmpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
3179     void __gmpz_fdiv_ui (mpz_srcptr, ulong);
3180 
3181     void __gmpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
3182     void __gmpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
3183     void __gmpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
3184     ulong __gmpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
3185     void __gmpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
3186     void __gmpz_tdiv_ui (mpz_srcptr, ulong);
3187 
3188     void __gmpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
3189 
3190     void __gmpz_pow_ui (mpz_ptr, mpz_srcptr, ulong);
3191     void __gmpz_ui_pow_ui (mpz_ptr, ulong, ulong);
3192 
3193     void __gmpz_swap (mpz_ptr, mpz_ptr);
3194 
3195     int __gmpz_cmp (mpz_srcptr, mpz_srcptr);
3196     int __gmpz_cmp_d (mpz_srcptr, double);
3197     int __gmpz_cmp_si (mpz_srcptr, long);
3198     int __gmpz_cmp_ui (mpz_srcptr, ulong);
3199 
3200     int __gmpz_cmpabs (mpz_srcptr, mpz_srcptr);
3201     int __gmpz_cmpabs_d (mpz_srcptr, double);
3202     int __gmpz_cmpabs_ui (mpz_srcptr, ulong);
3203 
3204     void __gmpz_nextprime (mpz_ptr, mpz_srcptr);
3205 
3206     void __gmpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
3207     ulong __gmpz_gcd_ui (mpz_ptr, mpz_srcptr, ulong);
3208 
3209     void __gmpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
3210     void __gmpz_lcm_ui (mpz_ptr, mpz_srcptr, ulong);
3211 
3212     char *__gmpz_get_str (char*, int, mpz_srcptr);
3213     size_t __gmpz_sizeinbase (mpz_srcptr, int);
3214     void *__gmpz_export (void* , size_t*, int, size_t, int, size_t, mpz_srcptr);
3215     void __gmpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
3216 
3217     void __gmpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
3218     void __gmpz_powm_ui (mpz_ptr, mpz_srcptr, ulong, mpz_srcptr);
3219 
3220     int __gmpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
3221 
3222     ulong __gmpz_get_ui (mpz_srcptr);
3223     long __gmpz_get_si (mpz_srcptr);
3224     double __gmpz_get_d (mpz_srcptr);
3225 
3226     int __gmpz_fits_ulong_p(mpz_srcptr);
3227     int __gmpz_fits_slong_p(mpz_srcptr);
3228     int __gmpz_fits_uint_p(mpz_srcptr);
3229     int __gmpz_fits_sint_p(mpz_srcptr);
3230     int __gmpz_fits_ushort_p(mpz_srcptr);
3231     int __gmpz_fits_sshort_p(mpz_srcptr);
3232 
3233     void __gmpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
3234     void __gmpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
3235     void __gmpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
3236     void __gmpz_com (mpz_ptr, mpz_srcptr);
3237 
3238     void __gmpz_setbit (mpz_ptr, mp_bitcnt_t);
3239     void __gmpz_clrbit (mpz_ptr, mp_bitcnt_t);
3240     void __gmpz_combit (mpz_ptr, mp_bitcnt_t);
3241     int __gmpz_tstbit (mpz_srcptr, mp_bitcnt_t);
3242 
3243     mp_bitcnt_t __gmpz_popcount (mpz_srcptr);
3244 
3245     // TODO wrap:
3246     void __gmpz_root (mpz_ptr, mpz_srcptr, ulong);
3247     void __gmpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
3248 
3249     void __gmpz_sqrt (mpz_ptr, mpz_srcptr);
3250     void __gmpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
3251 
3252     void __gmpz_perfect_power_p (mpz_ptr, mpz_srcptr);
3253 }
3254 
3255 pragma(lib, "gmp");
3256 pragma(lib, "c");               // needed by `malloc` and `free`