Python While loop to calculate smallest common multiple - python

This is meant to calculate the smallest common multiple of 1-20.
I can't seem to figure out why the while loop won't end. Can anyone help me out?
i = 1
j = 1
factors = 0
allfactor = False
while allfactor == False:
while j < 21:
if i % j == 0:
factors = factors + 1
j = j + 1
else:
break
if factors == 20:
allfactor = True
break
else:
i = i + 1
j = 1
factors = 0

The least common multiple of the numbers 1..20 is 232792560.
To get to that number you just need to look at the numbers 1 to 20. You need at least all prime numbers: 2, 3, 5, 7, 11, 13, 17 and 19.
In addition, you need another 2 to calculate 4, and two more 2s for 16. To get a 9 you also need another 3.
So you end up with:
2 * 2 * 2 * 2 * 3 * 3 * 5 * 7 * 11 * 13 * 17 * 19 = 232792560
And you can easily confirm that using Python:
>>> all(map(lambda x: 232792560 % x == 0, range(1, 21)))
True
I.e. all numbers are divisors of said number; and per the proof above (its construction) there is no smaller number.

Related

finding divisor with condition with python using 'if' and 'while'

trying to find how many divisors in 120, and printing divisors
div_n = 1
count = 0
n = 120
while div_n <= n:
if n % div_n == 0:
print(div_n)
count += 1
div_n += 1
print('number of divisor that 120 is {}.'.format(count))
the output should be
1
2
3
4
5
6
8
10
12
15
20
24
30
40
60
120
number of divisor that 120 is 16
But the problem I'm trying to solve says the code is not meeting the requirements.
If there is nothing wrong, or more information is needed let me know.
You can use this:
def get_factors(n):
ret = []
for i in range(1, n+1):
if not n % i:
ret.append(i)
return ret
factors = get_factors(120)
print(*factors, sep='\n')
print('Total factors:', len(factors))
Output:
1
2
3
4
5
6
8
10
12
15
20
24
30
40
60
120
Total factors: 16
Your code, once properly indented, works just fine. So I suspect the requirement you don't meet is that of speed - try the code with n=120000000.
When you look for divisors you don't need to check all the numbers from 1 to n: just check numbers from 1 to int(sqrt(n)) - when you find a divisor lower than the square root you have also found a related divisor, greater than the square root. In your example, when you find 2 you also find 60, and so on.
So I would do something like:
def divisors(n):
divs = []
divs2 = []
r = int(sqrt(n))
for d in range(1,r):
q,m = divmod(n,d)
if m == 0:
divs.append(d)
divs2.append(q)
if n % r == 0:
divs.append(r)
for d in divs:
print(d)
for d in divs2[::-1]:
print(d)
print(f'Divisors for {n}: {len(divs)+len(divs2)}')
EDIT: there was a small bug - if n happened to be a perfect square, my code would count its square root twice. So we better stop at int(sqrt(n))-1 and handle the square root separately.

Finding the total number of elements in list, comparisons and swaps needed to sort the numbers list using selection sort

QUESTION:
Consider the incomplete function below:
def my_selection_sort(a_list):
for I in range(len(a)_list - 1, 0, -1):
...
Complete the my_selection_sort() function above so that it returns the total number of elements, comparisons and swaps needed to sort the numbers list. The function must return these 3 values as a tuple.
Consider the following:
A list with reverse order numbers: # of elements = 8, # of comparisons = 28 (1 + 2 + 3 + 4 + 5 + 6 + 7), # of swaps = 7
A list with sorted order numbers: # of elements = 8, # of comparisons = 28 (1 + 2 + 3 + 4 + 5 + 6 + 7), # of swaps = 7
MY CODE:
def my_selection_sort(a_list):
length = len(a_list)
swaps = 0
comparisons = 0
for i in range(len(a_list)-1,0,-1):
lowest_value_index = i
for j in range(len(a_list)-1,i+1,-1):
comparisons += 1
if a_list[j] < a_list[lowest_value_index]:
lowest_value_index = j
swaps += 1
a_list[i],a_list[lowest_value_index] = a_list[lowest_value_index],a_list[i]
return (length,comparisons,swaps)
TEST:
Test 1:
nums = [6]
res = my_selection_sort(nums)
print('Length: {} Comparisons: {} Swaps: {}'.format(res[0], res[1], res[2]))
Test 2:
nums = [70, 48, 54, 79, 33]
res = my_selection_sort(nums)
print('Length: {} Comparisons: {} Swaps: {}'.format(res[0], res[1], res[2]))
EXPECTED OUTPUT:
Test 1:
Length: 1 Comparisons: 0 Swaps: 0
Test 2:
Length: 5 Comparisons: 10 Swaps: 4
ACTUAL OUTPUT:
Test 1:
Length: 1 Comparisons: 0 Swaps: 0
Test 2:
Length: 5 Comparisons: 3 Swaps: 4
A different and simple strategy. You don't need to even apply the for loops.
In selection sort, the comparisons and swapping's are fixed always. There are mathematical formulas for both that you can implement in python:
Assume length of the list = n
Total no of comparisons: Summation from 1 till n-1
Total number of swaps = n-1
Special Case : n = 0 and n=1 (You can check for this in if statements)
Other Cases : n > 1 ,
for example n = 8 ,
Comparisons = 1+2+3+4+5+6+7 = 28,
Swaps = 8-1 = 7.
for example n = 5,
Comparisons = 1+2+3+4 = 10,
Swaps = 5-1 = 4.

Is there a way to list super primes between 1 and n in NumPy

Is there a way to list super primes (primes in a prime position wikipedia article) between 1 and n using NumPy.
I got this without Numpy, is that okay?
here is the code based on
Sieve of Atkin
import math
is_prime = list()
limit = 100
for i in range(5, limit):
is_prime.append(False)
for x in range(1, int(math.sqrt(limit)) + 1):
for y in range(1, int(math.sqrt(limit)) + 1):
n = 4 * x ** 2 + y ** 2
if n <= limit and (n % 12 == 1 or n % 12 == 5) and n <= len(is_prime):
# print "1st if"
is_prime[n] = not is_prime[n]
n = 3 * x ** 2 + y ** 2
if n <= limit and n % 12 == 7:
# print "Second if"
is_prime[n] = not is_prime[n]
n = 3 * x ** 2 - y ** 2
if x > y and n <= limit and n % 12 == 11:
# print "third if"
is_prime[n] = not is_prime[n]
for n in range(5, int(math.sqrt(limit))):
if is_prime[n]:
for k in range(n ** 2, limit + 1, n ** 2):
if k <= len(is_prime):
is_prime[k] = False
for n in range(5, limit):
if n < len(is_prime) and is_prime[n]:
print(n)
Numpy Code Version
Sieve modification of Numpy Sieve by user2357112 supports Monica
import numpy as np
def sieve(n):
'''
Sieve of Erastosenes using numpy
'''
flags = np.ones(n, dtype=bool) # Set all values to True
# Set 0, 1, and even numbers > 2 to False
flags[0] = flags[1] = False
flags[4:n:2] = False
for i in range(3, n, 2):
# Check for odd primes
if flags[i]:
flags[i*i::i] = False
return np.flatnonzero(flags) # Indexes of True are prime
def superPrimes(n):
'''
Find superprimes
'''
# Find primes up to n using sieve
p = sieve(n)
# p(i) denotes the ith prime number, the numbers in this sequence are those of the form p(p(i))
# Want to find numbers we can index in the list (i.e. has to be less than len(p))
indexes = p[p < len(p)] # base 1 indexes within range
return p[indexes-1] # Subtract 1 since primes array is base 0 indexed
Test
print(superPrimes(200))
# Output: [ 3 5 11 17 31 41 59 67 83 109 127 157 179 191]

python - adding each digit that is greater than 4

Given an integer. for each individual digit that is greater than 4, i need to add it to all the next digits that greater than 4.
For example: a = 4567; the result should be 0 + (5) + (5+6) + (5+6+7) = 34
So far in my code, I was able to get the sum for single digit only. If the integer is greater 10, it will only give the sum of the very first digit. Any idea why this happening?
def morethanfour(number):
num = 0
num = [int(d) for d in str(number)] #seperate into individual digit
total = 0
for i in range (len(num)):
if num[i] > 4:
total = sum(x for x in range(5, num[i]+1)) #adding the sum
return total
num = 9
print(morethanfour(num))
the result when num = 9 is 35 (5+6+7+8+9)
However, when num = 178, it gave me 0
Try this:
>>> def morethanfour(number):
return sum(sum(range(5,x+1)) for x in map(int,str(number)) if x>4)
>>> morethanfour(9)
35
>>> morethanfour(4567)
34
>>> morethanfour(178)
44
>>> sum(sum(num[j] for j in range(0, i+1) if num[j] > 4) for i in range(len(num)))
34

Efficient way to find sum of digits of an entire sequence

In the following code snippet I am finding the sum of digits of all odd number between the interval [a,b]
def SumOfDigits(a, b):
s = 0
if a%2 == 0:
a+=1
if b%2 == 0:
b-=1
for k in range(a,b+1,2):
s+= sum(int(i) for i in list(str(k)))
return s
Is there an efficient way to accomplish the same?
Any patterns, which is leading to a clear cut formula.
I did search in https://oeis.org
Avoid all the overhead of conversion to and from strings and work directly with the numbers themselves:
def SumOfDigits(a, b):
result = 0
for i in range(a + (not a % 2), b + 1, 2):
while i:
result += i % 10
i //= 10
return result
Of course there is a pattern. Let's look at the problem of summing up the digitsums of all – odd and even – numbers between a and b inclusively.
For example: 17 to 33
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
The middle section gives you the sum of all digits from 0 to 9 (45) plus ten times 2. The left section is 7 + 8 + 9 plus three times 1 and the right the sum of 0 + 1 + 2 + 3 plus four times 3.
The middle section can comprise several blocks of ten, for example if you calculate the range between 17 and 63, you get 40 times 45 plus ten simes the the digitsums from 2 to 5.
This gives you a recursive algorithm:
def ssum(n):
return n * (n + 1) // 2
def dsum(a, b):
res = 0
if a == b:
while a:
res += a % 10
a //= 10
elif a < b:
aa = a // 10
bb = b // 10
ra = a % 10
rb = b % 10
if aa == bb:
res += ssum(rb) - ssum(ra - 1)
res += (rb - ra + 1) * dsum(aa, bb)
else:
if ra > 0:
res += 45 - ssum(ra - 1)
res += (10 - ra) * dsum(aa, aa)
aa += 1
if rb < 9:
res += ssum(rb)
res += (rb + 1) * dsum(bb, bb)
bb -= 1
if aa <= bb:
res += 45 * (bb - aa + 1)
res += 10 * dsum(aa, bb)
return res
Now let's extend this to include only odd numbers. Adkust a so that it is even and b so that it is odd. Your sum of digit sums now runs over pairs of even and odd numbers, where even + 1 == odd. That means that the digitsum of the odd number id one more than the even number, because all except the last digits are the same and the last odd digit is one more than the even digit.
Therefore:
dsum(a, b) == oddsum + evensum
and:
oddsum - evensum == (b - a + 1) // 2
The function to sum the digitsums of all odd numbers is then:
def oddsum(a, b):
if a % 2: a -= 1
if b % 2 == 0: b -= 1
d = (b - a + 1) // 2
return (dsum(a, b) + d) // 2
When I looked at your comment about OEIS, I've noticed that the algorithm can probably be simplified by writing a function to sum the digits from all numbers from zero to n and then calculate the difference dsum(b) - dsum(a). There are probably more opportunities for optimisation.

Categories

Resources