4

I'm writing a program and I multiply numbers by 5... For example:

var
  i:integer;
  k:int64;
begin
  k:=1;
  for i:=1 to 200000000 do
  begin
    k:=5*(k+2);
  end;
  end;
end.

But when I compıle and start my program I get an overflow integer error. How can I solve this problem?

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
dnaz
  • 276
  • 5
  • 14
  • I try your code in a delphi 7 console application and works ok without exceptions even using {$Q+} (Overflow checking). can you add more details to your question? – RRUZ Aug 01 '11 at 08:23
  • i'm not sure why nobody's suggested this yet, but: *Use a floating point type (e.g. `Real`)* – Ian Boyd Aug 15 '11 at 03:20
  • @IanBoyd It won't fit in `Real` either. And it's always wrong to store integers in floating point data types. – David Heffernan Sep 21 '14 at 21:04
  • @DavidHeffernan It's safe to store integers in floating point types when the numbers are not integers. It depends on what number is representing. That will then help you decide if you can/should use an integral or approximate type. – Ian Boyd Sep 29 '14 at 14:40
  • @IanBoyd Not really. For instance a 64 bit double can store only 53 bits of precision. Beyond 2^52 you can't store all integers any more. Between 2^52 and 2^53 you can only store even numbers. Then between 2^53 and 2^54 you can only store multiples of 4. If you have 64 bits to use, you should store as an integer. So, I would restate my claim that it is always wrong to store integers in floating point data types. Unless you are coding in Javascript. – David Heffernan Sep 29 '14 at 14:47

3 Answers3

7

The correct value of k will be at least 5^20,000,000, or 2^48,000,000. No integer type on a computer is going to be able to store that; that's 48,000,000 bits, for crying out loud. Even if you were to store it in binary, it would take 6,000,000 bytes - 5.7 MB - to store it. Your only hope is arbitary-precision libraries, and good luck with that.

What are you trying to compute? What you are doing right now is computing a sequence of numbers (k) where the ith element is at least as big as 5^i. This won't work up to i = 20,000,000, unless you use other types of variables...

Patrick87
  • 27,682
  • 3
  • 38
  • 73
4

@Patrick87 is right; no integer type on a computer can hold such a number.
@AlexanderMP is also right; you would have to wait for a very long time for this to finish.

Ignoring all that, I think you’re asking for a way to handle extremely large number that won’t fit in an integer variable.
I had a similar problem years ago and here's how I handled it...

Go back to the basics and calculate the answer the same way you would if you were doing it with pencil and paper. Use string variables to hold the text representation of your numbers and create functions that will add & multiply those strings. You already know the algorithms, you learned it as a kid.

If your have two functions are MultiplyNumStrings(Str1, Str2) & AddNumStrings(Str1, Str2) you sample code would look similar except that K is now a string and not an int64:

var
  i : integer;
  k : string;
begin
  k := '1';
  for i:=1 to 200000000 do
  begin
    k := MultiplyNumStrings('5', AddNumStrings(k, '2'));
  end;
end;

This function will add two numbers that are represented by their string digits:

function AddNumStrings (Str1, Str2 : string): string;
var
  i : integer;
  carryStr : string;
  worker : integer;
  workerStr : string;
begin
  Result := inttostr (length(Str1));
  Result := '';
  carryStr := '0';

  // make numbers the same length
  while length(Str1) < length(Str2) do
    Str1 := '0' + Str1;

  while length(Str1) > length(Str2) do
    Str2 := '0' + Str2;

  i := 0;
  while i < length(Str1) do
  begin
    worker := strtoint(copy(Str1, length(str1)-i, 1)) +
              strtoint(copy(Str2, length(str2)-i, 1)) +
              strtoint (carryStr);
    if worker > 9 then
    begin
      workerStr := inttostr(worker);
      carryStr := copy(workerStr, 1, 1);
      result := copy(workerStr, 2, 1) + result;
    end
    else
    begin
      result := inttostr(worker) + result;
      carryStr := '0';
    end;


    inc(i);
  end; { while }
  if carryStr <> '0' then
    result := carryStr + result;
end;

This function will multiply two numbers that are represented by their string digits:

function MultiplyNumStrings (Str1, Str2 : string): string;
var
  i, j : integer;
  carryStr : string;
  worker : integer;
  workerStr : string;
  tempResult : string;
begin
  Result := '';
  carryStr := '0';
  tempResult := '';

  // process each digit of str1
  for i := 0 to length(Str1) - 1 do
  begin
    while length(tempResult) < i do
      tempResult := '0' + tempResult;

    // process each digit of str2
    for j := 0 to length(Str2) - 1 do
    begin
      worker := (strtoint(copy(Str1, length(str1)-i, 1)) *
                 strtoint(copy(Str2, length(str2)-j, 1))) +
                strtoint (carryStr);
      if worker > 9 then
      begin
        workerStr := inttostr(worker);
        carryStr := copy(workerStr, 1, 1);
        tempResult := copy(workerStr, 2, 1) + tempResult;
      end
      else
      begin
        tempResult := inttostr(worker) + tempResult;
        carryStr := '0';
      end;
    end; { for }
    if carryStr <> '0' then
      tempResult := carryStr + tempResult;
    carryStr := '0';

    result := addNumStrings (tempResult, Result);
    tempResult := '';
  end; { for }

  if carryStr <> '0' then
    result := carryStr + result;
end;

Example: We know the max value for an int64 is 9223372036854775807.
If we multiply 9223372036854775807 x 9223372036854775807 using the above routine we get 85070591730234615847396907784232501249.

Pretty cool, huh?

DogLimbo
  • 436
  • 4
  • 9
  • I ran the for-loop listed above for about 20 hours... i was equal to 45,000 and the length of k was 31,455 digits long! I'm not goning to let i run to 200,000,000. – DogLimbo Aug 09 '11 at 16:59
  • 2
    That's because you're using string. An easier and faster way would be to use an array of regular integer for groups of digits. An integer for each 4 digits, so you would easily perform multiplications and obtain maximum 8 digits, which have no problem fitting into a standard 32 bit integer. It should be at least 4 times faster, but even that would be INCREDIBLY slow. More complex data structures could be optimized for speed and memory, but even that doesn't handle the problem of humongous number multiplication speed. The links I gave were to some of these algorithms. – Alex Aug 09 '11 at 21:28
  • 1
    You should replace `strtoint(copy(S, Index, 1))` with `Ord(S[1])-Ord('0')` since all of the characters are `'0'..'9'`, and replace any remaining `copy(S, Index, 1)` with `S[Index]`, which then allows some places, like `carryStr`, to replace `String` with `Char`. – Remy Lebeau Jan 12 '13 at 01:26
3

Performing 2 billion multiplications on huge numbers, in one single thread? Unless you've got a state-of-the-art overclocked CPU cooled with liquid helium, you'd have to wait a whole lot for this to complete. However if you do have, you'd just have to wait for a very long time.

Look what search engines gave out:

if you're lucky, one of them should be enough for this atrocity. If not - good luck finding something.

Community
  • 1
  • 1
Alex
  • 14,338
  • 5
  • 41
  • 59
  • 2
    @AlexanderMP , really? this code is executed in less of two seconds in a VM running delphi 7 and Windows XP. – RRUZ Aug 01 '11 at 08:25
  • I tried calculating Fibonacci (non-recursive) numbers far out in the series, and it took quite a while once it reached large numbers. And the operation was just addition. Here, the numbers are larger, the number of operations is also larger. At this point I am quite surprised of this result you're telling me. Though I did commit an error in my estimations, caused by the error in reading the number. When I saw 2 with lots of zeroes I thought it was maxint for signed 32 bit integers (2 billion), and not 200 million. Which in this case would mean a great deal of performance. – Alex Aug 01 '11 at 17:08