# -*- coding: utf-8 -*-
"""
Created on Sun Sep 27 15:57:16 2020

@author: jbobowsk
"""

# This function finds all of the prime numbers between integer inputs a and
# b with b > a.  The function returns an array of the prime numbers listed
# in sequential order and an integer equal to the number of prime numbers
# that exist between a and b.

# Note that the syntax 'y % x' results in the remainder of y/x.  Therefore,
# 'y % 1' has a remainder of zero if and only if y is an integer.

def primes(a, b):
     import numpy as np
     primes = [] # Initialize an empty array
     if a % 1 == 0 and b % 1 == 0 and a > 0 and b > 0 and b > a: # This first
         # if statement checks to see if a and b are positive integers with
         # b > a.  If any of the conditions fail, an error message is returned.
         for i in range(a, b + 1): # loop over all of the integers between a and b.
             cnt = 0 # cnt is used to terminate the while loop below.
             # cnt != 0 implies that a factor has been found and i is not a prime.
             if i != 1 and i % 2 == 1 and sum(map(int, str(i))) % 3 != 0\
             and i % 10 != 5 or i == 2 or i == 3 or i == 5:
                 # Only enter the while loop if i is not 1, 2, 3, 5, even, 
                 #not divisible by 3 and not divisible by 5
                 j = 7 # We will start checking the odd factors from j = 7. 
                 while j < i/(j - 2) and cnt == 0: # Continue the while loop only
                     # if a factor has not been found (cnt = 0) and if the current
                     # candidate factor j is less than i/(j - 2).
                     # The reason for dividing i by j - 2 is the following:
                     # If j is not a factor of i, then it's guaranteed that i will 
                     # not have any factors larger than i/(j - 2).   
                     # Take 25, for example.  j = 3 is not a factor of 25,
                     # so any number greater than 25/3 = 8.33 cannot be a
                     # factor of 25. j = 4 is not a factor of 25, so any
                     # number grater than 25/4 = 6.25 cannot be a factor of
                     # 25.  Of course, 5 is a factor of 25.
                     if i % j == 0: # Check to see if i/j has a remainder.
                         # If it doesn't, then i is not a prime and set cnt = 1
                         # and exist the while loop.
                         cnt = 1
                     j = j + 2 # Increment j to the next odd candidate factor.
                 if cnt == 0: # If after the while loop cnt is still zero, we
                     # have found a prime and it is added to the list of primes.
                     primes = primes + [i]
         f = np.array(primes) # Conver the prime list to an array. 
         n = len(f) # Get the total number of primes found.
     else:
         f = 'ERROR: a and b in primes(a, b) must be positive integers with b > a.'
         n = -1 # Return an error message due to bad inputs.
     return f, n