Practice Makes Perfect 6/15: is_prime. Getting "none" returned for 3


#1

Hello!

I am having a little trouble with the is_prime exercise (here). My code is the following:

def is_prime(x):
  if x > 2:
    for n in range(2, x-1):
    return x % n == 0
  elif x == 2:
    return True
  else:
    return False

I get the error

Your function fails on is_prime(3). It returns None when it should return True.

I don´t understand why it does not pass 3 (I take this is what is what is happening for the loop to return none). If I am not mistaken, what the loop should be doing would be:

  1. Verify 3 % (3-1) == 0, and therefore return True
  2. Verify 3 % 2 == 0, and therefore return True

I added the elif statement because I thought the function might not work when 2 was passed (it would be trying to work with range (2, 1), which I think would contradict the if x > 2 statement.

In any case, the whole thing looks a bit off, so any clues as to how to move forward are appreciated.

Thanks!


#2

This is returning on the first iteration without a conditional. Will definitely return a lot of false positives.

What happens when n is 3? The loop does not run so the return value is, None.


What if you filter the values less than 2, first?

if x < 2: return False

Now test all values greater than 2.

if x > 2: # run factor test

Assuming the factor test has not found a factor, x will fall to the bottom of the code since no return has been encountered in its flow through the logic. We give it the same return that 2 gets after having fallen through the if statements, and '3, falling through the loop.

return True

The first (and only) challenge is the factor test, since all the rest is spelled out. Make it return False if any factor is found. There is no else anywhere in this logic.


#3

Hello!

Thanks for your very detailed explanation! It really helped me visualize the flow and the structure of the function, and made me realize how much better was to filter x < 2 first.

However, you got me completely lost on:

Maybe I did not understand correctly, but I thought modulo did not need an if or return True statement to return False (== 0) or true (<> 0). Did I get it wrong?

Also, I still don´t get why it wouldn´t run for x == 3. Which is probably while I am still getting the same error (Your function fails on is_prime(3). It returns None when it should return True.), in spite of having tried some options.

My code is now the following:

def is_prime(x):
  if x < 2:
    return False
  elif x > 2:
    for n in range(3, x-1):
      if x % n == 0:
	return False
  elif x == 2:
    return True

I really know I am doing something wrong, but I swear I have no clue about what exactly it is.

Thanks a lot anyway for the explanation!


#4

The return line should be an indented block under the if ____:

if ____:
    return False

Not needed, we already know that x is 2 (or another prime).

    for n in ____:
        if ____:
            return False
    return True

Start the range on 2 so all even numbers get flushed on the first pass. It can end on x since the last value in the range will be x - 1.


#5

Thanks!

It works now, with the following code:

def is_prime(x):
	if x < 2:
		return False
	elif x >= 2:
		for n in range(2, x):
			if x % n == 0:
				return False
		return True

It also worked with range(2, x-1) (for the record, my original instinct was to use (2, x) instead of (2, x-1), but the exercise especifically requested x-1 to be used. Must be the only one I got right from the start :joy:).

I still would really appreciate your take on the modulo question of my previous post:

I mean: why needing a conditional and a return statement, if modulo already returns something by itself, and (if I got it correctly) when ==0 it is equivalent to False, and when <> 0 it equals True?

It´s just I am sure I am not getting how modulo works as a Boolean, and that is one of the reasons this exercise took me so long to get.

Again, thanks a lot for your answers, they are helping me a lot with understanding flow control and how to build functions up!


#6

Modulo is not working as a boolean, it is merely part of a boolean expression. A == B is a boolean expression regardless what we write for A or for B. All the modulo is telling us is if there is a factor or not. That is why we only return on False and continue to proceed on True. No else.

As for the range, the instruction is confusing and misleading and had led a thousand people down this path if not more. The author is ambiguous and does not know how well the learner has grasped the concept of range. When it is range(x) the last value IS x - 1. But that is of no real concern since if the range is greater than one-half x it is moot, anyway. How can 3 divide into 5? or 6 into 11? of 51 into 100? What the author thought was leading was misleading. It’s a mistake in the instructions that has cost a lot of people a lot of confusion.

def is_prime(x):
	if x < 2:
		return False
	if x > 2:
		for n in range(2, int(x / 2) + 1):
			if x % n == 0:
				return False
	return True

When it really comes down to it, the upper limit need be no larger than the integer square root of x, plus 1 so it completes the range.

3 * 9 == 9 * 3

int(sqrt(27)) == 5

for n in range(2, 6):
    if 27 % n == 0: return False

The moment n gets to 3 we’re done.

5 * 25 == 25 * 5

int(sqrt(125)) == 11

for n in range(2, 12):
    if 125 % n == 0: return False

Again, the moment n is 5, we’re done. We never exhaust the range if the number x is not prime, and we certainly don’t need a full range.


#7

WOW :open_mouth:

I think I need to study math first, and leave Python for later.

Thanks A LOT for this lesson and for the time you took to answer my questions. Everything is much clearer now!


#8

Or, study math alongside programming. Math is not a prerequisite but a good understanding of it helps when doing math with a program. One thing we do not see right away in maths is the algorithmic nature of equations.

y = ax^2 + bx + c

In the above, y depends upon x, where x is the independent variable and y is the dependent variable. The equation is known as a polynomial in two degrees (or a second degree equation), also known as a quadratic.

What is not so obvious is that this is a curve, a parabola, to be exact. We solve for x to determine the zeros of the equation (where the curve crosses the x-axis). The curve is continuous between -infinity and + infinity and the slope is never constant. The above standard form of the equation describes this curve exactly, but we need an algorithm to be able to plot the curve.

Maths give us ways to sketch the curve using a few points such as the vertex, the zeroes, the amplitude and a little calculus. But with a program we can perform dozens, or hundreds or even thousands of calculations to have the computer plot it for us. If you have a graphing calculator you will be familiar with this process though perhaps not fully aware of how the calculator is doing it. It is simply iterating over very small intervals in some domain for x we can call [a, b], with a being the smaller of the two.

Eg.

https://www.wolframalpha.com/input/?i=x^2+-x+-2

x2-x-2

Does a program help with this process? Immensely. Do we need a program to plot this curve? No. Our math skills, once developed sufficiently are plenty enough for us to sketch it.

Maths help us to see the world in terms of physics. We may discover certain properties of numbers and relationships with a program, but it won’t be the same as learning about them and then using a program to exploit that knowledge. Math is the language of physics. Programming is just a tool to handle the repetitive tasks ans speed up analysis. Respect that Python is a tool for chomping data, and nothing more.

Of course we can do a lot more than just math with a program since computing isn’t just about crunching numbers. Information takes all forms and programs help us to gather, organize and store, and retrieve and process (disseminate) it.

So whatever you do, don’t park your study of programming. When you enter an area where your knowledge is limited then pause long enough to gain more knowledge and understanding, then apply that knowledge to move forward. I have a limited range of ability in both programming and in math but try to learn something new everyday, and apply it so it sinks in. With time complexity yields to elegance and confusion yields to clarity. Just don’t be in too big a hurry and always know that around the next corner you will find what you seek, if you look for it.


#9
from math import sqrt
def quadratic_solutions(a, b, c):
    if a > 0:
        d = b ** 2 - 4 * a * c
        if d > 0:
            x1 = (-b - sqrt(d)) / (2 * a); x2 = (-b + sqrt(d)) / (2 * a)
            print ('a = {}, b = {}, c = {} | There are two real roots, x = {} and {}'.format(a, b, c, x1, x2))
            return (x1, x2)
        elif d < 0:
            print ('a = {}, b = {}, c = {} | There is no real solution.'.format(a, b, c))
        else:
            x = -b / (2 * a)
            print ('a = {}, b = {}, c = {} | Roots are loaded. x = {}'.format(a, b, c, x))
            return x
    elif a < 0: 
        print ('a = {}, b = {}, c = {} | There are no real solutions.'.format(a, b, c))
    else:
        if c == 0:
            print ('a = {}, b = {}, c = {} | Solution is indeterminate!'.format(a, b, c))
        elif b == 0 and c != 0:
            print ('a = {}, b = {}, c = {} | There is no solution.'.format(a, b, c))
        else:
            x = c / -b
            print ('a = {}, b = {}, c = {} | The equation is linear. x = {}'.format(a, b, c, x))
            return x 
print (quadratic_solutions(1, -1, -2))
print (quadratic_solutions(0, -1, -2))
print (quadratic_solutions(0, 0, -2))
print (quadratic_solutions(0, 0, 0))
print (quadratic_solutions(2, 4, 2))
print (quadratic_solutions(5, 2, 1))

==== RESTART: quadratic_formula.py ====
a = 1, b = -1, c = -2 | There are two real roots, x = -1.0 and 2.0
(-1.0, 2.0)
a = 0, b = -1, c = -2 | The equation is linear. x = -2.0
-2.0
a = 0, b = 0, c = -2 | There is no solution.
None
a = 0, b = 0, c = 0 | Solution is indeterminate!
None
a = 2, b = 4, c = 2 | Roots are loaded. x = -1.0
-1.0
a = 5, b = 2, c = 1 | There is no real solution.
None
>>> 

Python Help
#10

Thanks a lot for this!

Your post is a really good example of where I want to be in some years. It really encourages me to keep on with studying and trying to solve math and programming problems! It should be published in a more accessible place, not buried on this thread :slight_smile:

And the quadratic equation function is crystal clear… so much, that it has given me a new, better view on how the equation behaves, different to the way I was taught in high school.

Again, thanks so much for the time you are taking on answering and helping newbies like me learn the ropes… I will probably be back with more questions, hopefully better and better with time!


#11

The above quadratic solutions is based on an assignment posted in the corner bar…

Python Help

You’ll notice a discrepancy in the above code example…

if a < 0

Read #3 in the second set of points (in the screenshot). I believe it is a typo and should read d < 0. When a is less than zero, the graph opens downwards. There are still possible solutions depending on b and c.

I wrote the above solution with the intent of the learner discovering the discrepancy and hopefully asking about it. Nobody likes to tell their teacher they made a mistake but in this case one hopes the teacher discovers this without embarrassment.

revised code
from math import sqrt

def quadratic_solutions(a, b, c):
    if a != 0:
        d = b ** 2 - 4 * a * c
        if d > 0:
            x1 = (-b - sqrt(d)) / (2 * a)
            x2 = (-b + sqrt(d)) / (2 * a)
            print ('a = {}, b = {}, c = {} | There are two real roots, x = {} and {}'.format(a, b, c, x1, x2))
            return (x1, x2)
        elif d < 0:
            print ('a = {}, b = {}, c = {} | There is no real solution.'.format(a, b, c))
            return
        else:
            x = -b / (2 * a)
            print ('a = {}, b = {}, c = {} | Roots are loaded. x = {}'.format(a, b, c, x))
            return x
    else:
        if c == 0:
            print ('a = {}, b = {}, c = {} | Solution is indeterminate!'.format(a, b, c))
            return
        elif b == 0 and c != 0:
            print ('a = {}, b = {}, c = {} | There is no solution.'.format(a, b, c))
            return
        else:
            x = c / -b
            print ('a = {}, b = {}, c = {} | The equation is linear. x = {}'.format(a, b, c, x))
            return x
print (quadratic_solutions(1, -1, -2))
print (quadratic_solutions(-1, 1, 2))    # a less than zero
print (quadratic_solutions(0, -1, -2))
print (quadratic_solutions(0, 0, -2))
print (quadratic_solutions(0, 0, 0))
print (quadratic_solutions(2, 4, 2))
print (quadratic_solutions(5, 2, 1))
a = 1, b = -1, c = -2 | There are two real roots, x = -1.0 and 2.0
(-1.0, 2.0)
a = -1, b = 1, c = 2 | There are two real roots, x = 2.0 and -1.0
(2.0, -1.0)
a = 0, b = -1, c = -2 | The equation is linear. x = -2.0
-2.0
a = 0, b = 0, c = -2 | There is no solution.
None
a = 0, b = 0, c = 0 | Solution is indeterminate!
None
a = 2, b = 4, c = 2 | Roots are loaded. x = -1.0
-1.0
a = 5, b = 2, c = 1 | There is no real solution.
None

#12

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.