Search code examples
pythonpascalfactorization

Pascal/Python Factorization Program


I have made two programs to find the prime factors of a number, one in python and one in pascal. I would like to factorize 600851475143; the python program factorizes it instantly. However, the pascal one does't finish in a reasonable amount of time. Is it to do with the different programming language or how I coded the one in Pascal? I used recursion in the python one but not in the pascal one. Why does the pascal program not also complete instantly?

python:

def findLowestFactor(num, factors=None):
    if factors:
        start = factors[-1]
    else:
        start = 2
    for i in range(start, int(num)):
        if num%i == 0:
            return i
    else:
        return False


def findPrimeFactors(num, factors=None):
    if factors is None:
        factors = []
    factor = findLowestFactor(num, factors)
    if factor:
        factors.append(factor)
        findPrimeFactors(num/factor, factors)
        return factors
    else: 
        factors.append(int(num))
        return factors


if __name__ == "__main__":
    while True:
        num = int(input("Please enter a number: "))
        factors = findPrimeFactors(num)
        print(*factors)

Pascal:

program Primes;

var
  input:string;
  num:integer;
  error:integer;
  factor:integer;
  factors:array of integer;
  found: boolean;
  start:integer;
  x:integer;


begin
  writeln(600851475143);
  (*Repeat untill exit*)
  while true do
  begin
    (*Repeat untill valid input*)
    repeat
    write('Enter a number: ');
    readln(input);
    val(input, num, error);
    if error = 1 then
      writeln('Not an integer');
    until error = 0;

    writeln;

    (*set up list*)
    SetLength(factors, 0);
    factor := 0;
    found := false;
    (*while num is not prime*)
    while found = false do
    begin
      (*start from largest factor found for efficiency*)
      if length(factors) > 0 then
        start := factors[length(factors)-1]
      else
        start := 2;
      (*loop through numbers from number in start var to current num*)
      for factor := start to num do
      begin
        (*if there are no more factors*)
        if num / factor = 1 then
          begin;
            (*add final factor to list*)
            SetLength(factors, length(factors)+1);
            factors[length(factors)-1] := factor;
            (*break out of the loop*)
            found := True;
          end
        (*if factor is found*)
        else if num mod factor = 0 then
          begin
            (*divide num by found factor*)
            num := num div factor;
            (*add the factor*)
            SetLength(factors, length(factors)+1);
            factors[length(factors)-1] := factor;
            (*break for efficiency*)
            Break;
          end;


      end;
    end;

    write('Prime Factors: ');
    for x:= 0 to length(factors)-1 do
      write(factors[x], ' ');
    writeln;
    writeln;

  end;

end. 

Solution

  • I translated your Python code to Pascal. I used Delphi, but it should compile in FreePascal too. It returns instantaneously:

    type
      TIntArray = array of Integer; // Delphi: TArray<Integer>;
    
    function findLowestFactor(num: Int64; factors: TIntArray): Integer;
    var
      start: Integer;
      i: Int64;
    begin
      if Length(factors) > 0 then
        start := factors[High(factors)]  // factors[-1] in Python, i.e. last entry.
      else
        start := 2;
      i := start;
      while i < num do        // Int64 can not be used as index in for-loop... 
      begin                   // ... so I use while loop.
        if num mod i = 0 then // Python: if num % i == 0:
          Exit(i);            // return i
        Inc(i);
      end;
      Exit(0);
    end;
    
    procedure findPrimeFactors(num: Int64; var factors: TIntArray);
    var
      factor: Integer;
    begin
      factor := findLowestFactor(num, factors);
      if factor > 0 then
      begin 
        // Delphi: factors := factors + [factor];
        SetLength(factors, Length(factors) + 1);
        factors[High(factors)] := factor;
    
        findPrimeFactors(num div factor, factors);
      end
      else
      begin
        // Delphi: factors := factors + [Integer(num)];
        SetLength(factors, Length(factors) + 1);
        factors[High(factors)] := Integer(num);
      end;
    end;
    
    const
      testValue: Int64 = 600851475143;
    
    var
      factors: TIntArray;
      i: Integer;
      result: Int64;
    
    begin
      // Instead of user input, I use the testValue above.
      Writeln('test value: ', testValue);
      findPrimeFactors(testValue, factors);
      result := 1;
      for i in factors do
      begin
        Write(i:8);
        result := result * i;
      end;
      Writeln;
      Writeln('multiplied: ', result);
      Readln;
    end.
    

    Note that I had to use Int64 in some places. I assume Python does this automatically, but not Pascal. Perhaps the use of Integers in some places made your code so slow.

    I omitted the user input parts of the code (Readln etc.), just used the constant value you gave. But, as I said, it returns instantaneously, with the right values (see variable result).