Calculating Polygonal Numbers Taking A While To Calculate - python

I've created a function which, hopefully, creates a list of numbers that are both pentagonal and square.
Here is what i've got so far:
def sqpent(n):
i = 0
list = []
while n >= 0:
if n == 0:
list.append(0)
elif n == 1:
list.append(1)
elif (i*i == (i*(3*i-1)//2)):
list.append(i)
n -= 1
i += 1
But when it gets past the first two numbers it seems to be taking a while to do so...

You have two issues: the first is that the special-casing for n==0 and n==1 doesn't decrease n, so it goes into an infinite loop. The special-casing isn't really needed and can be dropped.
The second, and more significant one, is that in the test i*i == (i*(3*i-1)//2) you are assuming that the index i will be the same for the square and pentagonal number. But this will only happen for i==0 and i==1, so you won't find values past that.
I suggest:
Iterate over i instead of n to make things simpler.
Take the ith pentagonal number and check if it is a square number (e.g. int(sqrt(x))**2 == x).
Stop when you've reached n numbers.

Thanks to #interjay's advice, I came up with this answer which works perfectly:
import math
def sqpent(n):
counter = 0
i = 0
l = []
while counter < n:
x = (i*(3*i-1)//2)
#print(x)
if(int(math.sqrt(x))**2 == x):
#print("APPENDED: " + str(x))
l.append(x)
counter += 1
i += 1
return l
For an explanation:
It iterates through a value i, and gets the ith pentagonal number. Then it checks if it is a square and if so it appends it to a list which i ultimately return.
It does this until a final point when the counter reaches the number of items in the list you want.

Related

python - finding circular prime number

I am trying trying to find the number of circular primes from a given limit. The prime(x) will return whether a number is a prime or not. The rotations() will return a list of rotated numbers. Lastly, prime_count() will output the total amount of circular primes based on the given limit. Both prime() and rotations() gave me the correct output; however, prime_count() is not incrementing like it should. Any ideas on what i did wrong?
def prime(number): #return true or false
return all(number% i for i in range(2,number))
def rotations(num): #rotating number and return list
list = []
m = str(num)
counter = 0
while counter < len(str(num)):
m=m[1:] + m[0]
list.append(int(m))
counter+=1
list1=sorted(list,key=int)
return list1
def prime_count(limit): #return numbers of circular primes from given limit
counter = 0
for i in range(1,limit+1):
a=rotations(i)
for j in a:
if j == prime(j):
counter+=1
return counter
print(prime_count(100))
There are a few problems with your code:
Your prime function has a bug:
In [8]: prime(1)
Out[8]: True
It erroneously returns True for any number less than 2 due to range(2, n) being empty and any([]) == True.
prime_count should be counting the total number of circular primes below limit. prime(j) returns a boolean, but you check j == prime(j), which can only be true if j is zero or one, which definitely isn't what you want. Try creating an is_circular_prime function that takes in an integer n and returns whether or not the prime is circular. Then, prime_count becomes easy to write.
This is the heart of the problem:
a=rotations(i)
for j in a:
if j == prime(j):
counter+=1
You're counting the wrong thing (e.g. 13 counts twice independent of 31 counting twice) and you're comparing the wrong thing (numbers against booleans.) The problem is simpler than you're making it. Rearranging your code:
def prime(number):
return number > 1 and all(number % i != 0 for i in range(2, number))
def rotations(num):
rotated = []
m = str(num)
for _ in m:
rotated.append(int(m))
m = m[1:] + m[0]
return rotated
def prime_count(limit):
counter = 0
for number in range(1, limit + 1):
if all(prime(rotation) for rotation in rotations(number)):
counter += 1
return counter
print(prime_count(100))
Note that you don't need to sort the rotations for this purpose. Also list, or any other Python built-in function, is a bad name for a variable.
Problem may be here:
for i in range(1,limit+1):
a=rotations(i)
for j in a:
if j == prime(j): # Prime will return True or False, comapring with J will cause it False ,except when J = 1
counter+=1
Changing it to prime(j)
for i in range(2,number//2):
if(number%i==0):
return False
return True
def rotations(num):
count=0
rotation_lst=[]
num=str(num)
while(count<len(num)):
num=num[1:]+num[0]
count+=1
rotation_lst.append(int(num))
rotation_lst1=sorted(rotation_lst,key=int)
return rotation_lst1
def get_circular_prime_count(limit):
count=0
for i in range(1,limit+1):
a=rotations(i)
for j in a:
if(check_prime(j)):
count+=1
return count
print(get_circular_prime_count(1000) ```

Python 3: List of over 100 indices cycles back around after index 47. why? how do I stop this?

so this is a function that gets the nth prime number. I know its been done before and that my method may not be very efficient (new coder btw minor dabbling in the past).
Anyway the code below works and returns the prime number of the supplied index.
ie:
ind = 4
final[1,2,3,5,7,11]
return final[ind-1]
returns: 5
But final[51-1] returns whats in final[3-1]. Seems like after index 47 it loops back around and starts over. Ive printed the whole of the list contained in final. and it prints every prime, even those past 47. Im not sure whats going on. Is there some limit to lists in python?
Here is the code:
def nthPrime(ind): #gets nth prime number. IE: 5th prime == 11. works based off very in-efficient version of Sieve of Eratosthenes. but in increments of 200
p = {}
T = 2
incST = 2
incEND = incST + 200
final=[1]
while len(final) < ind:
for i in range(incST,incEND):
p[i] = True
while T <= math.sqrt(incEND):
l = 0
while l <= incEND:
p[T**2 + (T*l)] = False
l+=1
if T**2+(T*l) > incEND:
break
for k,v in p.items():
if p[k] == True and k > T:
T = int(k)
break
for k in p:
if p[k] == True:
final.append(k)
incST = incEND + 1
incEND = incST + 200
'''
currently function works perfectly for
any index under 48.
at index 48 and above it seems to start
back at index 1.
IE: final[51]
^would actually return final[4]
'''
return final[ind-1]
You need to count how many primes you have in your list, but you accumulate in final within the loop, so you add all the numbers up to the limit several times in the loop. Starts at 2 again after 199.
Also, using dictionaries and relying on the order is dangerous. You should sort them when iterating.
My solution only counts the primes to know when to end the loop, and compose the list just in the end, omitting 1 and shifting the index by 1.
I also sort the dictionary when iterating over it to make sure:
import math
def nthPrime(ind): #gets nth prime number. IE: 5th prime == 11. works based off very in-efficient version of Sieve of Eratosthenes. but in increments of 200
p = {}
T = 2
incST = 2
incEND = incST + 200
lenfinal = 1
while lenfinal < ind:
for i in range(incST,incEND):
p[i] = True
while T <= math.sqrt(incEND):
l = 0
while l <= incEND:
p[T**2 + (T*l)] = False
l+=1
if T**2+(T*l) > incEND:
break
for k,v in sorted(p.items()):
if v and k > T:
T = int(k)
break
incST = incEND + 1
incEND = incST + 200
# compute length, no need to order or to actually create the list
lenfinal = sum(1 for k,v in p.items() if v)
# now compose the list
final = [k for k,v in sorted(p.items()) if v]
return final[ind-2]
A more efficient way to do this would be a recursive function:
I'll put some explanation in the code.
def nthPrime(ind):
first_prime=1 #first prime number
number = 1 # all numbers that we will check, this will be incremented
prime_numbers = [first_prime] # The list of prime numbers we will find
def findPrimeInPosition(ind, number):
if ind > len(prime_numbers): # This recursive function will exit if find a sufficient number of primes
number+=1 # incrementing to check the next number
is_prime = True # Assuming number is a prime
for p in prime_numbers[1:]: # Check if it is a prime
if not number % p:
is_prime = False
if is_prime:
prime_numbers.append(number) # Add to the list of primes
findPrimeInPosition(ind, number)
return prime_numbers[-1] # Get the last element found
return findPrimeInPosition(ind, number)
Example of usage:
print nthPrime(47)
>> 199
print nthPrime(48)
>> 211
This isn't a Python issue, the problem is in your calculation on how you calculate the results. When you do final[51] it actually returns the value that holds that position, do this:
# Modify your line
# return final[ind-1]
# return final
# Call your method
o_final = nthPrime(100)
for k in range(len(o_final)):
print(k, y[k])
Then you realize that at pos 93 you reach the next one and keep incrementing.

How to create a piece of code which checks a number for its greatest prime factor?

I was trying to make a program which would check a number for its greatest prime factor. I was almost done when this error message came up. list index out of range.
What does this mean and what is wrong with my code?
Here is my code.
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n = n + 1
for i in z:
if is_prime(z[i]) == True:
prime.append(z[i])
else:
not_a_prime.append(z[i])
print(prime)
Problem3()
You're just a bit off. for-loops in Python iterate an object and return it's entities, not a pointer/ index.
So just use the thing you get from each iteration of 'z'
(Side note: might want to check out this post, it'll help you make your is_prime function more performant)
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n =+ 1 # Python version of n++
for i in z: # Python for-loop is more like a say "for each", no need for the indexing
if is_prime(i): # no need for '=='; Python will 'truthify' your object
prime.append(i)
else:
not_a_prime.append(i)
print(prime)
Problem3()
"list index out of range - what does this mean?"
The message list index out of range refers to an IndexError. Basically, this means that you are attempting to refer to an index in a list that doesn't exist.
Using your code as an example: you generate a list, z, containing the factors of the number 144. You then iterate through each element in this list (for i in z:). This means that for the:
1st iteration: i is the 1st element in z, which is 2;
2nd iteration: i is the 2nd element in z, which is 3;
and so on.
Then, you attempt if isprime(z[i]) == True:. So, as written, your program works like this:
1st iteration: if isprime(z[2]) == True:;
2nd iteration: if isprime(z[3]) == True:;
...
8th iteration: if isprime(z[16]) == True:
At this point, your code prompts an IndexError, because there are only 13 elements in z.
"what is wrong with my code?"
One way to get the result that you want is to iterate through range(len(z)) instead of each element of z. So, adjust the line for i in z to for i in range(len(z)).
Additionally, since prime is a list, and you want to return the greatest prime factor, change print(prime) to print(max(prime)).
These two changes will give you the result you are looking for.
Additional Learnings
Overall, your program could be written much more efficiently. If you want a simple algorithm to determine the greatest prime factor of a number, here is one possibility:
def greatest_prime_factor(n):
greatest_prime = 1
for i in range(n + 1):
# iterate through range(n). We skip index 0.
if i == 0:
continue
# determine if the number i is a factor of n.
if n % i == 0:
# determine if the number i is prime.
for i_ in range(2,i):
if i % i_ == 0:
break
else:
# update greatest_prime.
greatest_prime = max(greatest_prime, i)
return greatest_prime
print (greatest_prime_factor(144))
This algorithm saves a lot of memory space when compared with your original program by not initializing lists to store numbers that are primes, that aren't primes, etc. If you want to store those values, that's up to you; there are just far more efficient possibilities for what you appear to want to achieve.
Check this link for some more info on algorithmic efficiency and how to think about time and space complexity.

Amicable Numbers

I am struggling with optimizing these functions that I have used to calculate the sum of the amicable pairs under 10000. An amicable pair is a pair (a, b) where the sum of the divisors of "a" excluding "a" itself equals b and the sum of the divisors of "b" excluding "b" itself equals "a".
I.e. divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110: The sum of which is 284. And the sum of the divisors of 284 (1, 2, 4, 71 and 142) equals 220.
My code is:
import math
def Divisorsbaritself(x):
divList = [1]
y = 2
while y <= math.sqrt(x):
if x % y == 0:
divList.append(y)
divList.append(int(x / y))
y += 1
return sum(divList)
def amicable():
solution = []
for i in range(10000):
if Divisorsbaritself(Divisorsbaritself(i)) == i:
solution.append(i)
return sum(solution)
print amicable()
I need help with understanding why the amicable function is not working. To me it makes logical sense that the if Divisorsbaritself(Divisorsbaritself(i)) == i: condition is the right condition to include i in the list, but it is giving me 40285, rather than 31626, the answer.
If Divisorsbaritself(i)==i you shouldn't count i.
def amicable():
solution = []
for i in range(10000):
if Divisorsbaritself(i)!=i and Divisorsbaritself(Divisorsbaritself(i)) == i:
solution.append(i)
return sum(solution)
But you should also fix the bug that would be an issue if i is a perfect square and in an amicable pair.
You can improve this with list comprehensions.
def amicable():
solution = [i for i in xrange(10000) if Divisorsbaritself(i)!=i and Divisorsbaritself(Divisorsbaritself(i)) == i]
return sum(solution)
They're amicable numbers only if they're different. So if divsum(i) is equal to i, then that's not included, despite the fact that means that divsum(divsum(i)) also equals i.
In addition, your current check counts the square root of a perfect square twice, even though it's only one factor.
And, on top of that, I wouldn't be using a list then summing it at the end when you can simply use an accumulator. And it's usually faster to do multiplication than square roots so you can change the while loop to take that into account.
Finally, for the love of whatever deities you believe in, comment your code! It'll make it so much easier to understand what's going on, both for others and for yourself six months down the track.
Incorporating those changes gives you the following DivisorsBarItself function:
def DivisorsBarItself(num):
# Maintain sum of factors.
divSum = 1
# Go through every integer up to but excluding sqrt(num).
testnum = 2
while testnum * testnum < num:
# If factor, add it and the complement (guaranteed integer).
if num % testnum == 0:
divSum += testnum + num/testnum
testnum += 1
# If perfect square, add the square root once.
if testnum * testnum == num:
divSum += testnum
# Return the sum.
return divSum
Fixing the logic for detecting amicable numbers and using a sum rather than a list gives you:
def AmicableSum():
# Set sum to zero and process all numbers below 10,000.
solution = 0
for num in range(10000):
# Get the "friend", add only if different and f(f(x)) = x.
numFriend = DivisorsBarItself(num)
if numFriend != num and DivisorsBarItself(numFriend) == num:
solution += num
return solution
print AmicableSum()
which gives the correct result of 31626.
I have fixed the bug now by going:
def Divisorsbaritself(x):
divList = [1]
y = 2
while y <= math.sqrt(x):
if x % y == 0:
if y is not int(x/y):
divList.append(y)
divList.append(int(x / y))
else:
divList.append(y)
y += 1
return sum(divList)
I have written the whole thing you said as a function
def devisor(a):
listOfFactors=[]
for possibleFactor in range(1,a):
if a%x==0:
listOfFactors.append(possibleFactor)
sumOfFactors=0
for item in z:
sumOfFactors+=item
factorsOfNewSumAddedUp=0
for x in range(1,sumOfFactors):
if temp%x==0:
factorsOfNewSumAddedUp+=x
if a==factorsOfNewSumAddedUp:
print("this is a divisor")

given and integer, return the next integer that is a prime number and a palindrome . Python

Given any random integer, create a function to find the next number that is a prime number and also a palindrome.
My attempt
def golf(number):
x = number + 1
for i in range(2, x):
if x % i == 0 or str(x) != str(x)[::-1]:
golf(number + 1)
return x
E.g golf(13) = 101
I'm actually looking for an alternative option than the recursion method i used. How can this best be accomplished without using recursion?
Thanks
Here's a variation on byron he's answer which adds several optimizations:
We can eliminate all even x values (other than 2) before doing any elaborate tests, since we can trivially tell they are not prime.
A small improvement is to only call str(x) once, and reuse the value later.
We can take advantage of the fact that all even-length palindromes are multiples of 11, which means that (except for 11 itself) they're not prime. We can jump ahead to the next odd-length x value.
Since we've already eliminated even numbers, our prime test only needs to test odd divisors. Further we can stop our loop when we reach sqrt(x), rather than going all the way to x itself.
Finally, there's no need to use a Boolean flag variable to carry the primeness out of the loop. If we don't break, the else block attached to the loop will be run.
The code:
import math
def next_prime_palindrome(x):
while True:
x += 1
if x > 2 and x % 2 == 0: # even numbers greater than 2 are non-prime
continue
s = str(x) # compute str(x) just once
if x > 11 and len(s) % 2 == 0: # all even-length palindromes are multiples of 11
x = 10 ** len(s) # so jump to the next odd-length integer
continue
if s != s[::-1]: # palindrome test
continue
for i in xrange(3, round(math.sqrt(x))+1, 2): # loop over odd potential divisors
if x % i == 0: # prime test
break
else: # this else block runs only if no break happened in the loop, so x is prime
return x
Here are some tests runs, showing a few cases where the optimizations save significant time:
>>> next_prime_palindrome(1)
2
>>> next_prime_palindrome(3)
5
>>> next_prime_palindrome(9)
11
>>> next_prime_palindrome(11)
101
>>> next_prime_palindrome(99999)
1003001
>>> next_prime_palindrome(999999999)
10000500001
A further improvement might be to directly generate palindromes, rather than working with integers to start with, and doing a palindrome test to filter them. That would get quite a bit further from your original design, so I'll leave that for someone else.
Palindrome are a sparser set of numbers than primes, and you can generate palindromes directly.
Consider the sequence 98.102
These are palidrome numbers you can base on these
989, 9889, 999, 9999, 10001, 100001, 10101, 101101, 10201, 102201
ADDED
Not also that all of the palidromes with an odd number of digits will come before the palidromes with an even number of digits.
If you write this as a generator (ie using yield) get get a straightforward algorithm for generating palindromic numbers in order.
For 1..9 you generate either 9 or 18 palindromes depending upon whether you consider 1 digit numbers palindromic.
For 10..99 you generate 90 even digit and 90 odd digit palindromes.
For 100..999 you generate 900 even digit and 900 odd digit palindromes.
You have just generated all 1989 (or 1997 if including single digit numbers) of the palindromic numbers less than 1 million. There are 78,498 primes less than 1 million
Any algorithm that is based on generating primes then testing for a palindrome will be much slower that generating palindromes and then testing for primes
def golf(number):
primes = []
i = 2
while i <= number:
if isPrime(i, primes):
primes.append(i)
i += 1
answer = primes[-1] + 1
while True:
if isPrime(answer, primes):
primes.append(answer)
if str(answer) == str(answer)[::-1]:
return answer
answer += 1
def isPrime(n, primes):
for (p for p in primes if p<=n**0.5):
if n%p == 0:
return False
return True
Your solution can be slightly modified in order to create an iterative solution:
def golf(number):
x = number + 1
while True:
is_golf = True
for i in range(2, x):
if x % i == 0 or str(x) != str(x)[::-1]:
is_golf = False
break
if is_golf:
return x
x += 1
improved according to Blckknght's advice, thanks.
def golf(number):
x = number
while True:
x += 1
if str(x) != str(x)[::-1]:
continue
for i in xrange(2, x):
if x % i == 0 :
break
else:
return x

Categories

Resources