Operator overloading

Overloading

Now that we have a bignum class ZZ, it would be convenient to add two ZZ’s using the + operator, instead of having to call mpz_add directly.

This comes at a cost. If we write a = b + c, a new bignum must be created by the + operator and the old bignum “a” must be cleaned up by the garbage collector and the destructor (which calls mpz_clear). This is a giant overhead, but seems to be hard to avoid in a class based approach.

In C, we don’t have classes, so mpz_add is used directly, i.e. mpz_add(a, b, c). Here the old bignum “a” is not cleaned up and no new bignum is created.

In D we can also overload the += operator, which allows for a = a + b to be made fast, so long as we remember to write a += b wherever possible. In this case we do have control over the bignum “a” and don’t have to clean it up or allocate a new bignum.

The example that we benchmark later in this series could benefit greatly from this optimisation, but for the time being we will only overload the + operator, as the comparison with the C approach is enlightening.

Overloading the + operator for ZZ is quite straightforward. Actually, I couldn’t make head nor tail of the D documentation on operator overloading, so I cheated and just guessed what should work. And it did.

ZZ opAdd(ZZ b)
{
   ZZ r = new ZZ();
   mpz_add(&r.z, &z, &b.z);
   return r;
}

While we are at it we may as well overload the + operator to add a bignum and an int.

ZZ opAdd(int b)
{
   ZZ r = new ZZ();
   mpz_add_si(&r.z, &z, b);
   return r;
}

Of course we are going to need similar functions for the – and * operators. Rather than duplicate the code, D offers a very nice template approach

ZZ binop(alias f)(ZZ b)
{
   ZZ r = new ZZ();
   f(&r.z, &z, &b.z);
   return r;
}

alias binop!(mpz_add) opAdd;
alias binop!(mpz_sub) opSub;
alias binop!(mpz_mul) opMul;

While we are at it, we overload the operators for int, long and ulong. It seems that uints are automatically promoted correctly to a ulong, but for some reason the compiler can’t decide whether to promote an int to a long or ulong, which causes an ambiguity unless the operator is also specifically overloaded for an int.

Modules

Finally, as our bignum class implementation is taking on a life of its own, we now put it in a separate file and make it a module. This is as simple as adding the following line at the top of the file (bignum.d):

module bignum;

We can now import this module from our D program in the obvious way:

import bignum;
‹‹‹ Previous Post Next Post ›››

Leave a Reply