Why does this let one prime number through? - python-2.7

I'm going back and tooling around with Project Euler questions to see if I can speed up my code, this is 003: finding the max prime factor of a really big number.
def is_prime(n):
'''check if n is prime'''
if n == 1: return 0
elif n == 2: return 1
elif n % 2 == 0: return 0
for i in range(3, int(n**0.5) +1, 2):
if n % i == 0:
return 0
else:
return 1
factor_list = []
the_number = 600851475143
for i in range(3, int(the_number**0.5) +1, 2):
if the_number % i == 0: factor_list.append(i)
print factor_list
for i in factor_list:
if is_prime(i) == False: factor_list.remove(i)
print factor_list
print max(factor_list)
The first print call prints: [71, 839, 1471, 6857, 59569, 104441, 486847]
So far, so good, printing the pre-n^0.5 factors of n.
The second print call prints: [71, 839, 1471, 6857, 104441]
Wait, how did 104441 slip through the is_prime function?
The third print call prints the incorrect answer, namely 104441. My question is how is 104441 slipping through?

I believe you have an issue with your for loop. When you use a for-each loop, you usually don't want to remove values because it ends up skipping over some. So I think what is happening is that 59569 gets removed, and then because you remove it, your next i value is 486847.
If you want a working solution, refer to steveha's code.

It's always tricky to try to modify a list while looping over it. It's better and safer to just build the list you need, rather than trying to pull out values you don't need.
This code works perfectly:
factor_list = [n for n in xrange(3, int(the_number**0.5) +1, 2) if the_number % n == 0]
print(factor_list)
prime_factors = [n for n in factor_list if is_prime(n)]
print(prime_factors)
answer = max(prime_factors)
print(answer)
Also, you should be returning False and True from is_prime(), not 0 and 1.

Related

Why is the dry run of finding prime number in a given range not working as expected?

n=int(input("Enter a number"))
for num in range(2,n+1):
for i in range(2,num):
if(num%i==0):
break
else:
print(num,end="")
Here is the dry run-:
https://imgur.com/a/8cyBulI
Everything is fine except for 2 where I am not getting 2 as output. What has gone wrong here? I don't understand what is gone wrong here?
2 mod 2 is 0, so your loop breaks.
Instead of checking if your number is divisible by every integer up to the number, try checking it only against the array of primes you have already found - this should be more efficient, and also give the output you are looking for :-)
EDIT:
Here is some code I wrote in JavaScript as an example of my suggestion:
let n = 5
let foundPrimes = []
for (let num = 2; num <= n; num++){
let divisible = false
for (let prime of foundPrimes){
if (num%prime == 0) {
divisible = true
break;
}
}
if (!divisible) {
foundPrimes.push(num)
}
}
console.log(foundPrimes)

code debugging: 'take a list of ints between 0-9, return largest number divisible by 3'

I'm trying to understand what is wrong with my current solution.
The problem is as follows:
using python 2.7.6"
You have L, a list containing some digits (0 to 9). Write a function answer(L) which finds the largest number that can be made from some or all of these digits and is divisible by 3. if it is not possible to make such a number, return 0 as the answer. L will contain anywhere from 1 to 9 digits. The same digit may appear multiple times in the list, but each element in the list may only be used once.
input: (int list) l = [3, 1, 4, 1]
output: (int) 4311
input (int list) l = [3 ,1 ,4 ,1 ,5, 9]
output: (int) = 94311
This is my code to tackle the problem:
import itertools
def answer(l):
'#remove the zeros to speed combinatorial analysis:'
zero_count = l.count(0)
for i in range(l.count(0)):
l.pop(l.index(0))
' # to check if a number is divisible by three, check if the sum '
' # of the individual integers that make up the number is divisible '
' # by three. (e.g. 431: 4+3+1 = 8, 8 % 3 != 0, thus 431 % 3 != 0)'
b = len(l)
while b > 0:
combo = itertools.combinations(l, b)
for thing in combo:
'# if number is divisible by 3, reverse sort it and tack on zeros left behind'
if sum(thing) % 3 == 0:
thing = sorted(thing, reverse = True)
max_div_3 = ''
for digit in thing:
max_div_3 += str(digit)
max_div_3 += '0'* zero_count
return int(max_div_3)
b -= 1
return int(0)
I have tested this assignment many times in my own sandbox and it always works.
However when I have submitted it against my instructor, I end up always failing 1 case.. with no explanation of why. I cannot interrogate the instructor's tests, they are blindly pitched against the code.
Does anyone have an idea of a condition under which my code fails to either return the largest integer divisible by 3 or, if none exists, 0?
The list always has at least one number in it.
It turns out that the problem was with the order of itertools.combinations(l, b)
and sorted(thing, reverse = True). The original code was finding the first match of n%3 == 0 but not necessarily the largest match. Performing sort BEFORE itertools.combinations allowed itertools to find the largest n%3 == 0.

How to simplify for loop in prime number generator in python

import math
def is_prime(num):
if num < 2:
return False
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
return True
Primes seems to be a popular topic but in the book in which I am learning Python, I am on chpt 6 out of 21 and in the iteration chapter which it teaches while loops. I have not learned for loops yet although I understand what they do. So, let's say I have not learned for loops yet and am given only if/elif/else statements and the while loops as my tools. How can I change the for line of code into something more simple using the above tools? While asking this question I quickly came up with this code:
def formula(num):
i = 2
while i >= 2:
return int(math.sqrt(num)+ 1)
def is_primetwo(num):
i = 2
if num < 2:
return False
formula(num)
if num % i == 0:
return False
return True
It works but would this be a simple version of the for loop or is there something even more simple where I do not have to wrap a function within a function?
Absolutely, you do not need a function to replace a for loop.
So you've got this
for i in range(2, int(math.sqrt(num))+ 1):
which is your for loop. Take a second to think what it's doing.
1.) It's taking the variable i, and it's starting it at a value of 2.
2.) It's checking whether to do the loop every time by checking if i is less than the (square root of num) plus 1
3.) Every time through the loop, it adds one to i.
We can do all of these things using a while loop.
Here's the original
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
let's rename the second and third lines loop contents just so we're focusing on the looping part, not what logic we're doing with the variables i and num.
for i in range(2, int(math.sqrt(num))+ 1):
loop contents
ok, now let's just rearrange it to be a while loop. We need to set i to 2 first.
i = 2
Now we want to check that i is in the range we want
i = 2
while i <= int(math.sqrt(num) + 1):
loop contents
Now we're almost set, we just need to make i actually change, instead of staying at a value of 2 forever.
i = 2
while i <= int(math.sqrt(num) + 1):
loop contents
i = i + 1
Your example seemed to do some of these elements, but this way is a simple way to do it, and no extra function is necessary. It could be the range() function that is confusing. Just remember, the for loop is doing three things; setting a variable to an initial value, checking a condition (one variable is less than another), and incrementing your variable to be one large than previously to run the loop again.
How about something like:
from math import sqrt
def is_prime(num):
if (num < 2):
return False
i = 2
limit = int(sqrt(num) + 1)
while (i <= limit):
if num % i == 0:
return False
i = i + 1
return True
Not sure if this is what you want, but the for loop:
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
return True
can be expressed as:
i = 2
while i < int(math.sqrt(num))+ 1):
if num % i == 0:
return False
i += 1
return True
Probably a good idea to determine int(math.sqrt(num))+ 1) once:
i = 2
n = int(math.sqrt(num))+ 1)
while i < n:
if num % i == 0:
return False
i += 1
return True

Project Euler #2 in "Python"

I am an absolute beginner here. I was giving the questions on Project Euler a try in Python. Can you please point out where does my code go wrong?
Q) Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
def fib(a):
if ((a==0) or (a==1)):
return 1
else:
return((fib(a-1))+(fib(a-2)))
r=0
sum=0
while (fib(r))<4000000:
if(((fib(r))%2)==0):
sum+=fib(r)
print(sum)
Your code isn't wrong, it's just too slow. In order to solve Project Euler problems, not only does your code have to be correct, but your algorithm must be efficient.
Your fibonacci computation is extremely expensive - that is, recursively trying to attain the next fibonacci number runs in O(2^n) time - far too long when you want to sum numbers with a limit of four million.
A more efficient implementation in Python is as follows:
x = 1
y = 1
z = 0
result = 0
while z < 4000000:
z = (x+y)
if z%2 == 0:
result = result + z
#next iteration
x = y
y = z
print result
this definetly is not the only way- but another way of doing it.
def fib(number):
series = [1,1]
lastnum = (series[len(series)-1]+series[len(series)-2])
_sum = 0
while lastnum < number:
if lastnum % 2 == 0:
_sum += lastnum
series.append(lastnum)
lastnum = (series[len(series)-1] +series[len(series)-2])
return series,_sum
You should use generator function, here's the gist:
def fib(max):
a, b = 0, 1
while a < max:
yield a
a,b = b, a+b
Now call this function from the shell, or write a function after this calling the fib function, your problem will get resolved.It took me 7 months to solve this problem
This is probably the the most efficient way to do it.
a, b = 1, 1
total = 0
while a <= 4000000:
if a % 2 == 0:
total += a
a, b = b, a+b
print (total)
Using recursion might work for smaller numbers, but since you're testing every case up to 4000000, you might want to store the values that you've already found into values. You can look for this algorithm in existing answers.
Another way to do this is to use Binet's formula. This formula will always return the nth Fibonacci number. You can read more about this on MathWorld.
Note that even numbered Fibonacci numbers occur every three elements in the sequence. You can use:
def binet(n):
""" Gets the nth Fibonacci number using Binet's formula """
return int((1/sqrt(5))*(pow(((1+sqrt(5))/2),n)-pow(((1-sqrt(5))/2),n)));
s = 0; # this is the sum
i = 3;
while binet(i)<=4000000:
s += binet(i);
i += 3; # increment by 3 gives only even-numbered values
print(s);
You may try this dynamic program too, worked faster for me
dict = {}
def fib(x):
if x in dict:
return dict[x]
if x==1:
f = 1
elif x==2:
f = 2
else:
f = fib(x-1) + fib(x-2)
dict[x]=f
return f
i = 1
su = 0
fin = 1
while fin < 4000000:
fin = fib(i)
if fin%2 == 0:
su += fib(i)
i+=1
print (su)
As pointed in other answers your code lacks efficiency. Sometimes,keeping it as simple as possible is the key to a good program. Here is what worked for me:
x=0
y=1
nextterm=0
ans=0
while(nextterm<4000000):
nextterm=x+y
x=y
y=nextterm
if(nextterm%2==0):
ans +=nextterm;
print(ans)
Hope this helps. cheers!
it is optimized and works
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
fib(10000)
This is the slightly more efficient algorithm based on Lutz Lehmann's comment to this answer (and also applies to the accepted answer):
def even_fibonacci_sum(cutoff=4e6):
first_even, second_even = 2, 8
even_sum = first_even + second_even
while even_sum < cutoff:
even_fib = ((4 * second_even) + first_even)
even_sum += even_fib
first_even, second_even = second_even, even_fib
return even_sum
Consider the below Fibonacci sequence:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, ...
Every third element in the Fibonacci sequence is even.
So the even numbers in the above sequence are 2, 8, 34, 144, 610, ...
For even number n, the below equation holds:
n = 4 * (n-1) + (n-2)
Example:
34 = (4 * 8) + 2, i.e., third even = (4 * second even) + first even
144 = (4 * 34) + 8, i.e., fourth even = (4 * third even) + second even
610 = (4 * 144) + 34 i.e., fifth even = (4 * fourth even) + third even
İt's can work with If we know in how many steps we will reach 4000000. It's around 30 steps.
a=1
b=2
list=[a,b]
for i in range (0,30):
a,b=b,a+b
if b%2==0:
list.append(b)
print(sum(list)-1)
Adapting jackson-jones answer to find the sum of the even-valued fibonacci terms below 4 million.
# create a function to list fibonacci numbers < n value
def fib(n):
a, b = 1, 2
while a < n:
yield a
a, b = b, a+b
# Using filter(), we extract even values from our fibonacci function
# Then we sum() the even fibonacci values that filter() returns
print(sum(filter(lambda x: x % 2 == 0, fib(4000000))))
The result is 4613732.

How to calculate first n prime numbers?

Assume the availability of a function is_prime. Assume a variable n has been associated with a positive integer. Write the statements needed to compute the sum of the first n prime numbers. The sum should be associated with the variable total.
Note: is_prime takes an integer as a parameter and returns True if and only if that integer is prime.
Well, I wrote is_prime function like this:
def is_prime(n):
n = abs(n)
i = 2
while i < n:
if n % i == 0:
return False
i += 1
return True
but it works except for n==0. How can I fix it to make it work for every integer?
I'm trying to find out answers for both how to write function to get the sum of first n prime numbers and how to modify my is_prime function, which should work for all possible input, not only positive numbers.
Your assignment is as follows.
Assume the availability of a function is_prime. Assume a variable n has been associated with a positive integer. Write the statements needed to compute the sum of the first n prime numbers. The sum should be associated with the variable total.
As NVRAM rightly points out in the comments (and nobody else appears to have picked up on), the question states "assume the availability of a function is_prime".
You don't have to write that function. What you do have to do is "write the statements needed to compute the sum of the first n prime numbers".
The pseudocode for that would be something like:
primes_left = n
curr_num = 2
curr_sum = 0
while primes_left > 0:
if is_prime(curr_num):
curr_sum = curr_sum + curr_num
primes_left = primes_left - 1
curr_num = curr_num + 1
print "Sum of first " + n + " primes is " + curr_sum
I think you'll find that, if you just implement that pseudocode in your language of choice, that'll be all you have to do.
If you are looking for an implementation of is_prime to test your assignment with, it doesn't really matter how efficient it is, since you'll only be testing a few small values anyway. You also don't have to worry about numbers less than two, given the constraints of the code that will be using it. Something like this is perfectly acceptable:
def is_prime(num):
if num < 2:
return false
if num == 2:
return true
divisor = 2
while divisor * divisor <= num:
if num % divisor == 0:
return false
divisor = divisor + 1
return true
In your problem statement it says that n is a positive integer. So assert(n>0) and ensure that your program outer-loop will never is_prime() with a negative value nor zero.
Your algorithm - trial division of every successive odd number (the 'odd' would be a major speed-up for you) - works, but is going to be very slow. Look at the prime sieve for inspiration.
Well, what happens when n is 0 or 1?
You have
i = 2
while i < n: #is 2 less than 0 (or 1?)
...
return True
If you want n of 0 or 1 to return False, then doesn't this suggest that you need to modify your conditional (or function itself) to account for these cases?
Why not just hardcode an answer for i = 0 or 1?
n = abs(n)
i = 2
if(n == 0 || n == 1)
return true //Or whatever you feel 0 or 1 should return.
while i < n:
if n % i == 0:
return False
i += 1
return True
And you could further improve the speed of your algorithm by omitting some numbers. This script only checks up to the square root of n as no composite number has factors greater than its square root if a number has one or more factors, one will be encountered before the square root of that number. When testing large numbers, this makes a pretty big difference.
n = abs(n)
i = 2
if(n == 0 || n == 1)
return true //Or whatever you feel 0 or 1 should return.
while i <= sqrt(n):
if n % i == 0:
return False
i += 1
return True
try this:
if(n==0)
return true
else
n = abs(n)
i = 2
while i < n:
if n % i == 0:
return False
i += 1
return True