Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi factorial operations precision

SITUATION

I need to make a program for my maths course about Combinations and Permutations. If you want to calculate them you have to deal with factorials and I have written this typical recursive function:

//TCombinazioni is a class that I have created to solve Combinations
function TCombinazioni.fattoriale(const x: integer): Int64;
begin

 Result:= 1;
 if x > 0 then
  begin
   Result:= fattoriale(x-1)*x;
  end;

end;

PROBLEM

I have written this code in my class TCombinazioni:

function TCombinazioni.getSoluzioni: Int64;
begin
  //C(n,k) = (n+k-1)! / (k! * (n-1)!)
  Result := fattoriale(n+k-1) div (fattoriale(k) * fattoriale(n-1));    
end;

The code itself is correct and if n and k (both integers) are small the function returns the desired number. The problem comes out when you input big numbers because the factorial grows up very quickly. Here you see an example.

enter image description here

On the left you can see that the output 11440 is correct but on the right it is not correct. I know that this kind of computation is "dangerous" because I am dealing with big integers, even if they are declared as Int64.

The type Int64 is the biggest type of integer as far as I know, but is there any other possibility if I am trying to make calculations with big integers?

Possible soluton(s)

  1. Very easy, I could set that n and k cannot be greater than 10 for example (but I prefer not doing so)

  2. Using floating point arithmetic. I was thinking that I could use the getSoluzioni function with an Extended return value (instead of Int64). Since the result of these operations must be an integer, I could check if the double has a decimal part equal to zero. If not, I'll not accept the result.

I was considering point number 2 because Extended has a wider range of values than Int64. Is the Extended division in Delphi more precise than Int64 division?

I would like to be able to have a decent result with at least n=14 and k=8 for example.

like image 399
Alberto Miola Avatar asked Jan 07 '17 14:01

Alberto Miola


1 Answers

Extended has 64 bits of precision so no gain there. Plus it greatly complicates the coding. You could certainly make the calculation less prone to overflow by rewriting it to do the divisions as you go along. That will help to a degree. So when you find the same factor in both numerator and denominator simply remove it from both.

But really what you need is a big integer library. Search the web to find one.

like image 143
David Heffernan Avatar answered Nov 19 '22 14:11

David Heffernan