Writing a program that finds perfect numbers - error - python

I'm working on a program that finds perfect numbers (i.e., 6, because its factors, 1, 2, and 3, add up to itself). My code is
k=2
mprim = []
mprimk = []
pnum = []
def isprime(n):
"""Returns True if n is prime."""
if n == 2:
return True
if n == 3:
return True
if n % 2 == 0:
return False
if n % 3 == 0:
return False
i = 5
w = 2
while i * i <= n:
if n % i == 0:
return False
i += w
w = 6 - w
return True
def mprime(k):
while k < 50:
check = (2**k)-1
if isprime(check) == True:
mprim.append(check)
mprimk.append(k)
print check
k+=1
else:
k+=1
mprime(k)
def isperf(lst):
for i in lst:
prm = (((2**i)-1)(2**i))/(2)
pnum.append(prm)
isperf(mprimk)
print pnum
The first part, that checks if a number is prime, and produces mercenne primes, is working alright. Its the second part I'm having trouble with. I have read that if 2^k - 1 is prime, then ((2^k - 1)(2^k))/2 is a perfect number, so I am using that formula.
The error it gives is
Traceback (most recent call last):
File "python", line 47, in <module>
File "python", line 44, in isperf
TypeError: 'int' object is not callable
Line 47 is isperf(mprimk) and line 44 is prm = (((2**i)-1)(2**i))/(2). Any assistance would be appreciated.
Thanks!

The error clearly states that you are trying to call an int type, which isn't callable.
In practice it means you trying to do something like 123()
And code responsible for it is ((2**i)-1)(2**i) because you forgot * and it should be (((2**i)-1)*(2**i))/(2)

Related

i want to create a factorial function in python such that it returns N

According to my code which is
def factorial(n):
if n == 0:
return 1
else:
N = 1
for i in range(1, n+1):
if i==1*2*3*...*N:
return(N)
it did not produce n error when i tested with the value zero it give one but with other number i.e 7 it gave this error
TypeError Traceback (most recent call last)
<ipython-input-167-5e0569aed165> in <module>
----> 1 factorial(7)
<ipython-input-166-cef7895a4a43> in factorial(n)
5 N = 1
6 for i in range(1, n+1):
----> 7 if i==1*2*3*...*N:
8 return(N)
TypeError: unsupported operand type(s) for *: 'int' and 'ellipsis'
and the line 7 is the problem
Perhaps something like this would be good?
#!/usr/local/cpython-3.8/bin/python3
import itertools
def factorials_forever():
n = 1
for factor in itertools.count(2):
yield n
n *= factor
def find_which_n(n):
for factorialno, factorial in enumerate(factorials_forever(), start=1):
if factorial > n:
raise ValueError('input not a valid factorial')
if factorial == n:
return factorialno
def main():
# for fact in zip(range(10), factorials_forever()):
# print(fact)
nth = find_which_n(3628800)
print(nth)
main()
HTH.
def factorial(n):
if n == 0:
return 1
else:
N = 1
for i in range(1, n+1):
N *= i
return(N)
so this is the ans you can try it

Estimating in Python

I am trying to write a python function which will give me back the first value of a number k which will function 2 >= function 1
function 1(p) => 1 + 1/1! + 1/2! + 1/p!
function 2(k) => (1 + 1/k)^k
So I input use 2 for example in function 1. It would take estimate e at 2.5 but it would take k being 6 for it to get close which is 2.522.
I want to return the 6.
I get this far but I am not sure where to go from there.
for x in range(p):
factorial(x):
if x == 0:
return 0
else:
return x * factorial(x-1)
result = 1 + 1/factorial(p)
I think you need two separate functions, and no loops are needed.
def factorial(x):
if x in {0, 1}:
return 1 # This needs to be 1, otherwise you multiply everything by 0
else:
return x * factorial(x-1)
def summ(p):
if p == 0:
return 1
elif p == 1:
return 2
else:
return 1/factorial(p) + summ(p-1)
Regarding the rest of the question, I think this will help
def f2(k):
return 1 if k == 0 else (1 + 1/k)**k
max_iter = 10 # TODO: increase
k = 0
delta = 0.000001
while max_iter > 0:
f1_result = summ(k)
f2_result = f2(k)
check = f1_result <= f2_result
print("k={}: {:6.8f} <= {:6.8f} == {}".format(k, f1_result, f2_result, check))
k += 1
max_iter -= 1
# if check:
# break
# TODO: Check if difference is within acceptable delta value
Output
k=0: 1.00000000 <= 1.00000000 == True
k=1: 2.00000000 <= 2.00000000 == True
k=2: 2.50000000 <= 2.25000000 == False
k=3: 2.66666667 <= 2.37037037 == False
k=4: 2.70833333 <= 2.44140625 == False
k=5: 2.71666667 <= 2.48832000 == False
k=6: 2.71805556 <= 2.52162637 == False
k=7: 2.71825397 <= 2.54649970 == False
k=8: 2.71827877 <= 2.56578451 == False
k=9: 2.71828153 <= 2.58117479 == False
From larger numbers, this check still fails at k=996 and throws a recursion error.
k=996: 2.71828183 <= 2.71691848 == False
Traceback (most recent call last):
File "python", line 22, in <module>
File "python", line 13, in summ
File "python", line 5, in factorial
File "python", line 5, in factorial
File "python", line 5, in factorial
[Previous line repeated 992 more times]
RecursionError: maximum recursion depth exceeded
Therefore, it would help if you wrote a factorial function using a loop rather than recursion.
Edit
I think I understand what you are trying to get now
in1 = int(input("value 1:"))
v1 = summ(in1)
v2 = 0
max_iter = 50 # Recursion execution limit
while f2(v2) <= v1 and max_iter > 0:
v2 += 1
max_iter -= 1
print(v2)
Output
value 1: <enter 2>
6

Project Euler #37 issue

I tried to solve Project Euler #37:
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
I wrote my code in Python but I am facing weird issues.
Here's my code:
def isPrime(n):
if n == 2 or n == 3 or n == 5: return True
if n < 2 or n%2 == 0: return False
if n < 9: return True
if n%3 == 0: return False
if n%5 == 0: return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0: return False
if n%(f+2) == 0: return False
f +=6
return True
def gen(nb):
results = []
nb_str = str(nb)
for k in range(0, len(nb_str) - 1):
results.append(nb_str[k:])
results.append(nb_str[-k:])
return results
def check(nb):
for t in gen(nb):
if not isPrime(int(t)):
return False
return True
c = 0
s = 0
i = 2
while c != 11:
if check(i):
c += 1
s += i
i += 1
print(s)
Where does the error come from? (The expected result is 748317)
I suspect the errors coming from the results list
Yes, the gen() function is not working correctly as your slicing is off, also, you count 2, 3, 5 and 7 as truncatable primes which the question denies.
The second slice should be the other way around:
>>> s = 'abcd'
>>> for i in range(1,len(s)-1):
... print(s[i:])
... print(s[:-i])
...
bcd
abc
cd
ab
which we can see produces the right strings.
Altogether then, the function should be:
def gen(nb):
results = [nb]
nb_str = str(nb)
for k in range(1, len(nb_str)):
results.append(int(nb_str[k:]))
results.append(int(nb_str[:-k]))
return results
note I also added a string to int conversion - not sure how Python didn't make that obvious for you :/
And before get the full solution, Project Euler nearly always gives you an example which you can use to check your code:
>>> check(3797)
True
You must also add a condition in the check function to return False if the number is 2, 3, 5 or 7 as this is stated clearly in the question.
And the result is the expected: 748317.
Joe Iddon has explained the error in your code, but you can speed it up a little by turning gen into an actual generator. That way, you can stop checking the results for a given nb as soon as you detect a composite number (and gen will stop generating them). I've also made a few minor tweaks to your primality tester. Remember, the or operator short-circuits, so if a is True-ish in a or b then it doesn't bother evaluating b.
def isPrime(n):
if n in {2, 3, 5, 7}:
return True
if n < 2 or n%2 == 0:
return False
if n%3 == 0 or n%5 == 0:
return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0 or n%(f+2) == 0:
return False
f += 6
return True
def gen(nb):
yield nb
nb_str = str(nb)
for k in range(1, len(nb_str)):
yield int(nb_str[k:])
yield int(nb_str[:-k])
def check(nb):
for t in gen(nb):
if not isPrime(t):
return False
return True
c = s = 0
# Don't check single digit primes
i = 11
while c < 11:
if check(i):
c += 1
s += i
print(i)
i += 2
print('sum', s)
output
23
37
53
73
313
317
373
797
3137
3797
739397
sum 748317
In fact, you can get rid of the check function, and replace it with all, which also short-circuits, like or does. So you can replace the
if check(i):
with
if all(map(isPrime, gen(i))):

What is wrong with my code?(python)

Here is my code:
def extractEachKth(inputArray, k):
n = []
for i in inputArray:
n.append(i)
for i in range(1, len(n) + 1):
if i % k == 0:
n.remove(n[i-1])
return (n)
print (extractEachKth([1,2,3,4,5,6,7,8,9,10],3))
and here is my error:
Traceback (most recent call last):
File "C:/Users/Harry/Documents/randompythonprograms/editable.py", line 9, in <module>
print (extractEachKth([1,2,3,4,5,6,7,8,9,10],3))
File "C:/Users/Harry/Documents/randompythonprograms/editable.py", line 7, in extractEachKth
n.remove(n[i-1])
IndexError: list index out of range
This : n.remove(n[i-1]) is causing the problem, since you're removing values from the list and looping till len(n) so it won't have same size i.e, length of the list will reduce and will give you index out of bound error, your range is correct.
You can solve it by updating the N whenever you remove a value, like this :
def extractEachKth(inputArray, k):
n = []
for i in inputArray:
n.append(i)
i = 1
N = len(n) + 1
while i < N:
if i % k == 0:
n.remove(n[i-1])
N = len(n) + 1
# or simply
# N -= 1
i += 1
return (n)
print (extractEachKth([1,2,3,4,5,6,7,8,9,10],3))

Iterating until a function returns True a user defined number of times

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

Categories