How to make a while loop faster in python? - python

I am trying to make a script that figures out the least number divisible by numbers from 1 to 20 without any remainder. Apparently it works well with finding the least number that can be divided from 1 to 10 which is 2520, but for the former problem it takes a lot of time to actually find it because the number is much bigger than 2520 (232792560). So is there anyway to make that process faster, I am totally new to Python by the way. Here is the code I used:
num = 1
oper = 1
while oper <= 20:
y = num % oper
if y == 0:
oper += 1
else:
num += 1
oper = 1
print(num)

from math import gcd
a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
lcm = a[0]
for i in a:
lcm = lcm*i//gcd(lcm, i)
print(lcm)
Your algorithm is quite slow and will not work for quite large numbers efficiently.
This will find the lcm for each number and multiply it to the previous number.

you can do it using numpy:
import numpy as np
arr = np.arange(1,21)
t = np.lcm.reduce(arr)
also see these examples

Related

Find minimal operations such that N will become 1 with 3 operations

We are given N as a natural number and we can do these 3 operations with him.
1)Subtract 1 from N
2)If it is even, divide by 2
3)If it divides 3, then divide by 3
We stop this when N becomes 1. We need to find minimal operations such that N will become 1
#!/bin/python3
import math
import os
import random
import re
import sys
#
# Complete the 'count' function below.
#
# The function is expected to return an INTEGER.
# The function accepts INTEGER num as parameter.
#
def count(num):
count = 0
while num != 1:
if (num % 3 ==0 ):
count += 1
num = num / 3
elif((num -1) % 3 == 0):
count += 2
num = (num - 1) / 3
elif (num % 2 ==0):
count += 1
num = num / 2
else:
num = num - 1
count += 1
return count
This is my code. From 11 test cases it passed 9 and gave 2 wrong answers. I don't know for which test cases my code gives wrong answers. Can you help to understand where is problem?
You make an assumption that it is better to subtract 1 and divide by 3 first if you can, but that isn't always true.
Consider 16
Your solution would be 16-15-5-4-3-1 = 5 steps
Better solution:
16-8-4-2-1 = 4 steps
Probably not the most efficient solution but:
def count(num):
count1, count2 = float('inf'), float('inf')
if num == 1:
return 0
if num % 3 == 0:
count1 = 1 + count(num // 3)
if num % 2 == 0:
count2 = 1 + count(num // 2)
count3 = 1 + count(num - 1)
return min(count1, count2, count3)
These types of problems usually have a small set of rules that produce the optimal answer.
Your fundamental problem, though, is that you are assuming that your rule set is optimal with no evidence whatsoever. You really have no reason to believe that it will produce the right count.
Unfortunately, answers to these kinds of questions on SO sometimes provide the correct rule set, but always seem to omit any kind of proof that the rule set is optimal.
You have to do something that is guaranteed to work, so unless you have that kind of proof, you should fall back on an A* search or similar.
You may use the non-recursive breadth-first strategy.
Say there is a queue holding lists of numbers. Initially, enter a list holding just N into the queue. Then repeat the following until the queue is empty:
Pick the first list in the queue.
Repeat 3 for all three operations.
Select an operation. If possible, apply it to the last list number and add the result to the end of the list. If the list is a solution, store it somewhere. If not, add it to the end of the queue.
This strategy is exhaustive and finds all solutions. Since only the minimum is of interest, we introduce a limiting bound. Once a solution list is available, we do not enter lists longer than that into the queue, nor do we consider them if they are in the queue already.

Finding the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? [duplicate]

This question already has answers here:
Least common multiple for 3 or more numbers
(32 answers)
Closed 5 years ago.
This is a Project Euler challenge where I'm trying to find the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
The logic while I came up with seems to run really slowly. It's been running for the last 4 mins and still hasn't found the number. I'm trying to figure out a) Is this logic correct? b) Why does this take so long? and c) Could someone give me a hint on an alternate logic that is more efficient.
# 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
# What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
smallest_num = 2520
while smallest_num >= 2520:
divisor = 2
while smallest_num % divisor == 0 and divisor < 21:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor += 1
smallest_num += 1
print("Smallest number is: {}").format(smallest_num)
This is still processing and so far my terminal looks like this
Here's your method run "properly" (using the term liberally), but as #James mentioned it will take an egregious amount of time as a loop.
divisors = np.arange(1, 21)
num = 2520
while True:
if np.all(num % divisors == 0):
print(num)
break
num += 1
A much better method (for Python 3.x). Directly from a similar question:
import functools
import math
functools.reduce(lambda x,y: x*y//math.gcd(x, y), range(1, 21))
Out[27]: 232792560
The following code works fine.
#!/usr/bin/env python
import math
#Generating primes
divisorMax = 20;
top = divisorMax + 1 #divisor max is the upper limit
p = [x for x in range(2,top)]
for num in p:
for idx in range(2,(top//num)+1):
if num*idx in p:
p.remove(num*idx)
#Solving the problem
result = 1;
for i in range(0, len(p)):
a = math.floor(math.log(divisorMax) / math.log(p[i]));
result = result * (p[i]**a);
print(result)
You are using brute force technique to calculate the number, which is easy to understand and write, but takes very much time.
I am using the Prime Factorisation technique explained here.
i am not 100% sure, if my solution is really correct, but i guess it is and it is pretty fast.
First of all, we don't need to care for all divisors, as most are multiples of each other. So best way is to count the divisors backwards, for example starting with 20 down to 1.
I had a look at the prime numbers, the solution needs to be a multiple of all primes above 10, furthermore we need to check the 20 divisor, the rest can be ignored, as when testing divisor 18, the 9 will work as well, and so on.
So i mulitplied 11 * 13 * 17 * 19 * 20. The resulting is 923780 and is divisible by at least the primes + 20.
So i would start at 923780 and test only every 923780th number.
smallest_num = 923780
steps = 923780
while True:
divisor = 19
while smallest_num % divisor == 0 and divisor > 10:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor -= 1
if divisor == 10:
print("Smallest number is: {}").format(smallest_num)
break
smallest_num += steps
Maybe i have logical error?!

Project Euler #5 using python

The problem statement goes like this:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
Here is my solution:
x=2520.0
list=[]
true_list=[11.0, 12.0, 13.0, 14.0, 16.0, 17.0, 18.0, 19.0, 20.0]
b=1
def test():
for n in true_list:
z=x/n
if z%2==0:
list.append(n)
while b==1:
test()
if list==true_list:
b=2
print x
else:
x=x+20
list=[]
-> Basically, I have defined an empty list which gets filled up by the function test(). What test() does is it checks if the given number (x in this case) is evenly divisible by values from 11-20. If it is, it places that value(between 11-20) in the empty list.
When test() has run it's course, the program checks whether the list is equal to a predefined true_list which contains all numbers from 11-20. If it is, x is printed. Else, the program continues after incrementing the value of x.
This means that if list is equal to true_list, all the numbers from 11-20 are evenly dividing our number (x), which is what's asked in the problem.
It gives the answer: 465585120.0 after running for a minute or so. This happens to be incorrect. I do not know why that is. I've been trying to solve this for 8+ hours now and am at my wit's end. What is the error?
You do not need to read ahead, but in case you have queries about why I've used certain things in my solution, then I've addressed some of them here:
->I have not used all 20 numbers in true_list to speed up the program as any number evenly divisible by 11-20 is also evenly divisible by 1-20 as well.
->I have used x=x+20 to speed up the program because it is just as valid as x=x+1 or x+2;only, it is faster.
->I have used float values because I am using z=x/n in the function 'test()', and i do not want to chop off the decimal part because doing that would make even float values eligible for the subsequent operation i.e. z%2.
example:
1) with int values:
x=17
n=2
z=x/n=8
Here, z%2==0 is valid which should not be the case since it is not actually valid in mathematics.
2) with float values:
x=17.0
n=2.0
z=x/n=8.5
Here, z%n != 0 which is how it should be.
Like other people have mentioned just find the lcm, but here is a simple way to do it. Just remember lcm(a, b, c) = lcm(a, lcm(b, c)). That's all this is:
from fractions import gcd
print(reduce(lambda a, b: a * b / gcd(a, b), range(1, 21)))
If you want to write your own gcd function, it works like this (https://en.wikipedia.org/wiki/Euclidean_algorithm):
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
Tht % operator is called the "modulus" operator. In english: a % b is read "a mod b" and means "the remainder of a/b". So 100%3=1 and 12%5=2.
A common way to check divisibility is to check "Does my number modulo my divisor equal 0?". Or in code:
if a%b == 0:
print("b divides a!")
In your code you want to check if n divides x. You checked:
z=x/n
if z%2==0:
print("n divides x?") #No not really
z is the quotient of x and n. if z%2==0 can be interpreted as "If z is divisible by 2".
So you are asking "Is the quotient of x and n divisible by 2?" Which of course is nowhere close to what you want. Instead simply do
if x%n==0:
print("n divides x?") # YES!
I suggest you do a couple python tutorials so that you can get the basics down before attempting problems. :)
If you need anymore help let me know. :)
First of all as I stated in the comment, why are you trying to do it the brute force way? You could much easier calculate the LCM of the numbers 1 through to 20 in a couple of seconds.
Second of all, your line of code,
if z%2==0:
list.append(n)
That essentially gives you double the answer you want, as this statement causes you to calculate the LCM*2, as it must divide into an extra factor of 2.
The correct answer is 232792560, which I calculated using a piece of paper and a calculator in <20 seconds.
As you can see, the answer you are getting is double that
<-- Edit my previous code was wrong. this one works----->
You can correct this by doing:
x=2520.0
list=[]
true_list=[11.0, 12.0, 13.0, 14.0, 16.0, 17.0, 18.0, 19.0, 20.0]
b=1
def test():
for n in true_list:
if x%n==0:
list.append(n)
while b==1:
test()
if list==true_list:
b=2
print(x)
else:
x=x+20
list=[]
This is how you can do it by working out the LCM:
allFactors={}
#for each divisor (ignore 1 as it can divide into everything)
for n in range(2,21,1):
factors={}
i=2
while i<=n:
while n%i==0:
try:
factors[i]+=1
except KeyError:
factors[i]=1
n=n/i
i+=1
for pf,v in factors.iteritems():
try:
if allFactors[pf] < v:
allFactors[pf]=v
except KeyError:
allFactors[pf]=v
lcm=1
for pf,v in allFactors.iteritems():
lcm=lcm*(int(pf)**v)
print(lcm)
There are many ways to solve this problem. Since you're doing an early exercise from Project Euler, I suppose you'd like to develop an approach that helps you understand the basic Python constructs (as opposed to the "batteries included" approach with gcd and so on).
Here's a basic approach, not efficient in run time or developer time :) but a decent exercise:
found = None
n = 0
while not found:
n += 1
for d in xrange(2,21):
if n % d:
break
else:
found = n
print found
Which goes like this:
Examine a numerator n starting at 0. (You could actually start at 2520 since we know the answer must be no smaller than the answer to the 1-10 case, but that's a tiny optimization.)
Loop forever until a solution is found. (In a real-world program, you would probably put in some kind of safety check so this can't run forever, but this is fine for what we're doing.)
If we haven't found a solution yet, bump the numerator up by one for the next round.
Divide the numerator by a denominator d in the 2-20 range. If any value of d results in a non-zero remainder, break out of the loop - no point in testing the remaining denominators. (If we wanted to be more efficient, we could use xrange(2,n) since there is no point in dividing by a value greater than the numerator. If efficiency was an extreme concern, like if the range was vastly larger (2-1000 instead of 2-20), we could actually use xrange(2,floor(sqrt(n)) since there is no possibility of no remainder for a divisor great than the square root).
If we make it all the way through the for loop without breaking out early, the else clause operates, and we record the curent value of the numerator - this is the solution.
This approach is clearly brute force. It's fine as a learning exercise. For larger versions of the same problem, you'd be much better off using Euclid's algorithm and hardware-aware optimizations.
import time
start_time = time.time()
for i in range(2520,10000000000):
if i % 11 == 0 and\
i % 12 == 0 and\
i % 13 == 0 and\
i % 14 == 0 and\
i % 15 == 0 and\
i % 16 == 0 and\
i % 17 == 0 and\
i % 18 == 0 and\
i % 19 == 0 and\
i % 20 == 0:
print(i)
break
print(time.time() - start_time," seconds")
You can find the LCM of the Prime Numbers and the Composite Numbers separately, and then find the LCM of their LCMs. Gets the job done in almost a second! Here's my code:
import time
start_time = time.time()
nums = []
primeNums = []
allNums = []
def findFactors(num):
factors = []
for i in range(1, num + 1):
if num % i == 0:
if i not in factors:
factors.append(i)
x = int(num / i)
factors.append(x)
else:
break
return factors
def isDivisibleByAll(number, numbers):
isDivisbleBy = []
for num in numbers:
if number % num == 0:
isDivisbleBy.append(num)
return isDivisbleBy == numbers
for i in range(11, 21):
nums.append(i)
for num in nums:
if findFactors(num) == [1, num]:
primeNums.append(num)
nums.remove(num)
currentNum = nums[-1]
currentPrimeNum = primeNums[-1]
while isDivisibleByAll(currentNum, nums) == False:
currentNum = currentNum + nums[-1]
print(currentNum)
while isDivisibleByAll(currentPrimeNum, primeNums) == False:
currentPrimeNum = currentPrimeNum + primeNums[-1]
print(currentPrimeNum)
allNums.append(currentNum)
allNums.append(currentPrimeNum)
currentAllNum = allNums[-1]
while isDivisibleByAll(currentAllNum, nums) == False:
currentAllNum = currentAllNum + allNums[-1]
print(currentAllNum)
print(currentNum, currentPrimeNum, currentAllNum)
end_time = time.time()
print("Time taken: ", end_time - start_time)
A more efficient and shorter way of solving this problem will be the code mentioned below. So, as we know from the question that number that is divisible from all numbers between 1 to 10 is 2520. And we know that the factors of x are also the factors of yx. So, we can create a function that checks whether the number is divisible from all the numbers from 11 to 20. And we can make a while loop in which will increment the value of x by 2520 until the value of x is the answer. This method takes less than a second(on my i5 machine and 0.6083979606628418 seconds exactly).
def isdivisiblebyall(n):
for i in range(11, 21):
if n % i != 0:
return False
return True
no = 2520
while not isdivisiblebyall(no):
## if number is not divisible by range of 11 to 20 the value of 'no' will be incremented by 2520
no+=2520
print(no)

Python "OverflowError" [duplicate]

This question already has answers here:
`xrange(2**100)` -> OverflowError: long int too large to convert to int
(5 answers)
Closed 13 days ago.
I am just starting to learn to code in Python. I am trying to write some code to answer this Project Euler Question:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
My program works with the test case of 13195, but when I try to enter 600851475143, I get the error: "OverflowError: range() results has too many items"
Does anyone know how I can fix this?
Here is my code:
class Euler3:
"A class to find the largest prime factor of a given number"
n = 600851475143
primeFactors = []
for i in range(2,n):
if (n%i ==0):
primeFactors.append(i)
n = n/i
i = i -1 #reset i
print primeFactors
Any help or suggestions would be much appreciated!
The range function creates a list and tries to store it in memory. Creating a list many numbers long is what's causing the OverflowError. You can use xrange instead to get a generator which produces the numbers on demand.
That said, I think you'll find that your algorithm is way too slow for calculating large primes. There are a lot of prime number algorithms, but I might suggest checking out the Sieve of Eratosthenes as a starting point.
EDIT: Properly xrange actually doesn't return a generator, but an xrange object which behaves a lot like a generator. I'm not sure if you care, but it was bugging me that i wasn't precise!
I'm guessing you're using python 2 and not python 3 -- range(2,n) actually constructs a list! You don't have enough memory to store 600 billion numbers! xrange should be fine, though.
Also, your idea of i=i-1 doesn't work. For loops don't work like C, and that hack only works in C-style loops. The for loop iterates over range(2,n). If i gets the value 5 at once iteration, then no matter what you do to i, it still gets 6 the next time through.
Also, the list range(2,n) is constructed when you enter the loop. So when you modify n, that doesn't change anything.
You're going to have to rethink your logic a bit.
(if you don't believe me, try using 175 as a test case)
As a last comment, you should probably get in the habit of using the special integer division: n = n // i. Although / and // work the same in python 2, that is really deprecated behavior, and they don't work the same in python 3, where / will give you a floating point number.
You can fix the problem by using xrange instead of range
Your next problem will be that the program takes way too long to run because you need to break out of the loop under some condition
A better way to deal with repeat factors is to replace the if with a while
while (n%i ==0):
primeFactors.append(i)
n = n/i
n = 600851475143
primeFactors = []
for i in range(2,n):
i think you can optimize the function by noticing that
for i in range(2,n):
you can replace
range(2,n)
by
range(2,int(sqrt(n))+2)
because, you can see wiki...
This is the best way to find primes that I've found so far:
def isprime(n):
#make sure n is a positive integer
n = abs(int(n))
#0 and 1 are not primes
if n < 2:
return False
#2 is the only even prime number
if n == 2:
return True
#all other even numbers are not primes
if not n & 1:
return False
#range starts with 3 and only needs to go up to the square root of n
#for all odd numbers
for x in range (3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True #if it makes it through all the catches, it is a prime
This took me about 5 secs to get the answer.
import math
def is_prime_number(x):
for i in range(int(math.sqrt(x)), 2, -1):
if x % i == 0:
return False
return True
def next_prime_number(number):
#Returns the next prime number.
if number % 2 == 0 and number != 2:
number += 1
while not is_prime_number(number):
number += 2
return number
num = 600851475143
i = 2
while (i < long(math.sqrt(num) / 2)):
if num % i == 0:
largest = i
print largest
i = next_prime_number(i + 1)
xrange won't probably help you(or it may!),but the key thing here is to reliaze that you don't need to find the prime numbers up till 600851475143 or the factors of 600851475143,but it's prime factors,so...
Use the good old prime factorization method ,like so:
A=600851475143
n=2
fac=[]
while(n<=int(A)):
B=1
while(A%n==0):
B=0
A=A/n
if(B==0):
fac.append(n)
n=n+1
print max(fac)
This will return the argest prime factor almost instantly
I was battling with this Python "OverflowError", as well, working on this project. It was driving me nuts trying to come up with a combination that worked.
However, I did discover a clever, at least I think so :), way to do it.
Here is my code for this problem.
def IsNumberPrime(n):
bounds = int(math.sqrt(n))
for number in xrange(2,bounds+2):
if n % number == 0:
return False
return True
def GetListOfPrimeFactors(n):
primes = []
factors = GetListOfFactors(n)
if n % 2 == 0:
primes.append(2)
for entries in factors:
if IsNumberPrime(entries):
primes.append(entries)
return primes
GetListOfPrimeFactors(600851475143)
def GetListOfFactors(n):
factors = []
bounds = int(math.sqrt(n))
startNo = 2
while startNo <= bounds:
if n % startNo == 0:
factors.append(startNo)
startNo += 1
return factors
What I did was take the factors of the number entered and enter them into a list "factors". After that, I take the list of factors and determine which ones are primes and store them into a list, which is printed.
I hope this helps
-- Mike

Program to factorize a number into two smaller prime numbers

I have a very big number, and I want to make a program, that finds two prime numbers, that will give the original number, if multiplied.
Ex.
Original_number = 299
// The program should get these two numbers:
q = 13
p = 23
The program runs fine at the start, but at a certain point, it just stops, and I'm not sure what is wrong.
The code:
import time
import math
def main():
time1 = time.clock()
q = int(0)
p = int(0)
finalnumber = int(377)
print("in main \n")
print("q = ", q)
print("\n p = ", p)
gotResult = 0
while(gotResult == 0):
p = GetNextPrime(p)
if(p >= finalnumber):
q = GetNextPrime(q)
p = q
p = GetNextPrime(p)
if(q * p == finalnumber):
gotResult == 1
break
print("q = ", q)
print("\n p = ", p)
time2 = time.clock()
ElapsedTime = time2 - time1
print("Elapsed time: ", ElapsedTime)
def GetNextPrime(prime):
print("in GetNextPrime \n")
isPrime = 0
while(isPrime == 0):
prime = prime + 1
if(IsPrime(prime)== 1):
isPrime = 1
return prime
def IsPrime(prime):
print("in IsPrime \n")
isPrime = 0
i = 2
while(i <= math.sqrt(prime)):
if(i % 2 == 0):
i = i+1
if(prime % i == 0):
isPrime = 1
break
return isPrime
#start of program here
main()
I have written the program in python, and I know it probably isn't good, because I'm new to python.(I have been programming C++, and I'm not even good at it)
But I hope you can help me find the problem :)
ps. What is the maximum size of the original number? How many ciphers can it have?
Just factorize a number. You'll get a list of prime factors. If the list contains exactly two numbers, and the numbers are good for your purposes, you won. Else try another number.
But the approach above is quite wasteful. I'd rather take a list of primes, generate all pairs of it and multiply. The result would be a list of numbers that, well, can only be factorized into 2 primes. Like this:
some_primes = [2, 3, 5, 7, 11] # you can generate a better list
my_numbers = [x*y for x in some_primes for y in some_primes]
A simple approach is trial division:
import math
def factors(number):
return [(x, number / x) for x in range(int(math.sqrt(number)))[2:] if not number % x]
Then factors(299) returns [(13,23)]
There are problems with this method for large numbers:
Large numbers may exceed the python integer limit (found in sys.maxint). A 64-bit machine will be limited to 18 decimal digits.
Factoring large numbers is a hard problem, and an open research question. Trial division is about as brute force as it comes, but it will work for smaller numbers. Otherwise, you'll quickly need a more sophisticated algorithm. See wikipedia for a discussion.
If you're going to brute-force numerical problems, python is the wrong language. Identical algorithms will run faster in a compiled language like C++.
isPrime is wrong. You return 1 when the number is not prime. Also you never test if the number can be divided by 2. I didn't look any further than that.
Protip: Python is not C. There is True, False and you don't need all the brackets in if, while.
You should really test every function you write, not the whole program - that tells you nothing about where the bugs are.
In addition to Jochel Ritzel's and DSM's answers, the logic in main() while loop fails to account for cases when the number is not a product of two primes (then it will go into infinite loop).
Also, if you expect to factor really large numbers (say more than 20-30 digits), your approach is probably too slow. You should use Erastothenes sieve at minimum to generate a large enough list of primes in advance if you want to get acceptable results.
There are (pretty sophisticated) algoritms to deal with larger cases, but in general, this is a difficult problem and the solution to it scales very badly with number of digits.
In the following logic:
while(i <= math.sqrt(prime)):
if(i % 2 == 0):
i = i+1
if(prime % i == 0):
isPrime = 1
break
If i is odd and prime isn't divisible by it, it'll loop forever, and here it gets stuck on 3. [The other obvious problem has already been pointed out.]

Categories

Resources