1

I was wondering how this program knows if a number is prime or not. I understand that it checks for remainders to find even numbers to divide by but how does it know that a number has only 2 factors? I'm new to the concept of recursion so a explanation of the steps would be helpful thank you.

Code

def RecIsPrime(m):
    """Uses recursion to check if m is prime."""
    def PrimeHelper(m, j):
        """Helper Function to iterate through all j less than m up to 1 to look for even divisors."""
        if j == 1:  # Assume 1 is a prime number even though it's debatable.
            return True
        else:
            #do this task if both conditionals are true
            #else break and return false.
            return m % j != 0 and PrimeHelper(m, j - 1)
    return PrimeHelper(m, m -1)

Source

https://github.com/hydrogeologist/LearningPython/blob/master/_recursion%20example%20in%20Python

Lines: 184 to 194

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Judgey19XX
  • 11
  • 2
  • 3
    Your question focuses on even numbers in a way that the code doesn't. The code focuses on *smaller* numbers, which might or might not be even. The code itself is a shockingly inefficient trial division approach to primality testing and is worthless other than perhaps as a puzzle involving recursion. – John Coleman Nov 05 '16 at 13:41
  • @JohnColeman "even divisors" was probably intended to mean "evenly-dividing numbers". – Will Ness Nov 08 '16 at 13:26
  • Did any of the answers suit your needs? Could you leave a comment or accept an answer? – trincot Nov 16 '16 at 22:21

2 Answers2

2

It checks whether there's any number from m - 1 down to 1 that divides m, it doesn't check just even numbers.

EG, for RecIsPrime(10) you will have these nested functions call:

PrimeHelper(10, 9) = 10 % 9 != 0 and PrimeHelper(10, 8)
↪ PrimeHelper(10, 8) = 10 % 8 != 0 and PrimeHelper(10, 7)
  ↪ PrimeHelper(10, 7) = 10 % 7 != 0 and PrimeHelper(10, 6)
    ↪ PrimeHelper(10, 6) = 10 % 6 != 0 and PrimeHelper(10, 5)
      ↪ PrimeHelper(10, 5) = 10 % 5 != 0 == false

10 % 5 != 0 is false, so the right hand side of the and won't be evaulated. PrimeHelper(10, 5) will return false and doesn't continue the recursion.
In PrimeHelper(10, 6) you get 10 % 6 != 0 to be true, but we've just seen PrimeHelper(10, 5) to be false so this will return false as well, and so will all the other calls.

Andrea Ambu
  • 38,188
  • 14
  • 54
  • 77
0

This code is a tail recursion case, i.e. it can be seen as a recursive way to perform iteration. Note that Python doesn't actually interpret it that way (which would be an optimisation), but it is still helpful to see it like that:

See how every recursive call of PrimeHelper has the same value for m, but has a value for j that is one less compared to the value it had in the previous call.

So the code is comparable to this variant:

def RecIsPrime(m):
    for j in range(m-1, 1, -1):
        if m % j == 0:
            return False
    return m > 1

In this variant every iteration corresponds to a recursive call in the original code. Note that return False breaks the chain, which is done by m % j != 0 in the original code, i.e. there it serves two purposes:

  1. Return False
  2. Don't call PrimeHelper anymore

It is important to note that the two variants do not behave the same way when you call RecIsPrime with an argument of 1 or less. In those cases the recursive code can produce a "division by zero" error (when RecIsPrime(1)) or recurse for ever (e.g. RecIsPrime(-1) or any lesser value). This is a bug. To correct it change:

return PrimeHelper(m, m -1)

by

return m > 1 and PrimeHelper(m, m -1)

which also fixes the case for 1: it is more than just "debatable" whether 1 is prime or not: it is definitely not.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Note that while this is written with the intent of performing tail-recursion Python doesn't actually support it. – Andrea Ambu Nov 05 '16 at 13:58
  • Thanks for highlighting that, @AndreaAmbu. – trincot Nov 05 '16 at 14:05
  • even in a TCO-capable language, whether or not the original code is tail recursive would hinge on the implementational details of `and`. On itself it is tail-rec *modulo-cons*, where the actual *cons* used is the `and` (which can also be the *list-constructing* `cons`, or even `+`, etc.). – Will Ness Nov 08 '16 at 13:23