Please could you help correct this code! It's for finding all perfect numbers below the set limit of 10,000, I've used comments to explain what I'm doing. Thanks!
#Stores list of factors and first perfect number
facs = []
x = 1
#Defines function for finding factors
def findfactors(num):
#Creates for loop to find all factors of num
for i in range(1, num + 1):
if num % i == 0:
#Stores factor in facs
facs.append(i)
#Activates loop
while x < 10000:
#Finds factors of x and appends them to list
findfactors(x)
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x += 1
else:
#Increases x
x += 1
In number theory, a perfect number is a positive integer that is equal
to the sum of its proper positive divisors, that is, the sum of its
positive divisors excluding the number itself (also known as its
aliquot sum). The first perfect number is 6. The next perfect number
is 28. This is followed by the perfect numbers 496 and 8128.
(Wikipedia)
You have to exclude the number itself from the factors list.
Also, for each x you have to start with the empty facs and then append to it. You don't want previous numbers factors in that list. The following code works.
x = 1
def findfactors(num):
facs = []
for i in range(1, num):
if num % i == 0:
facs.append(i)
return facs
while x < 10000:
facs = findfactors(x)
facsum = sum(facs)
if facsum == x:
print(x)
x += 1
else:
x += 1
This is a simpler implementation of your logic.
x = 1
#Defines function for finding factors
def isperfectnum(num):
sum=0
#Creates for loop to find all factors of num
for i in range(1, num ):
if num % i == 0:
sum=sum+i
if sum==num:
return TRUE
else
return FALSE
#Activates loop
while x < 10000:
#Finds perfect numbers
if isperfectnum(x):
print(x)
x=x+1
Found the problem!
Should have been:
for i in range(1, num - 1)
Rather than:
for i in range(1, num + 1)
Thanks to all contributors!
intialize list inside the def and return and the range should not include the original num so range would be from 1 to num which includes 1 but excludes orginal num so it will generate range from 1 to num-1
#Stores list of factors and first perfect number
x = 1
#Defines function for finding factors
def findfactors(num):
facs = []
for i in range(1, num):
if num % i == 0:
#Stores factor in facs
facs.append(i)
return facs
#Activates loop
while x < 1000:
#Finds factors of x and appends them to list
facs=findfactors(x)
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x+= 1
Much faster than generating list
Approach from What is the most efficient way of finding all the factors of a number in Python?
#Stores list of factors and first perfect number
x = 1
#Defines function for finding factors
from functools import reduce
def factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
#Activates loop
while x < 10000:
#Finds factors of x and appends them to list
facs=factors(x)
facs.remove(x) # remove original number as it is not required further
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x+= 1
Related
I want to find all the PRIME numbers up to the given number, and add them to their lists respectively.
The number '100', has 25 primes, whereas I get 1060. What am I doing wrong?
!pip install sympy
import sympy
def count_primes(num):
primes = 0
nonprimes = 0
for x in range(0, num):
if sympy.isprime(x) == True:
primes = primes + x
else:
nonprimes = nonprimes + x
return primes
It seems like your are mixing the listing of primes and the counting.
You can either add all the primes and nonprimes to a list by defining
primes, nonprimes = [],[]
and keep everything else the same. This will just return the list of primes.
If you want to count the primes from 0 to 100, you can change the code in your if and else statement to
primes+=1
and
nonprimes +=1
and you will return the number of primes between 0 and 100.
instead of increasing of "primes" value by 1 you add "x" in "primes" when number is prime
You could this sympy.primerange() function to get a list of all prime numbers and use len() to get total number of primes for that number
def count_primes(num):
primes = list(sympy.primerange(0, num))
length = len(primes)
return length
print(count_primes(100)) #25
The problem lies within this:
if sympy.isprime(x) == True:
primes = primes + x
else:
nonprimes = nonprimes + x
Above, when you are doing primes = primes + x what you are saying is that you want to add the value of the x (a prime number) to the variable primes.
Thus what is happening, when you use 100 as your num your function will return 1060, as this is the sum of all the primes up to 100.
First, if you want to know the total amount of prime numbers up to a certain number, you can use the following:
#define a variable to track the total number of primes
primeTotal = 0
#using the if statement from before
if sympy.isprime(x) == True:
primeTotal += 1
What this does now, is for every instance of a prime number, you will add 1 to the count of prime numbers.
To create a list of prime numbers, you must first define a list, and then add the prime numbers to that list. Again, using the if statement from before:
#defining the list
primeNums = []
if sympy.isprime(x) == True:
primeNums.append(x)
Now what is happening is, for every instance of a prime number x (the prime number) is being added (appended) to the list primeNums. This should solve both your problems.
The final bit of code will look something like this:
import sympy
def count_primes(num):
primesTotal = 0
primeNums = []
for x in range(0, num):
if sympy.isprime(x) == True:
primesTotal += 1
primeNums.append(x)
return primesTotal, primeNums
print(primesTotal, primeNums)
If the number is of the form of a^bc^de^f where a,c and e are prime numbers then total number of factors are (b+1)(d+1)(f+1).
I approached the problem in the following way-
If there are more than or equal to K prime factors of X then it is possible otherwise it is not.
I am getting a TLE error.
We have to print 1 if such a number exists and 0 if not.
import math
T = int(input())
for _ in range(0,T):
flag = 0
X,K = map(int,input().split())
if K == 0:
if X == 1:
print(1)
else:
print(0)
elif K == 1:
if X >= 2:
print(1)
else:
print(0)
elif K>=2:
if X >= 2**K:
count = 0
while ((X % 2 > 0) == False):
X >>= 1
count += 1
K = K-1
#if (count > 0):
# count1 = count
for i in range(3, int(math.sqrt(X)) + 1):
while (X % i == 0):
X = int(X / i)
K = K-1
#if (count > count1):
# n.append(count)
i += 2
if (X > 2):
K = K-1
if K <= 0:
print(1)
else:
print(0)
else:
print(0) ***
The constraints are-
T<= 10^3
X,K <= 10^9
Any way to reduce the runtime?
You can use a simpler recursive function with a Counter object to determine if there are at least K prime factors forming X.
This function will not only give you the list of prime factors but will also provide a count (power) of each prime. The sum of these counts is the maximum number of factors of X.
from collections import Counter
def primeFactors(N):
for f in range(1,int(N**0.5)+1,2): # stepping by 2 gives a 30% speed-up
if f==1: f=2
if N%f==0:
return Counter([f]) + primeFactors(N//f)
return Counter([N])
X = 368640000
K = 21
result = 1 if sum(primeFactors(X).values())>=K else 0
print(result) # 1
This runs in 0.16 seconds for 1000 random test cases on my laptop. The worst case scenario takes 1.06 seconds if all 1000 test cases have X=999999937 (largest prime below 10^9)
[EDIT] here is a variant of the solution using a simple dictionary. It is a bit more code but has the same performance as with the counter object
def primeFactors(N):
for f in range(1,int(N**0.5)+1,2):
if f==1: f = 2
if N%f==0:
result = primeFactors(N//f)
result[f] = result.get(f,0)+1
return result
return {N:1}
[EDIT2] Here is an optimized version of your original code.
These are the optimizations I did:
Removed unnecessary logic and conditions (e.g. X>=2**K)
Fixed the 2 by 2 stepping range that didn't work (having i+=2 inside the loop does not make it step by 2).
Made the factor loop break when the squared factor (i) went beyond the remaining X (instead of always looping all the way to the square root of the original X).
Also broke the loop when the K target is reached.
Removed the special code to process prime=2.
Made sure to use only integer arithmetic (// instead of /)
Eliminated the square root calculation (using i x i < X to break the loop).
...
def OP(X,K):
if K == 0: return int(X==1)
if K == 1: return int(X>=2)
for i in range(1,X,2): # stride by two until break
if i==1: i=2 # handle first prime (2)
while not X % i: # reduce X and K for prime factors
X //= i # X becomes other factor in X = i * X'
K -= 1 # one less prime factor to find
if K<1 or i*i>X:
break # break when max prime reached (or K primes)
return int(K<=0)
With these changes, the calculation perform almost as fast as the primeFactors() function (roughly 50% slower).
My teacher wants me to find the median of 10 inputs from the user by using iterations.
This is how I used iterations to find the sum, number of odd numbers, the max, and the number of prime numbers. But I'm stuck on finding the median.
def Main(): #main function
sum=0
odd=0
temp=0
prime=0
median=0
for i in range(10):
x=float(input("Please enter a number")) #ask user for input 10 times
sum=sum+x #adds all inputs together
if x%2!=0: #all even numbers are divisible by 2
odd=odd+1
if x>=temp: #update temp with current largest input
temp=x
for p in range (2,int(math.sqrt(x))+1):#find prime numbers
if x>=2 and x%p==0: prime=prime+1
import math
def Main(): #main function
sum=0
odd=0
temp=0
prime=0
median=0
my_list =[]
for i in range(10):
x=float(input("Please enter a number: ")) #ask user for input 10 times
sum=sum+x #adds all inputs together
if x%2!=0: #all even numbers are divisible by 2
odd=odd+1
if x>=temp: #update temp with current largest input
temp=x
for p in range (2,int(math.sqrt(x))+1):#find prime numbers
if x>=2 and x%p==0: prime=prime+1
my_list.append(x)
my_list.sort()
size =len(my_list)
if size == 1:
median = my_list[0]
elif size % 2 == 0:
size = int(size/2)
median=(my_list[size-1]+my_list[size])/2
else:
median = my_list[int(size / 2)]
print("sum is ", sum, ",odd is ", odd, ",temp is ", temp, ",prime is ", prime, "median is ", median)
Main()
First of all, as a user pointed out in a comment to your question, your method to determine prime numbers is not correct. You only should increase that counter after all factors have been checked, not after each one.
There are a few questions on StackOverflow that show how to calculate primes in python; here is a slightly improved version of your code with that error fixed (and some style improvement suggestions):
def main():
sum = 0
counter_odd = 0
max_num = None
min_num = None
counter_prime = 0
median = 0
for i in range(10):
x = float(input("Please enter a number"))
sum += x
if x % 2 != 0:
counter_odd += 1
if max_num is None or max_num < x:
max_num = x
if min_num is None or min_num > x:
min_num = x
if x == 0 or x == 1:
counter_prime += 1
elif x > 1:
if not any(x % d == 0 for d in range(2, int(math.sqrt(x)) + 1)):
counter_prime += 1
As to your main question: there are several questions on SO about finding medians in unsorted lists (that would be very similar to searching for medians without having the whole list at the beginning). Maybe search for that without the Python tag, so you get to see some algorithms without tying to a specific language.
For example, in this question you can find the suggestion to use the median of medians approach (Wikipedia).
SPOILER ALERT! THIS MAY INFLUENCE YOUR ANSWER TO PROJECT EULER #3
I managed to get a working piece of code but it takes forever to compute the solution because of the large number I am analyzing.
I guess brute force is not the right way...
Any help in making this code more efficient?
# What is the largest prime factor of the number 600851475143
# Set variables
number = 600851475143
primeList = []
primeFactorList = []
# Make list of prime numbers < 'number'
for x in range(2, number+1):
isPrime = True
# Don't calculate for more than the sqrt of number for efficiency
for y in range(2, int(x**0.5)+1):
if x % y == 0:
isPrime = False
break
if isPrime:
primeList.append(x)
# Iterate over primeList to check for prime factors of 'number'
for i in primeList:
if number % i == 0:
primeFactorList.append(i)
# Print largest prime factor of 'number'
print(max(primeFactorList))
I'll first just address some basic problems in the particular algorithm you attempted:
You don't need to pre-generate the primes. Generate them on the fly as you need them - and you'll also see that you were generating way more primes than you need (you only need to try the primes up to sqrt(600851475143))
# What is the largest prime factor of the number 600851475143
# Set variables
number = 600851475143
primeList = []
primeFactorList = []
def primeList():
# Make list of prime numbers < 'number'
for x in range(2, number+1):
isPrime = True
# Don't calculate for more than the sqrt of number for efficiency
for y in range(2, int(x**0.5)+1):
if x % y == 0:
isPrime = False
break
if isPrime:
yield x
# Iterate over primeList to check for prime factors of 'number'
for i in primeList():
if i > number**0.5:
break
if number % i == 0:
primeFactorList.append(i)
# Print largest prime factor of 'number'
print(max(primeFactorList))
By using a generator (see the yield?) PrimeList() could even just return prime numbers forever by changing it to:
def primeList():
x = 2
while True:
isPrime = True
# Don't calculate for more than the sqrt of number for efficiency
for y in range(2, int(x**0.5)+1):
if x % y == 0:
isPrime = False
break
if isPrime:
yield x
x += 1
Although I can't help but optimize it slightly to skip over even numbers greater than 2:
def primeList():
yield 2
x = 3
while True:
isPrime = True
# Don't calculate for more than the sqrt of number for efficiency
for y in range(2, int(x**0.5)+1):
if x % y == 0:
isPrime = False
break
if isPrime:
yield x
x += 2
If you abandon your initial idea of enumerating the primes and trying them one at a time against number, there is an alternative: Instead deal directly with number and factor it out -- i.e., doing what botengboteng suggests and breaking down the number directly.
This will be much faster because we're now checking far fewer numbers:
number = 600851475143
def factors(num):
factors = []
if num % 2 == 0:
factors.append(2)
while num % 2 == 0:
num = num // 2
for f in range(3, int(num**0.5)+1, 2):
if num % f == 0:
factors.append(f)
while num % f == 0:
num = num // f
# Don't keep going if we're dividing by potential factors
# bigger than what is left.
if f > num:
break
if num > 1:
factors.append(num)
return factors
# grab last factor for maximum.
print(factors(number)[-1])
You can use user defined function such as
def isprime(n):
if n < 2:
return False
for i in range(2,(n**0.5)+1):
if n % i == 0:
return False
return True
it will return boolean values. You can use this function for verifying prime factors.
OR
you can continuously divide the number by 2 first
n = 600851475143
while n % 2 == 0:
print(2),
n = n / 2
n has to be odd now skip 2 in for loop, then print every divisor
for i in range(3,n**0.5+1,2):
while n % i== 0:
print(i)
n = n / i
at this point, n will be equal to 1 UNLESS n is a prime. So
if n > 1:
print(n)
to print itself as the prime factor.
Have fun exploring
First calculate the sqrt of your number as you've done.
number = 600851475143
number_sqrt = (number**0.5)+1
Then in your outermost loop only search for the prime numbers with a value less than the sqrt root of your number. You will not need any prime number greater than that. (You can infer any greater based on your list).
for x in range(2, number_sqrt+1):
To infer the greatest factor just divide your number by the items in the factor list including any combinations between them and determine if the resultant is or is not a prime.
No need to recalculate your list of prime numbers. But do define a function for determining if a number is prime or not.
I hope I was clear. Good Luck. Very interesting question.
I made this code, everything is explained if you have questions feel free to comment it
def max_prime_divisor_of(n):
for p in range(2, n+1)[::-1]: #We try to find the max prime who divides it, so start descending
if n%p is not 0: #If it doesn't divide it does not matter if its prime, so skip it
continue
for i in range(3, int(p**0.5)+1, 2): #Iterate over odd numbers
if p%i is 0:
break #If is not prime, skip it
if p%2 is 0: #If its multiple of 2, skip it
break
else: #If it didn't break it, is prime and divide our number, we got it
return p #return it
continue #If it broke, means is not prime, instead is just a non-prime divisor, skip it
If you don't know: What it does in range(2, n+1)[::-1] is the same as reversed(range(2, n+1)) so it means that instead of starting with 2, it starts with n because we are searching the max prime. (Basically it reverses the list to start that way)
Edit 1: This code runs faster the more divisor it has, otherwise is incredibly slow, for general purposes use the code above
def max_prime_divisor_of(n): #Decompose by its divisor
while True:
try:
n = next(n//p for p in range(2, n) if n%p is 0) #Decompose with the first divisor that we find and repeat
except StopIteration: #If the number doesn't have a divisor different from itself and 1, means its prime
return n
If you don't know: What it does in next(n//p for p in range(2, n) if n%p is 0) is that gets the first number who is divisor of n
I'm having trouble with my code. The question is:
"By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. What is the 10 001st prime number?"
This is what it looks like:
div = 10001
i = 2
count = 0
prime = 0
now = []
while count < div:
for x in range (2,i+1):
if len(now) ==2:
break
elif i%x == 0:
now.append(x)
if len(now)==1:
prime = i
count += 1
now = []
i+=1
print(prime)
I have tried div up to 1000 and it seems to work fine(for div 1000 I receive 7919). However, when I try div = 10001 I get nothing, not even errors. If someone would help me out I would really appreciate it.
Thank you.
# 7 10001st prime
import itertools
def is_prime(n):
for i in range(2, n//2 + 1):
if n % i == 0:
return False
else:
continue
return True
p = 0
for x in itertools.count(1):
if is_prime(x):
if p == 10001:
print(x)
break
p += 1
Try this code:
prime_list = lambda x:[i for i in xrange(2, x+1) if all([i%x for x in xrange(2, int(i**0.5+1))])][10000]
print prime_list(120000)
Lambda in Python defines an anonymous function and xrange is similar to range, defining a range of integer numbers. The code uses list comprehension and goes through the numbers twice up to the square root of the final number (thus i**0.5). Each number gets eliminated if it is a multiple of the number that's in the range count. You are left with a list of prime numbers in order. So, you just have to print out the number with the right index.
With just some simple modifications (and simplifications) to your code, you can compute the number you're looking for in 1/3 of a second. First, we only check up to the square root as #Hashman suggests. Next, we only test and divide by odd numbers, dealing with 2 as a special case up front. Finally, we toss the whole now array length logic and simply take advantage of Python's break logic:
limit = 10001
i = 3
count = 1
prime = 2
while count < limit:
for x in range(3, int(i ** 0.5) + 1, 2):
if i % x == 0:
break
else: # no break
prime = i
count += 1
i += 2
print(prime)
As before, this gives us 7919 for a limit of 1000 and it gives us 104743 for a limit of 10001. But this still is not as fast as a sieve.
m=0
n=None
s=1
while s<=10001:
for i in range(1,m):
if m%i==0:n=i
if n==1:print(m,'is prime',s);s+=1
m+=1