High-level wrapper for GNU MP (GMP)

Package Information

Version0.0.1 (2017-Jan-23)
CopyrightPer Nordlöw
AuthorsPer Nordlöw
Registered byPer Nordlöw



To use this package, put the following dependency into your project's dependencies section:





D-language high-level wrapper for GNU MP (GMP) library that aims to be compatible with std.bigint.BigInt and @safe pure nothrow @nogc except when converting to string.

Implementation is optimized through

  • mapping of GMP's C macros into D inline functions that operate directly on the internal C-representation __mpz_struct,

  • passing of MpZ-typed parameters as auto ref const

TODO list (in order of priority)

  • Delayed evaluation via expression templates is in development. Evaluation can kick in automatically for r-value parameters (when !__traits(isRef, param) when param is passed as (T)(auto ref const T param)). See this thread.

  • Copy-on-write (COW) RefCounted data store. Optionally with specialized heap-allocator for MpZ type (16-bytes).

  • Use instead of my own extern(C) definitions

  • Define mp{z,q,f} C-function wrappers callable with refs to D-wrapper structs (MpZ, MpQ, MpF).

  • Is for

  • MpZ, MpQ, MpF,

  • Natural/Integer/Rational,

  • (N,Z,Q`,`F) or

  • Big{Nat,Int,Rat,Flt,Float} preferred?

  • Is it preferred to core.stdc.config : c_long, c_ulong instead of builtin long and ulong like is done? The motivation should be that these alias to int and uint on non-Posix systems. This sounds like a very unportable solution.

  • Compare implementation with official C++ wrapper (gmpxx) and Rust wrappers such as rust-gmp to see that no optimization has been overseen

  • Forbid usage of

  • gmp_randinit (not thread-safe, obsolete)

  • mpz_random (not thread-safe, obsolete)

  • mpz_random2 (not thread-safe, obsolete)

  • mpf_set_default_prec (not thread-safe)

  • mpf_get_default_prec (not thread-safe)

  • mpf_init (not thread-safe)

  • mpf_inits (not thread-safe, va_list wrapper)

  • mpf_clears (va_list wrapper)

  • mpf_swap (no better than D's own std.algorithm.swap)

  • mpf_set_prec_raw (could be exposed with an unsafe function if needed)

  • mpz_inits (va_list wrapper)

  • mpz_clears (va_list wrapper)

  • mpz_swap (no better than D's own std.algorithm.swap)

  • mpq_inits (va_list wrapper)

  • mpq_clears (va_list wrapper)

  • mpq_swap (no better than D's own std.algorithm.swap)

  • Lazy evaluation via expression templates

  • x = -x => Assign(x, Neg(x)) => x.negate() (if compiler doesn't already rewrite this)

  • x *= -1 => mpz_neg(x, x) => x.negate()

  • x -= 2*x => mpz_neg(x, x) => x.negate()

  • x = y + z => mpz_add(x, y, z)

  • z = a*x + b*y => mpz_add(x, y, z)

  • x = x + y * z => mpz_addmul(x, y, z)

  • x = x ^ y % z => mpz_powm(x, x, y, z)

  • lots more...

  • toString, opCast should probably evaluate and cache result

  • Define a tagged union on top of __mpz_struct together with a ucent minus one discriminator bit. Similar to the small {array|vector} optimization used in C++ libraries. If value is <= 2^^(64-1)-1 it fits in the non-heap allocated small value.

  • Code generation via something like

ulong a = 27, b = 84, c = 110, d = 133;
compileGMP!"Integer res = a ^^ 5 + b ^^ 5 + c ^^ 5 + d ^^ 5"();

might generate the code

Integer res, r2; // r2 used as a register of sorts (minimise allocation of Integers)
mpz_init(res); mpz_init(r2);

mpz_ui_pow_ui(res, a, 5);
mpz_ui_pow_ui(r2, b, 5);
mpz_add(res, res, r2);

mpz_ui_pow_ui(res, c 5);
mpz_add(res, res, r2);

mpz_ui_pow_ui(r2, d, 5);
mpz_add(res, res, r2);

Available versions

0.0.1 ~master