Choosing a C/C++ BigInt library

I googled a few keywords, ended up on Boost.Multiprecision. In particular, they support 3 integer types backends: cpp_int, gmp_int and tom_int.

From Boost’s classification: gmp_int (based on GMP) is the fastest, cpp_int (Boost’s creation) the more versatile (?) while tom_int have no licence restrictions.

I wrestled a bit with Boost and GMP build systems (I had to make them work with the Cheerp compiler) before turning to LibTomMath and managing at the first attempt. It’s a pure C library with a mainly educational purpose. No dependencies required, very liberal license, seemed the perfect choice for my purpose.

[[ps: while publishing the article I realized that there is a sister library that promise to be even faster: TomsFastMath. I will give it a try at some point]]

API

Wrapping the memory management and C-style functions calls in a C++ class was needed and consulting the library manual it turned out straightforward (and required no understanding of how a BigInt library internally works).

This is, for example, a function to sum 2 BigInts:

static BigInt* BigInt::add(const BigInt& a, const BigInt& b)

{

BigInt* res = new BigInt();

//mp_add is the libtommath backend function

//wrapper takes care of checking the error

code returned by mp_add

wrapper( mp_add(&a.number, &b.number, &res->number) ); //Every resource will be garbage collected by JavaScript's GC

return res;

}

Then I played a bit with calculating some factorials, fixed the inevitable errors, and I had a working C++ class.

Compile it with Cheerp

Cheerp aims to be just a regular C/C++ compiler. You call it like:

/opt/cheerp/bin/clang++ source_file.cpp -o output.js -target cheerp

In the basic settings, it takes in a cpp file in and it outputs a JavaScript file (wasm / wasm+js / asmjs being other possible output).

cd build_libtommath &&

/opt/cheerp/bin/clang *.c -c -O3 -target cheerp &&

cd .. &&

/opt/cheerp/bin/clang++ wrapper.cpp -c -Ilibtommath -O3 -target cheerp &&

/opt/cheerp/bin/clang++ build_libtommath/*.bc wrapper.bc -o wrapper.js -O3 -target cheerp -cheerp-pretty-code

Here I had to build the library files into .bc files (LLVM internal representation) then my wrapper.cpp into a .bc file, then all .bc files together into a JavaScript file.

It builds, perfect.

Cheerp provides a C++11 attribute [[cheerp::jsexport]], to preserve class names and interfaces into JavaScript, so it was just needed to tag the class with it and now it could be called as a library.

Now I went back to implementing the API, added a few more static methods that were missing in the wrapper class: subtraction, division, remainder, a constructor accepting native JavaScript String, and a toString() member function:

#include <client/types.h> //Cheerp provided header

//that forward declares String methods client::String* BigInt::toString(int radix) const

{

int dim = 0;

wrapper( mp_radix_size(&number, radix, &dim) );

std::string std_string;

std_string.resize(dim-1);

wrapper( mp_toradix(&number, &std_string[0], radix) );

return new client::String( std_string.c_str() );

}

Here is the toString implementation. client::String is just the JavaScript string type. A String constructor from a C char* is also provided in the header file.

Recompiling everything (by now I had a script in place), a couple of more bug fixing, and …with more

It works!