I've created a method for handling huge numbers, perhaps it might be useful to someone else. Maybe someone can find an error in it...
I was up against a problem: in a set of 1 million elements, how many ways can they be paired? The first el could be paired with 999,999 other choices. For each of those, the 2nd el could be paired with 999,997 other choices, so 999,999 x 999,997 x 999,995 x ... x 1. There would be a half million pairs:
499,999
∏ 999999-2i = ?
i=0
Wolfram/Alpha was unable to compute this.
I wondered if Free Pascal could do it.
Free Pascal's largest type (that I know of) is Extended, with a max value of 1.1x10^4932.
I set up a type with separate mantissa (an Extended) and exponent (a uint64).
type bignum = record mant :Extended; expn :uint64; end;
This might be more useful if the exponent be a signed int64 so it could handle very small numbers also.
To multiply two such numbers, you add the exponents and multiply the mantissas, and if the mantissas' product is larger than some limit you divide it by ten and add one to the exponent.
The program below computes the above product. I ran a test, shown at the end of the program - that worked; and I followed the output, it looks correct. The answer it computes is:
499,999
∏ 999999-2i ≈ 8.12014 x 10^2782852
i=0
This seems to be correct. It is smaller than 1M^500K, which is 10^3M.
The program took 1 second to finish on a 2 GHz Pentium.
Program bigmath;
// handles very large numbers
type
bignum = record
mant :Extended;
expn :uint64;
end;
var
// AA, BB, prod :bignum; // test
i :uint32;
accum, multiplier :bignum;
//====================================
procedure adjust( var X :bignum );
begin
while X.mant >= 10 do
begin
X.mant /= 10;
inc( X.expn );
end;
end;
//====================================
function multiply( A,B :bignum ) :bignum;
var temp :bignum;
begin
temp.mant := 1;
temp.expn := 0;
temp.mant := A.mant * B.mant;
temp.expn := A.expn + B.expn;
adjust( temp );
exit( temp );
end;
//=============== MAIN ===============
begin
accum.mant := 1; // accumulates the product
accum.expn := 0; // set it to 1 to begin with
for i := 0 to 499999 do
begin
multiplier.mant := 999999-2*i;
multiplier.expn := 0;
adjust( multiplier );
accum := multiply( accum, multiplier );
// tracking progress:
if (i < 50) or (i > 499949) or (i mod 500 = 0) then
writeln( i:7, ' acc=', accum.mant:0:5, 'x10^', accum.expn,
' multi=', multiplier.mant:0:5, 'x10^', multiplier.expn );
end;
// displaying the final answer:
writeln( ' acc=', accum.mant:0:5, 'x10^', accum.expn,
' multi=', multiplier.mant:0:5, 'x10^', multiplier.expn, ' <====' );
end.
// test: 999,999 * 999,997 = 999996000003
//
// AA.mant := 999999;
// AA.expn := 0;
// BB.mant := 999997;
// BB.expn := 0;
// prod := multiply( AA, BB );
// write( AA.mant:0:0, 'x10^', AA.expn,
// ' x ', BB.mant:0:0, 'x10^', BB.expn,
// ' = ', prod.mant:0:19, 'x10^', prod.expn );
//
// test result
// 999999x10^0 x 999997x10^0 = 9.9999600000300024000x10^11
// note the round-off error creeping up