Weird behaviour of division in python - 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
>>>

Related

Function that prints prime factorization of any number / 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

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

Summing 1 to even integer doubles the result

I was trying to come up with a simple on-liner to detect if an integer was even and if not add 1 to make it even. So I came up with this:
N = 62465
N += 1 if bool(N % 2) else N
print N
This works fine if N is odd but if it is even it returns double the value. What is happening here?
You are doubling your N when it is even; you essentially do this:
if N % 2:
N += 1
else:
N += N
You'd want to use N += 1 if N % 2 else 0 instead (the bool() is implied in conditionals).
To simplify that you can just add N % 2 as that'll be 0 for even and 1 for odd:
N += N % 2
The often-used way of doing this is by dividing then multiplying.
N = (N + 2 - 1)//2*2
This works with other moduluses that are not 2.

Math differences?

I'm learning python 3 and am doing some of the Codeeval stuff and I need to generate a list of prime numbers.
So I wrote a function that would check if a number is prime, and I wasn't getting the answer I was looking for so I found a similar function on this site that does work. However, technically (unless I'm not seeing something) they should produce the same output.
The "trouble" area is in the isPrime function in the range
Both int(n ** .5 +1) and math.ceil(math.sqrt(n)) produce the same value.
So my question is: Why do I end up with a different output between those two ways of getting the square root of a number?
def isPrime(n):
if n == 2:
return True
elif n < 2 or n % 2 == 0:
return False
# for i in range(3,int(n ** .5 + 1),2):
for i in range(3,math.ceil(math.sqrt(n)),2):
if n % i == 0: return False
return True
def generatePrimes(n):
primes = [2]
noOfPrimes = 1
idx = 3
while noOfPrimes < n:
if isPrime(idx):
primes.append(idx)
noOfPrimes+=1
idx += 2
return primes
print((generatePrimes(50)))
Your claim:
Both int(n ** .5 + 1) and math.ceil(math.sqrt(n)) produce the same value.
I disagree:
Let's look at the case when n == 9
int(n ** 0.5 + 1) == 4
math.ceil(math.sqrt(n)) == 3
The code, as written, produces 9, 49, 121, ... any square of a prime number. This is because the upper bound of range() is exclusive and you must add 1 to make it inclusive.
for i in range(3, math.ceil(math.sqrt(n)) + 1, 2):
# ^^^^
You seemed to remember this when using int(n ** .5 + 1), however. Or is that +1 in there for a different reason?

Categories