Project Euler Problem #27 is as follows:
Euler discovered the remarkable quadratic formula:
n² + n + 41
It turns out that the formula will produce 40 primes for the
consecutive values n = 0 to 39. However, when n = 40, 402 + 40 + 41 =
40(40 + 1) + 41 is divisible by 41, and certainly when n = 41, 41² +
41 + 41 is clearly divisible by 41.
The incredible formula n² − 79n + 1601 was discovered, which produces
80 primes for the consecutive values n = 0 to 79. The product of the
coefficients, −79 and 1601, is −126479.
Considering quadratics of the form:
n² + an + b, where |a| < 1000 and |b| < 1000
where |n| is the modulus/absolute value of n e.g. |11| = 11 and |−4| =
4 Find the product of the coefficients, a and b, for the quadratic
expression that produces the maximum number of primes for consecutive
values of n, starting with n = 0.
And this is my solution:
from math import sqrt, fabs
def eSieve(rnge):
rootedrange = int(sqrt(rnge))
mydict = dict([(_, True) for _ in range(2, rootedrange)])
for i in range(2, rootedrange):
if mydict[i] == True:
for j in range(i**2, rnge, i):
mydict[j] = False
mylist = []
for key in mydict.keys():
if mydict[key] is True:
mylist.append(key)
return mylist
primes = eSieve(87400)
def isPrime(n):
i = 0
while primes[i] <= n:
if primes[i] == n: return True
i+=1
return False
arange = 0
brange = 0
nrange = 0
for a in range(-1000, 1001):
for b in range(-1000, 1001):
n = 0
formula = n*n + a*n + b
print(formula)
while(isPrime(fabs(formula))):
n+=1
if n > nrange:
arange = a
brange = b
crange = c
print(arange * brange)
I do not know why is it continuously throwing this error:
Traceback (most recent call last):
File "D:\Programming\ProjectEuler\p27.py", line 33, in <module>
while(isPrime(fabs(formula))):
File "D:\Programming\ProjectEuler\p27.py", line 20, in isPrime
while primes[i] <= n:
IndexError: list index out of range
Can anyone tell where and how is my program getting out of lists range? It's very abnormal. Why is this happening?
Let's see what happens if you want to see if 1000000 is a prime:
i = 0
while primes[i] <= n:
if primes[i] == n: return True
i+=1
return False
None of the sieved primes is larger than 1000000 so your while condition is never fulfilled. First rule of Python is to never use while loop (except when you cannot use any other loop). Here you can easily replace it with for:
for i in primes:
if i == n:
return True
return False
But this is exactly what the in operator is set to replace:
return n in primes
In addition for your isPrime reimplementing the Python core feature n in primes, the
item in list gets slower than item in set as the number of items grows.
Thus for fastest code with almost least typing you can do:
>>> primes = eSieve(87400)
>>> prime_set = set(primes)
>>> 13 in prime_set
True
>>> # or if you want a function:
>>> is_prime = prime_set.__contains__
>>> is_prime(13)
True
__contains__ magic method of the set returns true if the given value is in the set - this is much faster using it directly than wrapping in operator in a function.
If isPrime(n) should return whether n is in the previously created list primes, then you can easily write:
def isPrime(n):
return n in primes
(Your solution fails, because your prime list is too short for n = 1000. The largest prime is 293, thus the while condition is always fulfilled. But after a while you want to compare primes[62] with n, which is out of range.)
Related
I am trying to compute the powerset of a list of prime numbers. I have already done some research and the prefered way of doing this seems to be using a line like
itertools.chain.from_iterable(itertools.combinations(primes, r) for r in range(2, len(primes) + 1))
and then iterating over all combinations to get the products with math.prod(). All in all, the code currently looks like this:
number = 200
p1 = []
# calculate all primes below specified number
for i in range(2, number + 1):
isPrime = True
for prime in p1:
if i % prime == 0:
isPrime = False
if isPrime:
p1.append(i)
Pp = []
myIterable = itertools.chain.from_iterable(itertools.combinations(p1, r) for r in range(2, len(p1) + 1))
# convert iterable to integer array of products -- The code below is extremely slow and should be improved
for x in myIterable:
newValue = math.prod(x)
if newValue <= number:
Pp.append(newValue)
This works, but it is not feasible for any "number" greater than 100 because of too high execution time. The problem is the last for loop, which takes forever to compute. Everything else performs reasonably well. The powerset has to be constricted to sets, whos products are less or equal to number, as done using the last if statement, or else the memory will explode.
The solution to this problem was to create a pointer array, which crawls through the prime array until the product of the pointed primes gets too high. The needed helper functions can be implemented like this:
def calcProductOfPointers(pointerArray, dataArray):
prod = 1
for pointer in pointerArray:
prod *= dataArray[pointer]
return prod
def incrementPointer(pointerArray, dataArray, threshold):
ret = False
for i in range(1, len(pointerArray) + 1):
index = len(pointerArray) - i
pointerArray[index] += 1
if calcProductOfPointers(pointerArray, dataArray) <= threshold and pointerArray[index] < len(dataArray):
ret = True
break
elif index > 0:
pointerArray[index] = pointerArray[index - 1] + 2
else:
break
return ret
And then the iteration over all powersets can be substituted with this code:
Pp = []
for i in range(2, len(p1) + 1): # start at a minimum of 2 prime factors
primePointers = []
for index in range(i):
primePointers.append(index)
if calcProductOfPointers(primePointers, p1) > number:
break
while calcProductOfPointers(primePointers, p1) <= number:
Pp.append(calcProductOfPointers(primePointers, p1))
if not incrementPointer(primePointers, p1, number):
break
I'm taking my first programming course, and my assignment has been to list the nth number of prime numbers in the Fibonacci sequence.
So far I've come up with this:
num = int(input("Enter a number: "))
a = 1
b = 1
c = 0
count = 0
isPrime = True
while (count < num):
isPrime = True
c = a + b
for i in range(2,c):
if (c % i == 0):
isPrime = False
break
if (isPrime):
print (c)
count = count + 1
a = b
b = c
This works, but for any input greater than 10 it takes a really long time, can anyone help me figure out how to make it a bit quicker? I assume it's because a,b and c end up becoming really big, but I'm not sure how to fix this.
fib = lambda n:reduce(lambda x,n:[x[1],x[0]+x[1]], range(n),[0,1])[0]
shortest and fastest fibonacci numbers one liner script in python.
>>> fib(1000)
43466557686937456435688527675040625802564660517371780402481729089536555417949051
89040387984007925516929592259308032263477520968962323987332247116164299644090653
3187938298969649928516003704476137795166849228875L
found here.
It's easiest to separate generation of fibonacci numbers from testing for primality. Here's a Python implementation of the Miller-Rabin primality test:
def isPrime(n, k=5): # miller-rabin
from random import randint
if n < 2: return False
for p in [2,3,5,7,11,13,17,19,23,29]:
if n % p == 0: return n == p
s, d = 0, n-1
while d % 2 == 0:
s, d = s+1, d/2
for i in range(k):
x = pow(randint(2, n-1), d, n)
if x == 1 or x == n-1: continue
for r in range(1, s):
x = (x * x) % n
if x == 1: return False
if x == n-1: break
else: return False
return True
Then it is easy to generate fibonacci numbers and test them for primality:
a, b, f = 1, 1, 2
while True:
if isPrime(f): print f
a, b, f = b, f, b+f
It won't take too long to find the 22nd prime fibonacci number:
357103560641909860720907774139063454445569926582843306794041997476301071102767570483343563518510007800304195444080518562630900027386498933944619210192856768352683468831754423234217978525765921040747291316681576556861490773135214861782877716560879686368266117365351884926393775431925116896322341130075880287169244980698837941931247516010101631704349963583400361910809925847721300802741705519412306522941202429437928826033885416656967971559902743150263252229456298992263008126719589203430407385228230361628494860172129702271172926469500802342608722006420745586297267929052509059154340968348509580552307148642001438470316229
You can see the program in action at http://ideone.com/L1oQgO. See A005478 or A001605 for more.
You definitely should use the following well-known heuristic:
To check if N is a prime number you only need to divide it by the
numbers from 2 to sqrt(N).
#user448810 implicitly uses it in the Miller-Rabin primality test. But just in case you just want to improve upon your own code.
This code does the same as the one line code and is more readable:
def fib(n):
a=1
b=1
for i in range(n-2):
a,b = b,a+b
return b
Trying to find the largest palindrome that's the product of two three-digit numbers. Before I look up the infinitely more efficient and - more importantly - working solution, could you tell me what's wrong with my code? I just keep getting the empty set.
def palindrome():
n = 100
m = 100
palind = []
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
return palind
m = m + 1
n = n + 1
return palind
print palindrome()
You have 3 problems.
Problem 1: Returning early.
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
# Here
return palind
m = m + 1
n = n + 1
# And here
return palind
A return statement means the function is over now. It stops where it is, the caller gets the return value, and the caller goes on its way. You don't want to do that until the function is completely done with its work. Let's move the return to after the loops, when the function is done computing.
Problem 2: palind[0] is uninitialized.
while n<=999:
while m<=999:
prod = n * m
# Here v
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
m = m + 1
n = n + 1
return palind
Suppose your program is going along and it finds its first palindrome. It tries to compare it to palind[0], but there is no palind[0]! You need to take the first palindrome without trying to compare it to one that doesn't exist. Let's fix that.
Problem 3: Not resetting m.
palind = None
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1]:
if palind is None or prod > palind:
palind = prod
m = m + 1
n = n + 1
return palind
After the first iteration of the n loop, you need to go back through all possible m values with n=101. You don't do that; your code keeps m at 1000, so it doesn't go through the inner loop again. You could explicitly reset m, but it's much easier to use for loops instead of whiles. With all 3 problems fixed, your code looks like
palind = None
for n in xrange(100, 1000):
for m in xrange(100, 1000):
prod = n * m
if str(prod) == str(prod)[::-1]:
if palind is None or prod > palind:
palind = prod
return palind
This shortcuts when it's impossible to return an i*j > the largest recorded and correctly returns 906609 (note, if you're in python 2, the below would work for you, but you'd prefer to use xrange instead of range to avoid creating unnecessary lists in memory):
def palindrome(floor=0, upto=999):
'''
return the largest palindrome product for all number from (but not including)
floor to (and including) upto
'''
start = upto
largest = None
for i in range(start, floor, -1): # decreasing from upto
if i * upto < largest: # if True, impossible for higher product from combo
break
for j in range(start, i-1, -1): # decrease from upto to not including i-1
product = i*j
if str(product) == str(product)[::-1]:
if product > largest:
largest = product
return largest
Usage:
>>> palindrome(99,999)
906609
>>> palindrome(10,13)
121
>>> palindrome(0,10)
9
The short-cutting is important because if given a very large number, it can take quite a while to return:
>>> palindrome(upto=100000000)
9999000000009999L
I also created a generator that hits every single combination from 0 to 999, and it returns 906609.
def palindrome(upto=1000):
return max(i*j for i in range(upto) for j in range(upto)
if str(i*j) == str(i*j)[::-1])
But when running this palindrome as in:
>>> palindrome(upto=100000000)
The complete search will search all 100000000^2, and take far too long.
I first had written it like this, with the idea that it would short-cut and avoid iterating over every possible combination, but this is incorrect, it returns 888888:
def palindrome():
start = 999
largest = 0
for i in range(start, 0, -1): # decreasing from 999
if i * 999 < largest:
return largest
for j in range(start, i, -1): # decreasing from 999 to i
if str(i*j) == str(i*j)[::-1]:
largest = i*j
It first multiplies 999 times 999, then 998 times 999, then
998*998
997*999
997*998
997*997
...
But the results aren't monotonically decreasing (that is, each result is not guaranteed to be smaller than the previous.)
You are not re-initializing m = 100, after every iteration of the outer while loop
You are returning early. Remove the return statement in the inner loop
The last return statement should NOT be inside the outer while loop.
You never initialized palind list (Thanks to #user2357112)
Suggestions:
Don't use a list to maintain the biggest number. A simple variable is enough.
You don't have to convert the number to string twice in the same expression. Store the stringified number in a variable.
Use range functions to loop through the numbers
If I were to write this program, I would have done it like this
from itertools import product
def palindrome():
numbers, result = range(1000, 100, -1), -1
for num1, num2 in product(numbers, repeat = 2):
prod = num1 * num2
sprod = str(prod)
if sprod == sprod[::-1] and prod > result:
result = prod
return result
print palindrome() # 906609
This is may not answer the question, but if you looking for to get palindromic numbers between range you can do this
def getPalindrome(lower, upper):
listPalind = []
for n in range(lower, upper):
if str(n) == str(n)[::-1]:
listPalind.append(n)
return listPalind
# Usage
print(getPalindrome(100, 300))
# Results
[101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292]
def is_palindromic(s):
if s == s[::-1]:
return True
else:
return False
palind = []
for i in range(100, 1000):
for j in range(100,1000):
product = i * j
if is_palindromic(str(product)):
palind.append(product)
return max(palind)
#result :
906609
def isPalindrome(self, x: int):
temp = 0
x1 = x
while x > 0:
y = x % 10
temp = temp * 10 + y
x = x//10
if(temp == x1):
return True
else:
return False
fib = [0,1]
a = 1
b = 0
i = 0
while i < n:
i = a+b
a,b = i, a
fib.append(i)
This works in cases where 'n' (which is a given variable) is a number in an actual Fibonacci sequence, like 21 or 13. However, if the number is something like six, it adds one more number than it should. The list should not contain a number that is greater than n.
You could always add a to the list first, then do your incrementing.
fib = [0]
a, b = 1, 0
while a <= n:
fib.append(a)
a,b = a+b, a
Using the classic shnazzy recursive Fibonacci function (which took me a few tries to remember and get right):
def fib(num):
if ((num == 0) or (num == 1)): return 1
fib_num = fib(num - 1) + fib(num - 2)
return fib_num
x, n, i = 2, 15, []
while (fib(x) < n):
i.append(fib(x))
x += 1
I've written a function, isprime(n), that returns True if a number is prime and false if not.
I am able to loop the function a defined number of times; but I can't figure out how to iterate until it finds x number of primes. I feel as though I have a decent understanding of For and While loops, but am confused as to how one integrates boolean return values into loops. Here is my current code and error:
Error result:
input:100
Traceback (most recent call last):
File "euler7.py", line 25, in <module>
primeList += 1
TypeError: 'int' object is not iterable
And the code:
def isprime(n):
x = 2
while x < sqrt(n):
if n % x == 0:
return False
else:
x += 1
return True
userinput = int(raw_input('input:'))
primeList = []
primesFound = 0
while primesFound != userinput:
i = 2
if isprime(i):
primeList.append(i)
primeList += 1
i += 1
else:
i += 1
EDIT (including the updated and functioning code):
from math import sqrt
def isprime(n):
x = 2
while x < (sqrt(n) + 1):
if n % x == 0:
return False
else:
x += 1
return True
userinput = int(raw_input('input:'))
primeList = []
primeList.append(2)
i = 2
while len(primeList) != userinput:
if isprime(i):
primeList.append(i)
i += 1
else:
i += 1
print 'result:', primeList[-1]
This line:
primeList += 1
Should be:
primesFound += 1
You cannot add and int to a python list. You should do primesFound += 1 to achieve your desired result.
Plus, your isprime function is wrong. It will return True for 9. You should do while x < sqrt(n) + 1 for the while loop of your isprime function.
So you should have:
def isprime(n):
x=2
while x < sqrt(n) +1:
if n % x == 0:
return False
else:
x += 1
return True
As others have pointed out:
You should increment primesFound, not primeList.
The isprime() function has a bug -- and returns True for 9. You need sqrt(n) + 1.
In addition:
You need to initialize i outside the while loop; otherwise, you simply build up a list of 2's.
There is no need for primesFound. Just check len(primeList).
And my pet peeve:
Command-line programs should resort to interactive user input only in special circumstances. Where possible, take parameters as command-line arguments or options. For example: userinput = int(sys.argv[1]).
To get n numbers that satisfy some condition, you could use itertools.islice() function and a generator expression:
from itertools import count, islice
n = int(raw_input('number of primes:'))
primes = list(islice((p for p in count(2) if isprime(p)), n))
where (p for p in count(2) if isprime(p)) is a generator expression that produces prime numbers indefinitely (it could also be written as itertools.ifilter(isprime, count(2))).
You could use Sieve of Eratosthenes algorithm, to get a more efficient solution:
def primes_upto(limit):
"""Yield prime numbers less than `limit`."""
isprime = [True] * limit
for n in xrange(2, limit):
if isprime[n]:
yield n
for m in xrange(n*n, limit, n): # mark multiples of n as composites
isprime[m] = False
print list(primes_upto(60))
# -> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
See Fastest way to list all primes below N in python.
Note: there are about limit / (log(limit) - 1) prime numbers less than limit.
You could also use an infinite prime number generator such as gen_primes(), to get the first n primes numbers:
primes = list(islice(gen_primes(), n))
See How to implement an efficient infinite generator of prime numbers in Python?
def is_prime(n):
x=2
while x < sqrt(n) +1:
if n % x == 0:
return False
break
else:
x += 1
return True