After I edited my code, I understand how to do it:
def sum_factors(n):
sum = 0
factor = 1
# Return the sum of all factors of n, not including n
while n!=0 and factor < n:
if n % factor == 0:
sum = sum + factor
factor = factor + 1
else:
factor = factor + 1
return sum
My initial code could not sum the factors but I don't understand why:
def sum_divisors(n):
sum = 0
factor = 1
# Return the sum of all divisors of n, not including n
while n % factor == 0 and factor < n:
sum = sum + factor
factor = factor + 1
return sum
Could you please explain why my initial code didn't work?
Your while loop writes
while n % factor == 0 and factor < n:
This would mean that once n % factor test condition is false, the code will break out of the while loop.
Let's use 10 as an example.
10 % 1 equals zero and 10 % 2 equals 0. But 10 % 3 does not equal 0. This means we break out of the while loop once factor gets to 3.
The answer we get would then be the sum of 1 and 2 which would be incorrect.
The initial code put a strong emphasize on the condition while n % factor == 0 which is not a necessary condition to end the while loop.
Sometimes, it helps to add some debugging output to a Python program:
def sum_divisors(n):
sum = 0
factor = 1
# Return the sum of all divisors of n, not including n
print(f"factor = {factor}")
while n % factor == 0 and factor < n:
sum = sum + factor
factor = factor + 1
print(f"factor = {factor}")
return sum
print(sum_divisors(30))
Output
factor = 1
factor = 2
factor = 3
factor = 4
6
Notes
As we can see, the while loop exits when it finds a number that is not a factor.
Refactoring
I noticed that you have duplicate code in your if-else block. Whenever this happens, you can move the common code outside:
if n % factor == 0:
sum = sum + factor
factor = factor + 1
Related
I am trying to write a predicate which checks if num is anti-prime.
A highly composite number (sometimes referred to as 'anti-prime') is a positive integer with more divisors than any smaller positive integer has.
I came up with this.
def count_divisors(num):
divisor_count = 0
for i in range(1, int(sqrt(num)) + 1):
if num % i == 0:
if num / i == i:
divisor_count += 1
continue
divisor_count += 2
return divisor_count
def is_highly_composite(x):
original_divisors = count_divisors(x)
for i in range(x-1, 0, -1):
if count_divisors(i) >= original_divisors:
return False
return True
Sadly it seems really inefficient and slow. Especially for big numbers.
I am learning coding so efficiency is kinda hard to wrap my head around.
Thanks for any help.
I could think of a bit neater approach to write your function count_divisors(). See the new version named count_divisors_np() below. (gmpy.is_square() allows for fast and accurate calculation for very large numbers, but you may just use divs[-1]**2 == num instead.)
import numpy as np
import gmpy2 as gp
def count_divisors_np(num):
divs = np.arange(1, round(np.sqrt(num)) + 1)
return 2*np.sum(num % divs == 0) - (1 if gp.is_square(num) else 0)
I compared the speeds, and on my PC, the new functions works consistently faster than the old one for numbers above 100,000, while it is almost twice as fast for numbers larger than 250,000. (See the code below that I used to compare the runtimes.)
import time
''' Other imports and definitions of count_divisors() and count_divisors_np()'''
def is_highly_composite(counter_func, x):
original_divisors = counter_func(x)
for i in range(x-1, 0, -1):
if counter_func(i) >= original_divisors:
return False
return True
for i in range(1, 10**3):
tic0 = time.time()
for x in range(i*1000 + 1, (i+1)*1000+1):
is_highly_composite(count_divisors, x)
toc0 = time.time() - tic0
tic1 = time.time()
for x in range(i* 1000 + 1, (i+1) * 1000+1):
is_highly_composite(count_divisors_np, x)
toc1 = time.time() - tic1
if toc1 < toc0:
print('from', i*1000+1, 'to', (i+1)*1000, ':', toc1, '<', toc0)
You can get good performance decomposing the number into its prime factors, applying the rules for a highly composite number.
All primes must be used sequentially at least once
The last prime factor must have a power of 1
The powers of prime factors must be in non-increasing order
If all of the above, check for other combinations of prime factors that can produce a higher (or equal) number of divisors with a smaller product.
Special cases: 4 and 36 are anti-primes
Infinite primes generator (you can make your own as needed, or just use a hard coded list of the first 100 primes):
primes = [2,3]
skips = {9:6}
def getPrimes(count=-1):
yield from primes[:max(0,count) or None]
p = primes[-1]+2
while count:
if p in skips:
mult,step = p,skips.pop(p)
mult += step
while mult in skips: mult += step
skips[mult] = step
else:
skips[p*p] = 2*p
primes.append(p)
yield p
count -= 1
p += 2
Anti-prime checking function:
from math import log
def isAntiPrime(N):
if N in [1,4,36]: return True # special cases
primeGen = getPrimes() # infinite primes generator
factors = [] # prime factors
lastPower = N # to check non-ascending order
divCount = 1 # number of divisors
R = N # reduced N (by factors)
for prime in primeGen: # go through prime factors
factors.append(prime)
if R==1: break # until number exausted
if R%prime: return False # unused prime factor
power = 0 # Count power of prime factor
while R%prime == 0:
power += 1
R //= prime # reduce number as we go
if lastPower<power: return False # increasing order
lastPower = power
divCount *= power+1 # compute number of divisors
if lastPower != 1: return False # last prime's power must be 1
def canReduce(i=0,prod=1,count=1): # recursively look for smaller number
if count>=divCount and prod<N: return True # found one
while i>=len(factors): # load primes list
factors.append(next(primeGen)) # up to index
prime = factors[i] # factor at index
for n in range(1,int(log(N/prod,prime))+1): # try prime^n
prod *= prime
if canReduce(i+1,prod,count*(n+1)): # combined
return True
return not canReduce() # no better power combo -> anti-prime
Output:
i = 0
for n in range(1,1000000):
if isAntiPrime(n):
i += 1
print(f"{i:2}",n)
1 1
2 2
3 4
4 6
5 12
6 24
7 36
8 48
9 60
10 120
11 180
12 240
13 360
14 720
15 840
16 1260
17 1680
18 2520
19 5040
20 7560
21 10080
22 15120
23 20160
24 25200
25 27720
26 45360
27 50400
28 55440
29 83160
30 110880
31 166320
32 221760
33 277200
34 332640
35 498960
36 554400
37 665280
38 720720
Other tests:
for n in [166320,166322,498960,494851, 169733893,
180068938933390833890254309768093,
7, 244877512201, 51983595331405913494380649,
2473017995717899, 252222613252687371148099,
7426227904486559070625807, 24247699, 3463957,
3674876304763078242658251219757, 713928607, 70693, 16807,
24975008738755062001]:
print(isAntiPrime(n),n)
True 166320
False 166322
True 498960
False 494851
False 169733893
False 180068938933390833890254309768093
False 7
False 244877512201
False 51983595331405913494380649
False 2473017995717899
False 252222613252687371148099
False 7426227904486559070625807
False 24247699
False 3463957
False 3674876304763078242658251219757
False 713928607
False 70693
False 16807
False 24975008738755062001
Note I didn't include any timing benchmarks because this is all instantaneous and just with the first 100 primes you can process numbers with up to 190 digits in less than a second
Finding anti-primes
The isAntiPrime function can be adapted to return the largest anti-prime <=N by leveraging its canReduce() function, turning it into an goal seeker from which we can get the largest divisor count with the smallest corresponding number:
def antiPrime(N):
if N in [1,4,36]: return N # special cases
primeGen = getPrimes() # infinite primes generator
factors = [] # prime factors
divCount = 1 # number of divisors
R = N # reduced N (by factors)
for prime in primeGen: # go through prime factors
factors.append(prime)
if R==1: break # until number exausted
if prime*prime>R: # when past square root,
prime = R # R is last prime
power = 0 # Count power of prime factor
while R%prime == 0:
power += 1
R //= prime # reduce number as we go
divCount *= power+1 # compute number of divisors
betterN = 0
def reduce(i=0,prod=1,count=1,lastPower=N): # look for smaller number
nonlocal divCount,betterN
if prod>=N: return
if count>divCount or count==divCount and prod<betterN:
divCount,betterN = count,prod # found better
while i>=len(factors): # load primes list
factors.append(next(primeGen)) # up to index
n,prime = 1,factors[i] # factor at index
while n<=lastPower and prod*prime<N: # try prime^n
prod *= prime
reduce(i+1,prod,count*(n+1),n) # combined
n += 1
reduce()
return betterN or N
Output:
for n in (1000000,713928607,2473017995717899,24975008738755062001,
180068938933390833890254309768093):
print(n,"anti-prime:",antiPrime(n))
1000000 anti-prime: 720720
713928607 anti-prime: 698377680
2473017995717899 anti-prime: 2021649740510400
24975008738755062001 anti-prime: 18401055938125660800
180068938933390833890254309768093 anti-prime: 156839524845080402008057229856000
This one is a bit slower on very large numbers because of the combinatory nature of the process.
8=2^3, 81=3^4.
How can I discover or find out which/what number can stand as a numerator and as a power for a certain number for example:
8 is the initial/certain number, but was split to 2 raised to the power of 3 where;
2 is the numerator and 3 is the power
Is there a software/algorithm of any sort that can provide an answer to this question for example 64?
You can do it by iterating over powers and finding the highest nth root that produces an integer.
from math import log
def findPower(N):
if N == 0: return (0,1) # support zero
if N < 0: # support negatives
r,p = findPower(-N)
return (-r,p) if p%2 else (N,1)
for power in range(int(log(N,2)),1,-1): # int(log(N,2))=N.bit_length()-1
root = int(N**(1/power))
for r in range(root-1,root+2):
if r**power == N: return (r,power)
return (N,1)
print(findPower(81)) # (3,4)
print(findPower(8)) # (2,3)
print(findPower(371293)) # (13,5)
print(findPower(29**7)) # (29,7)
print(findPower(-232630513987207)) # (-7, 17)
Note that this returns (n,1) for n = -1, 0 or 1 even though they all have an infinite number of solutions. It also returns only the positive base for even powers.
[EDIT] the above function is limited by the capabilities of floating point number representation. It will choke on very large integers.
Here is an alternative approach that supports Python's "infinite size" integers, using binary search for nth roots calculations and optimized using prime factors of the resulting exponent.
integer root calculation
# integer nth root of number X, Returns None if no exact root
rootMod7 = { p:{d**p%7 for d in range(1,8)} for p in range(1,7) }
def intRoot(X,n):
if n==1 or X==1: return X
odd,bits = X&1, X.bit_length() # odd/even and bit magnitude
if X%7 not in rootMod7[(n-1)%6+1]: return # mod 7 match possible roots
lo,hi = 1<<(bits//n),1<<(bits//n+1) # starting range on log(X,n)
while lo<=hi:
root = (lo+hi)//2 # binary search
if root&1 != odd: root += root < hi # odd/even must match X's
delta = X - root**n
if delta == 0: return root
if delta<0 : hi = root - 2 # adjust range
else: lo = root + 2 # on odd/even boundaries
return None
Prime number generator
def quickPrimes(N):
isPrime = [False,True]*(N//2+1)
primes = [2]
for p in range(3,N+1,2):
if not isPrime[p]: continue
primes.append(p)
isPrime[p*p:N+1:p] = (False for _ in range(p*p,N+1,p))
return primes
Solution for huge numbers
# finds base and power where base**power == N
def basePower(N):
base,power = (N,1) if N>=0 else basePower(-N)
if N<1: return (-base,power) if power%2 else (N,1)
maxPower = N.bit_length()
for p in reversed(quickPrimes(maxPower)):
if p>maxPower: continue
root = intRoot(base,p)
while root: # prime factorisation of exponents
maxPower = maxPower//p + 1
base,power = root,power*p
root = intRoot(base,p)
return base,power
This version can process huge numbers in a reasonable amount of time.
for example:
basePower(1522756**5553) # (1234, 11106) in 46 seconds, 34,333 digits
basePower(12345**12345) # (12345,12345) in 159 seconds, 50,510 digits
[EDIT2] A much better solution using prime factorisation:
You can find prime factors and take the greatest common denominator (gcd) of prime counts.
For example 216000's prime factors are 2^6, 3^3, 5^3 so the power will be 3. For each of the primes keep count/3 as the power to compute the base: 2^2 * 3^1 * 5^1 = 60. So 216000 = 60^3
def primeFactors(N): # returns dictionary of {prime:count}
result = dict()
p = 2 # p is a candidate prime factor
while p*p<=N: # prime candidates up to √N (remaining N)
while N%p == 0: # count prime factors
result[p] = result.get(p,0)+1
N //= p # by removing factors, only primes will match
p += 1 + (p&1) # next potential prime
if N>1: result[N] = 1 # anything remaining after √N is a prime
return result
def gcd(a,b=0,*c): # gcd using Euclid's algorithm
if c: return gcd(gcd(a,b),*c) # for multiple values
return a if not b else gcd(b,a%b) # Euclidian division version
def findPower(N):
counts = primeFactors(N) # {prime factor: count}
power = gcd(*counts.values()) # power is gcd of prime counts
base = 1
for f,c in counts.items(): # compute base
base *= f**(c//power) # from remaining prime powers
return base,power
This is much faster that the previous large-integer solution:
findPower(12345**12345)) # (12345,12345) in 2.8 seconds
A prime factor decomposition will give you the expected result. Demo:
def erato(n):
"""Search primes up to n using an Eratosthene's sieve"""
is_prime = [1] * n # expect all to be primes
for i in range(2,n): # and remove any multiple starting with 2
if is_prime[i] != 0: # but ignoring non primes
for j in range(i*i, n, i):
is_prime[j] = 0 # a multiple is not prime
return [i for i in range(2, n) if is_prime[i] != 0]
def decomp(n):
s = int(math.sqrt(n) + 1.5) # extract primes list up to sqrt(n)
primes = erato(s)
factors = []
for i in primes:
if i * i > n: # stop at sqrt(n)
break
q, r = divmod(n, i)
if r == 0: # found a divisor
p = 1
n = q
while True: # compute the exponent
q, r = divmod(n, i)
if r == 0:
p += 1
n = q
else:
break
factors.append((i, p)) # store the pair divisor, exponent
return factors
>>> decomp(8)
[(2, 3)]
>>> decomp(81)
[(3, 4)]
I am learning this Exponentiation Recursive algorithm, it works well.
But I don't understand why this works?
Because I expect that always returns 1,1,1...if n is even because a doesn't multiply in the return.
When I try recPower(3,2), and print the factor step by step, it will be like:
1
3
9
But, why does 3 come out?
def recPower(a, n):
# raises a to the int power n
if n == 0:
return 1
else:
factor = recPower(a, n//2)
if n%2 == 0: # n is even
return factor * factor
else: # n is odd
return factor * factor * a
Just follow it step by step:
recPower(3, 2)
n != 0 so go down the else branch:
factor = recPower(3, 2//2)
Which is:
recPower(3, 1)
In this recursive step n != 0 we follow the first else branches, 1%2 != 0 so we follow the second else branch. The factor is therefore 1 and a == 3.
The return value of this step is therefore:
factor * factor * a
or
1 * 1 * 3
I am not sure whether this question was posted before, after searching it, I cannot find it.
Question: Give one number, to print all factor product.
Example:
Given number: 20
Output: 1 * 20
2 * 10
2 * 2 * 5
4 * 5
Given number: 30
Output: 1 * 30
2 * 15
2 * 3 * 5
3 * 10
5 * 6
Here are my thoughts:
Solution 1.
step 1) First, get all prime factors of this number
def get_prime_factors(n):
factors = []
if n == 0:
return factors
# Get the number of 2s that divide n
while n%2 == 0:
factors.append(2)
n /= 2
# n must be odd
for i in range(3, int(ceil(sqrt(n))), 2):
while n%i == 0:
factors.append(i)
n /= i
# handle the case n is prime number greater than 2s
if n > 2:
factors.append(n)
return factors
step 2) Then get the combination of those factors
I plan to get all factor product through combination, however, I am stuck in how to handle those duplicate factors in this case? (question 1)
Solution 2:
Solve it through backtracking method.
def get_factors_recv(n, cur_ret, ret):
for i in range(2, int(ceil(sqrt(n)))):
if n%i == 0:
fact_arr = [i, n/i]
# add the current value to current result
cur_ret.extend(fact_arr)
if sorted(cur_ret) not in ret:
ret.append(sorted(cur_ret))
# backtracking
cur_ret = cur_ret[:-2]
get_factors_recv(n/i, cur_ret + [i], ret)
def get_all_factors_product(n):
if n == 0:
return '';
result = []
# push the simple factor multiplier
result.append([1, n])
get_factors_recv(n, [], result)
return result
I want to know is there any optimization for the above codes? (Question 2)
Is there any better solution to solve it? (Question 3)
A simple while loop can solve your first problem of dupicates. Given a number:
num_list = []
i = 2;
num = 72*5*5*19*10
while i <=num:
if(num%i == 0):
num_list.append(i)
num = num/i
else:
i = i + 1
print num_list
num_list will contain the factors. The idea is to not increase the index variable untill the number is no longer divisible by it. Also the number keeps reducing after every division so the loop will actually run a lot less iterations than the actual number. Instead of
while i<=num
you can also use
while i<=num/2
This is correct mathematically and results in further reduction of no of iterations.
This will give you all the factors.
Hope this helps.
number = 30
factors = []
for i in range(1, number+1):
if number%i == 0:
factors.append(i)
print factors
This is the code I created to find the largest power of 2 factor. I do not think that this is 100% correct because I keep getting 2 as the answer. I need some help figuring this out. I am completely new at programming.
MY CODE:
def largestPowerOfTwoThatIsAFactorOf(num):
factor = 2
while not(num > 0):
factor = factor + 1
return factor
print(largestPowerOfTwoThatIsAFactorOf(4))
print(largestPowerOfTwoThatIsAFactorOf(15))
print(largestPowerOfTwoThatIsAFactorOf(120))
#For any odd integer, largest power of 2 that’s a factor is 1.
This is an interesting and useful function, fit to deal with FFT, to perform Signal Processing and Analysis once FFT is a square matrix with "power of two" dimensions... understanding that a power of two is the result of two elevated to some power, and that there are infinite powers of two greater than n, a better name to the function should be minimum power of two greater than n - we just use it to dimension a collection of signal data to submit it to FFT filter. There follows two options, named minpowof2 and the maxpowof2...
def minpowof2(n):
'''Minimun Power of Two Greater Than n'''
f = 1
if n < 2: return 'try n greater or iqual to 2'
while n > 2:
n /= 2
f += 1
return 2**f
def maxpowof2(n):
'''Maximum Power of Two Lower than n'''
return int(minpot2(n)/2)
def largestPowerOfTwoThatIsAFactorOf(num):
if num % 2 != 0: return 1
factor = 0
while num % 2 == 0:
num /= 2
factor += 1
return 2 ** factor
## or return factor; as per your requirement
You need to update num inside the loop. Also, you cna optimize the code a little by checking whether the input was odd or not in the first statement.