Big Integers in Turbo Pascal 3.01A (3)

Division

The easy way to implement integer division is to use repeated subtraction. I tried this – but even on a Raspberry Pi B under Free Pascal it’s (unsurprisingly) incredibly slow, especially if the denominator is very much smaller than the numerator,

...
      quotient := '0';
      remainder := num;
      while ge(remainder,den) do
      begin
        remainder := sub(remainder,den);
        quotient := add(quotient, '1')
      end;
...

There are many, many algorithms that improve on this – almost all of which need serious study to make them comprehensible. I intend to revisit these if I ever make a version 2 of this library as they should be faster than the method I eventually implemented, based on a recursive algorithm written in C by Bastian Molkenthin. (The Turbo Pascal 3.0 reference manual for CP/M warns against the use of recursion as it’s slow. Quite how slow will be revealed in part 4!).

Here’s the Pascal realisation of Bastian’s method.

var quott, remt: BigInt; { Used as var parameters so can't be declared  }
                         { locally in fastdiv - see TP reference manual }
procedure fastdiv(num: BigInt; den: BigInt; var quot: BigInt; var rem: BigInt);
var dent: BigInt;
begin
  if lt(num,den) = TRUE then   { numerator < denominator, therefore quotient is 0 }
  begin
    quot := '0';
    rem := num
  end
  else
  begin
    dent := multiply(den,'2');  { double the denominator and make recursive call }
    fastdiv(num,dent,quott,remt);
    if lt(remt,den) then        { remainder < denominator, so quotient is doubled }
    begin
      quot := multiply(quott,'2');
      rem := remt
    end
    else                           { remainder >= denominator, so quotient is double }
    begin                          { the remainder plus 1 and the remainder is }
      quot := multiply(quott,'2'); { subtracted from the denominator }
      quot := add(quot, '1');
      rem := sub(remt,den)
    end;
  end;
end;

Modulo

While there are a number of different definitions of modulo, this implements the same definition as Turbo Pascal’s native integer mod function. This is simply the remainder from an integer division, which is positive if the numerator is positive and negative if the numerator is negative, regardless of the sign of the denominator (which is always treated as being positive).

Square root

Straightforward now that integer division is implemented, while remembering to check for attempts to find the square roots of negative numbers, 0 or 1.

Finding integer square roots of selected numbers
...
    if (num[1]='-') then                       { Square roots of negative numbers are complex ! }
      isqrt := 'NaN'
    else
    begin
      if (eq(num,'0') or eq(num,'1')) then     { Trap square root of 0 and 1 }
        isqrt := num
      else
      begin
        t0 := divide(num,'2');
        t1 := divide(num,t0);
        t1 := add(t0,t1);
        t1 := divide(t1,'2');
        while (lt(t1,t0)=TRUE) do              { Keep dividing until the square root is found }
        begin
          t0 := t1;
          t1 := divide(num,t0);
          t1 := add(t0,t1);
          t1 := divide(t1,'2');
        end;
        isqrt := t0
...

The mildly exciting news is that we now have enough of a library implemented to benchmark a Sieve of Eratosthenes prime number algorithm.