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