Function that prints prime factorization of any number / Python - python

I'm looking for help writing a function that takes a positive integer n as input and prints its prime factorization to the screen. The output should gather the factors together into a single string so that the results of a call like prime_factorization(60) would be to print the string “60 = 2 x 2 x 3 x 5” to the screen. The following is what I have so far.
UPDATE: I made progress and figured out how to find the prime factorization. However, I still need help printing it the correct way as mentioned above.
""""
Input is a positive integer n
Output is its prime factorization, computed as follows:
"""
import math
def prime_factorization(n):
while (n % 2) == 0:
print(2)
# Turn n into odd number
n = n / 2
for i in range (3, int(math.sqrt(n)) + 1, 2):
while (n % i) == 0:
print(i)
n = n / I
if (n > 2):
print(n)
prime_factorization(60)
Note that I am trying to print it so if the input is 60, the output reads " 60 = 2 x 2 x 3 x 5 "

You should always separate computation from presentation. You can build the function as a generator that divides the number by increasing divisors (2 and then odds). When you find one that fits, output it and continue with the result of the division. This will only produce prime factors.
Then use that function to obtain the data to print rather than trying to mix in the printing and formatting.
def primeFactors(N):
p,i = 2,1 # prime divisor and increment
while p*p<=N: # no need to go beyond √N
while N%p == 0: # if is integer divisor
yield p # output prime divisor
N //= p # remove it from the number
p,i = p+i,2 # advance to next potential divisor 2, 3, 5, ...
if N>1: yield N # remaining value is a prime if not 1
output:
N=60
print(N,end=" = ")
print(*primeFactors(N),sep=" x ")
60 = 2 x 2 x 3 x 5

Use a list to store all factors, then print them together in the required format as a string.
import math
def prime_factorization(n):
factors = [] # to store factors
while (n % 2) == 0:
factors.append(2)
# Turn n into odd number
n = n / 2
for i in range (3, int(math.sqrt(n)) + 1, 2):
while (n % i) == 0:
factors.append(i)
n = n / I
if (n > 2):
factors.append(n)
print(" x ".join(str(i) for i in factors)) # to get the required string
prime_factorization(60)

Here is a way of doing it with f-strings. In addition, you need to do integer division (with //) to avoid getting floats in your answer.
""""
Input is a positive integer n
Output is its prime factorization, computed as follows:
"""
import math
def prime_factorization(n):
n_copy = n
prime_list = []
while (n % 2) == 0:
prime_list.append(2)
# Turn n into odd number
n = n // 2
for i in range(3, int(math.sqrt(n)) + 1, 2):
while (n % i) == 0:
prime_list.append(i)
n = n // i
if (n > 2):
prime_list.append(n)
print(f'{n_copy} =', end = ' ')
for factor in prime_list[:-1]:
print (f'{factor} x', end=' ' )
print(prime_list[-1])
prime_factorization(60)
#output: 60 = 2 x 2 x 3 x 5

Related

How can I determine The numerator and the power from a certain number?

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)]

Weird behaviour of division in python

I'm trying to solve this problem in hackerrank. At some point I have to check if a number divides n(given input) or not.
This code works perfectly well except one test case(not an issue):
if __name__ == '__main__':
tc = int(input().strip())
for i_tc in range(tc):
n = int(input().strip())
while n % 2 == 0 and n is not 0:
n >>= 1
last = 0
for i in range(3, int(n ** 0.5), 2):
while n % i == 0 and n > 0:
last = n
n = n // i # Concentrate here
print(n if n > 2 else last)
Now you can see that I'm dividing the number only when i is a factor of n.For example if the numbers be i = 2 and n = 4 then n / 2 and n // 2 doesn't make any difference right.
But when I use the below code all test cases are getting failed:
if __name__ == '__main__':
tc = int(input().strip())
for i_tc in range(tc):
n = int(input().strip())
while n % 2 == 0 and n is not 0:
n >>= 1
last = 0
for i in range(3, int(n ** 0.5), 2):
while n % i == 0 and n > 0:
last = n
n = n / i # Notice this is not //
print(n if n > 2 else last)
This is not the first time.Even for this problem I faced the same thing.For this problem I have to only divide by 2 so I used right shift operator to get rid of this.But here I can't do any thing since right shift can't help me.
Why is this happening ? If the numbers are small I can't see any difference but as the number becomes larger it is somehow behaving differently.
It is not even intuitive to use // when / fails. What is the reason for this ?
The main reason of the difference between n // i and n / i given that n and i are of type int and n % i == 0 is that
the type of n // i is still int whereas the type of n / i is float and
integers in Python have unlimited precision whereas the precision of floats is limited.
Therefore, if the value of n // i is outside the range that is accurately representable by the python float type, then it will be not equal to the computed value of n / i.
Illustration:
>>> (10**16-2)/2 == (10**16-2)//2
True
>>> (10**17-2)/2 == (10**17-2)//2
False
>>> int((10**17-2)//2)
49999999999999999
>>> int((10**17-2)/2)
50000000000000000
>>>

Probability of finding a prime (using miller-rabin test)

I've implemented Miller-Rabin primality test and every function seems to be working properly in isolation. However, when I try to find a prime by generating random numbers of 70 bits my program generates in average more than 100000 numbers before finding a number that passes the Miller-Rabin test (10 steps). This is very strange, the probability of being prime for a random odd number of less than 70 bits should be very high (more than 1/50 according to Hadamard-de la Vallée Poussin Theorem). What could be wrong with my code? Would it be possible that the random number generator throws prime numbers with very low probability? I guess not... Any help is very welcome.
import random
def miller_rabin_rounds(n, t):
'''Runs miller-rabin primallity test t times for n'''
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) / 2
s = 1
while r % 2 == 0:
s += 1
r /= 2
# Run the test t times
for i in range(t):
a = random.randint(2, n - 1)
y = power_remainder(a, r, n)
if y != 1 and y != n - 1:
# check there is no j for which (a^r)^(2^j) = -1 (mod n)
j = 0
while j < s - 1 and y != n - 1:
y = (y * y) % n
if y == 1:
return False
j += 1
if y != n - 1:
return False
return True
def power_remainder(a, k, n):
'''Computes (a^k) mod n efficiently by decomposing k into binary'''
r = 1
while k > 0:
if k % 2 != 0:
r = (r * a) % n
a = (a * a) % n
k //= 2
return r
def random_odd(n):
'''Generates a random odd number of max n bits'''
a = random.getrandbits(n)
if a % 2 == 0:
a -= 1
return a
if __name__ == '__main__':
t = 10 # Number of Miller-Rabin tests per number
bits = 70 # Number of bits of the random number
a = random_odd(bits)
count = 0
while not miller_rabin_rounds(a, t):
count += 1
if count % 10000 == 0:
print(count)
a = random_odd(bits)
print(a)
The reason this works in python 2 and not python 3 is that the two handle integer division differently. In python 2, 3/2 = 1, whereas in python 3, 3/2=1.5.
It looks like you should be forcing integer division in python 3 (rather than float division). If you change the code to force integer division (//) as such:
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) // 2
s = 1
while r % 2 == 0:
s += 1
r //= 2
You should see the correct behaviour regardless of what python version you use.

Get combination of factors product of a given number

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 &lt=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&lt=num
you can also use
while i&lt=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

Computing Eulers Totient Function

I am trying to find an efficient way to compute Euler's totient function.
What is wrong with this code? It doesn't seem to be working.
def isPrime(a):
return not ( a < 2 or any(a % i == 0 for i in range(2, int(a ** 0.5) + 1)))
def phi(n):
y = 1
for i in range(2,n+1):
if isPrime(i) is True and n % i == 0 is True:
y = y * (1 - 1/i)
else:
continue
return int(y)
Here's a much faster, working way, based on this description on Wikipedia:
Thus if n is a positive integer, then φ(n) is the number of integers k in the range 1 ≤ k ≤ n for which gcd(n, k) = 1.
I'm not saying this is the fastest or cleanest, but it works.
from math import gcd
def phi(n):
amount = 0
for k in range(1, n + 1):
if gcd(n, k) == 1:
amount += 1
return amount
You have three different problems...
y needs to be equal to n as initial value, not 1
As some have mentioned in the comments, don't use integer division
n % i == 0 is True isn't doing what you think because of Python chaining the comparisons! Even if n % i equals 0 then 0 == 0 is True BUT 0 is True is False! Use parens or just get rid of comparing to True since that isn't necessary anyway.
Fixing those problems,
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0:
y *= 1 - 1.0/i
return int(y)
Calculating gcd for every pair in range is not efficient and does not scales. You don't need to iterate throught all the range, if n is not a prime you can check for prime factors up to its square root, refer to https://stackoverflow.com/a/5811176/3393095.
We must then update phi for every prime by phi = phi*(1 - 1/prime).
def totatives(n):
phi = int(n > 1 and n)
for p in range(2, int(n ** .5) + 1):
if not n % p:
phi -= phi // p
while not n % p:
n //= p
#if n is > 1 it means it is prime
if n > 1: phi -= phi // n
return phi
I'm working on a cryptographic library in python and this is what i'm using. gcd() is Euclid's method for calculating greatest common divisor, and phi() is the totient function.
def gcd(a, b):
while b:
a, b=b, a%b
return a
def phi(a):
b=a-1
c=0
while b:
if not gcd(a,b)-1:
c+=1
b-=1
return c
Most implementations mentioned by other users rely on calling a gcd() or isPrime() function. In the case you are going to use the phi() function many times, it pays of to calculated these values before hand. A way of doing this is by using a so called sieve algorithm.
https://stackoverflow.com/a/18997575/7217653 This answer on stackoverflow provides us with a fast way of finding all primes below a given number.
Oke, now we can replace isPrime() with a search in our array.
Now the actual phi function:
Wikipedia gives us a clear example: https://en.wikipedia.org/wiki/Euler%27s_totient_function#Example
phi(36) = phi(2^2 * 3^2) = 36 * (1- 1/2) * (1- 1/3) = 30 * 1/2 * 2/3 = 12
In words, this says that the distinct prime factors of 36 are 2 and 3; half of the thirty-six integers from 1 to 36 are divisible by 2, leaving eighteen; a third of those are divisible by 3, leaving twelve numbers that are coprime to 36. And indeed there are twelve positive integers that are coprime with 36 and lower than 36: 1, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, and 35.
TL;DR
With other words: We have to find all the prime factors of our number and then multiply these prime factors together using foreach prime_factor: n *= 1 - 1/prime_factor.
import math
MAX = 10**5
# CREDIT TO https://stackoverflow.com/a/18997575/7217653
def sieve_for_primes_to(n):
size = n//2
sieve = [1]*size
limit = int(n**0.5)
for i in range(1,limit):
if sieve[i]:
val = 2*i+1
tmp = ((size-1) - i)//val
sieve[i+val::val] = [0]*tmp
return [2] + [i*2+1 for i, v in enumerate(sieve) if v and i>0]
PRIMES = sieve_for_primes_to(MAX)
print("Primes generated")
def phi(n):
original_n = n
prime_factors = []
prime_index = 0
while n > 1: # As long as there are more factors to be found
p = PRIMES[prime_index]
if (n % p == 0): # is this prime a factor?
prime_factors.append(p)
while math.ceil(n / p) == math.floor(n / p): # as long as we can devide our current number by this factor and it gives back a integer remove it
n = n // p
prime_index += 1
for v in prime_factors: # Now we have the prime factors, we do the same calculation as wikipedia
original_n *= 1 - (1/v)
return int(original_n)
print(phi(36)) # = phi(2**2 * 3**2) = 36 * (1- 1/2) * (1- 1/3) = 36 * 1/2 * 2/3 = 12
It looks like you're trying to use Euler's product formula, but you're not calculating the number of primes which divide a. You're calculating the number of elements relatively prime to a.
In addition, since 1 and i are both integers, so is the division, in this case you always get 0.
With regards to efficiency, I haven't noticed anyone mention that gcd(k,n)=gcd(n-k,n). Using this fact can save roughly half the work needed for the methods involving the use of the gcd. Just start the count with 2 (because 1/n and (n-1)/k will always be irreducible) and add 2 each time the gcd is one.
Here is a shorter implementation of orlp's answer.
from math import gcd
def phi(n): return sum([gcd(n, k)==1 for k in range(1, n+1)])
As others have already mentioned it leaves room for performance optimization.
Actually to calculate phi(any number say n)
We use the Formula
where p are the prime factors of n.
So, you have few mistakes in your code:
1.y should be equal to n
2. For 1/i actually 1 and i both are integers so their evaluation will also be an integer,thus it will lead to wrong results.
Here is the code with required corrections.
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0 :
y -= y/i
else:
continue
return int(y)

Categories