-1

I'm reaching my limit with UInt64 and I was wondering if there are functions which do simple operating options such as +/- , etc. with just strings because they can store just as much RAM as you have... (theoretically)

For example I would like to calculate

24758800785707605497982484480 + 363463464326426 and get the result as a string.

I kinda know how to solve this problems with strings using the number system 0123456789 and kinda do digit by digit and overflow the next position - which would cost a lot more power, but I wouldn't mind this issue...

I would like to have this ability to do such calculations until my RAM just blows up (which would be the real limit...)

Are there such functions which already do that?

Ben
  • 3,380
  • 2
  • 44
  • 98
  • 1
    look around, there are [plenty solutions](http://stackoverflow.com/a/20944664/800214) – whosrdaddy Nov 21 '14 at 21:27
  • 1
    You can find third party big integer libraries that might help. There are not built-in routines or functions or capabilities that will do so, however, and asking for recommendations for libraries would be off-topic here. – Ken White Nov 21 '14 at 21:29
  • There are many bigint libraries. If perf matters find a wrapper to a reputable non-Delphi library. – David Heffernan Nov 21 '14 at 23:01
  • You can find a Delphi GMP wrapper [here](https://code.google.com/p/gmp-wrapper-for-delphi/). – LU RD Nov 24 '14 at 16:05

3 Answers3

2

Arbitrarily large integers are not supported at the language level in Delphi, but a bit of Googling turns up http://www.delphiforfun.org/programs/Library/big_integers.htm, which can support them as alibrary.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • Thank you, I haven't heard of "BigInt" and such. I'm sure this might be the solution. – Ben Nov 21 '14 at 21:34
  • 1
    Certainly a much better solution than doing calculations in strings. – Rudy Velthuis Nov 22 '14 at 00:21
  • @Rudy The library that Mason links to represents values as a byte array with one byte per decimal digit. Actually, an AnsiString is actually quite a sane data type for that. So far as I know, that's a common way for bigint libraries to operate. More performance oriented libraries will represent the number in a binary data type. http://stackoverflow.com/questions/3242256/how-does-gmp-stores-its-integers-on-an-arbitrary-number-of-bytes – David Heffernan Nov 22 '14 at 08:53
  • Using AnsiStrings to represent binary data (and an integer is as binary as can be) is IMO simply wrong. Most BigInt implementations I know use DWORDS, or at least 31 bits of them to represent the bits. The OP seems to be thinking of some kind of BCD. Not a good idea at all, IMO. – Rudy Velthuis Nov 22 '14 at 10:07
  • FWIW, in UBigIntsV4, the author uses `TDigits = array of int64` to represent the "digits" (or, as Knuth would say: "limbs") of a big int. OK, some of that can still be done a little more efficiently, but that is still a big improvemnt on using an ASCII version of unpacked BCD. – Rudy Velthuis Nov 22 '14 at 10:19
  • @Rudy Looks like I needed to read further down the page. Mason, why recommend this library over, say, a wrapper around gmplib? – David Heffernan Nov 22 '14 at 12:38
  • @DavidHeffernan: Never heard of gmplib, but as a general principle, a native library (as in, actually written in Delphi) is better, when such a choice exists, because a Delphi developer can both read it more easily and debug into it directly. – Mason Wheeler Nov 22 '14 at 13:18
  • @Mason It depends on what you care about. If you care about perf then the language that the code is written is does not matter so much. – David Heffernan Nov 22 '14 at 13:22
  • @DavidHeffernan: If you're using bigints, you don't care about perf; you care about magnitude. :P – Mason Wheeler Nov 22 '14 at 13:26
  • No. You certainly do care about perf oin some scenarios. – David Heffernan Nov 22 '14 at 13:36
  • 1
    @Mason: so you are saying that size counts after all? Anyway, the library you linked to is, IMO, not very performant at all (I looked at the code a little more closely: for instance, it uses arrays of Int64s to store "digits" with a maximum value of `1e6`, i.e. a maximum of 20 bits, for which UInt32s would be more than sufficient). GMP is a highly optimized C library that can easily be wrapped. And since big integers are pretty slow already, compared to hardware supported types, every bit of performance you can get counts, IMO. – Rudy Velthuis Nov 24 '14 at 00:35
1

On super computers, its called BCD math (Binary Coded Decimals) and each half-byte of RAM represents a decimal digit [0..9] - not an efficient use of RAM, but huge computations take minimal time (i.e. about 3 mSecs to multiply 2 million digit numbers. A BCD Emulator on a fast PC takes 5 or 6 minutes.

I never need to add big numbers, but I do multiply. Actually I call this routine iteratively to compute for example, 1000000 factorial (a 5,565,709 million digit answer. Str6Product refers to how it chops up a pair of string numbers. s1 and s2 have a practical length limit of about 2^31. The function is limited by what a "string can hold". Whatever that limit is, I've never gotten there.

//==============================================================================

function Str6Product(s1: string; s2: string): string;     //    6-13  5:15 PM

var
  so,snxt6          : string;
  z1,z3, i, j, k    : Cardinal;      // Cardinal is 32-bit unsigned
  x1,x3,xm      : Cardinal;
  countr            : Cardinal;
  a1, a2, a3        : array of  Int64;
  inum, icarry      : uInt64;        // uInt64 is 64-bit signed
begin

s1 := '00000'+s1;
s2 := '00000'+s2;
z1 := length(s1);                            // set size of Cardinal arrays
z3 := z1 div 6;
x1 := length(s2);                            // set size of Cardinal arrays
x3 := x1 div 6;

xm := max(x3,z3);
SetLength(a1,xm+1);                         
SetLength(a2,xm+1);                      

                                       // try to keep s1 and s2 about the 
                                       // same length for best performance
for i := 1 to xm do begin              // from rt 2 lft - fill arrays
                                       // with 4-byte integers
   if i <= z3 then a1[i]  := StrToInt(copy (s1, z1-i*6+1, 6));
   if i <= x3 then a2[i]  := StrToInt(copy (s2, x1-i*6+1, 6));
   if i  > z3 then a1[i]  := 0;
   if i  > x3 then a2[i]  := 0;
end;

k := max(xm-x3, xm-z3);                      // k prevents leading zeroes
SetLength(a3,xm+xm+1);

icarry := 0;     countr := 0;
icMax  := 0;     inMax  := 0;

for i := 1 to xm do begin             // begin 33 lines of "string mult" engine
   inum := 0;
   for j := 1 to i do
      inum := inum + (a1[i-j+1] * a2[j]);

   icarry := icarry + inum;
   if icMax < icarry then icMax := icarry;
   if inMax < inum   then inMax := inum;
   inum   := icarry mod 1000000;
   icarry := icarry div 1000000;
   countr := countr + 1;
   a3[countr] := inum;
end;
if xm > 1 then begin
   for i := xm  downto k+1 do begin                      // k or 2
      inum := 0;
      for j := 2 to i  do
         inum := inum + (a1[xm+j-i] * a2[xm-j+2]);

      icarry := icarry + inum;
      if icMax < icarry then icMax := icarry;
      if inMax < inum   then inMax := inum;
      inum   := icarry mod 1000000;
      icarry := icarry div 1000000;
      countr := countr + 1;
      a3[countr] := inum;
   end;
end;
if icarry >= 1 then begin
   countr     := countr + 1;
   a3[countr] := icarry;
end;

so := IntToStr(a3[countr]);
for i := countr-1 downto 1 do begin
    snxt6 := IntToStr(a3[i]+1000000);
    so := so+ snxt6[2]+ snxt6[3]+ snxt6[4]+ snxt6[5]+ snxt6[6]+ snxt6[7];
end;

while so[1] = '0' do                       // leading zeroes may exist
    so := copy(so,2,length(so));

result := so;
end;

//==============================================================================

Test call:

StrText := Str6Product ('742136061320987817587158718975871','623450632948509826743508972875');

0

I should have added that you should be able to add large numbers using the same methodology - From right to left, fragment the strings into 16 byte chunks then convert those chunks to uInt64 variables. Add the least significant digits first and if it produces a 17th byte, carry that over to the 2nd least significant chunk, add those two PLUS any carry over etc. When otherwise done, convert each 16-byte chunk back to string and concatenate accordingly.

The conversions to and from integer to string and vice-versa is a pain, but necessary for big number arithmetic.

  • 2
    This looks more like a comment to your first answer than like an answer. You should edit your first answer instead adding comments as a new answer. Please do so and remove this one :-) – bummi Nov 27 '14 at 07:14