-
Notifications
You must be signed in to change notification settings - Fork 62
How Erjang handles BigNums
All the JVM-based languages that have automatic overflow from integers to BigInteger have significant performance overhead for doing integer arithmetics. This applies for JRubi, Ioke, Clojure, and so on.
So in the general case, computing val1 + val2
involves a double-dispatch to reach a function that can compute +
for the specific type of the two operands. The code below illustrates how the double dispatch happens (with code for two integers) and the overflow check that will have to happen. The computation happens with 64-bit integers, and the overflow is a range check.
This will have a performance overhead, time wil show how bad it is… I don’t personally think that the extra instructions required is the big cost, the cost is in heap allocating a new ESmall for every integer arithmetic.
The body of ESmall.r_plus
below is almost a verbatim copy of the same code in Clojure. This variant however runs faster because it does not have to do instanceof
or casts, whcih is possible because Erjang objects all inherit from a class that I control. In clojure such a shared super class is not assumed.
// do plus static ENumber plus(EObject n1, EObject n2) { return n1.plus(n2); }
// Any erlang object class EObject { @BIF("+") ENumber plus(EObject rhs) { throw ERT.badarg(this,rhs); } ENumber r_plus(int lhs) { throw ERT.badarg(lhs,this); } ENumber r_plus(BigInteger lhs) { throw ERT.badarg(lhs,this); } ENumber r_plus(double lhs) { throw ERT.badarg(lhs,this); } }
// Representation of int32 class ESmall extends ENumber { int value; ENumber plus(EObject rhs) { return rhs.r_plus(value); } ENumber r_plus(int lhs) { long ret = (long)lhs + this.value; // can we convert ret to 32-bit and back to 64-bit without loss? if(ret == (long)(int)ret) return new ESmall((int)ret); else return new EBig(ret); } // and others ... }
The reality is slightly more complicated than conveyed here, … but you get the general idea. Guard BIFs have separate implementations, they return null
on failure.