2016-08-28 20:26:06 +03:00
|
|
|
from random import randint
|
2017-08-17 18:37:27 +03:00
|
|
|
try:
|
|
|
|
import sympy.ntheory
|
|
|
|
except ImportError:
|
|
|
|
sympy = None
|
2016-08-28 20:26:06 +03:00
|
|
|
|
|
|
|
|
2017-05-21 14:59:16 +03:00
|
|
|
class Factorization:
|
2016-08-28 20:26:06 +03:00
|
|
|
@staticmethod
|
|
|
|
def find_small_multiplier_lopatin(what):
|
2016-09-04 12:07:18 +03:00
|
|
|
"""Finds the small multiplier by using Lopatin's method"""
|
2016-08-28 20:26:06 +03:00
|
|
|
g = 0
|
|
|
|
for i in range(3):
|
|
|
|
q = (randint(0, 127) & 15) + 17
|
2016-09-03 11:54:58 +03:00
|
|
|
x = randint(0, 1000000000) + 1
|
2016-08-28 20:26:06 +03:00
|
|
|
y = x
|
|
|
|
lim = 1 << (i + 18)
|
|
|
|
for j in range(1, lim):
|
|
|
|
a, b, c = x, x, q
|
|
|
|
while b != 0:
|
|
|
|
if (b & 1) != 0:
|
|
|
|
c += a
|
|
|
|
if c >= what:
|
|
|
|
c -= what
|
|
|
|
a += a
|
|
|
|
if a >= what:
|
|
|
|
a -= what
|
|
|
|
b >>= 1
|
|
|
|
|
|
|
|
x = c
|
|
|
|
z = y - x if x < y else x - y
|
2017-05-21 14:59:16 +03:00
|
|
|
g = Factorization.gcd(z, what)
|
2016-08-28 20:26:06 +03:00
|
|
|
if g != 1:
|
|
|
|
break
|
|
|
|
|
|
|
|
if (j & (j - 1)) == 0:
|
|
|
|
y = x
|
|
|
|
|
|
|
|
if g > 1:
|
|
|
|
break
|
|
|
|
|
|
|
|
p = what // g
|
|
|
|
return min(p, g)
|
|
|
|
|
2016-09-03 11:54:58 +03:00
|
|
|
@staticmethod
|
|
|
|
def gcd(a, b):
|
2016-09-04 12:07:18 +03:00
|
|
|
"""Calculates the greatest common divisor"""
|
2016-09-03 11:54:58 +03:00
|
|
|
while a != 0 and b != 0:
|
|
|
|
while b & 1 == 0:
|
|
|
|
b >>= 1
|
|
|
|
|
|
|
|
while a & 1 == 0:
|
|
|
|
a >>= 1
|
|
|
|
|
|
|
|
if a > b:
|
|
|
|
a -= b
|
|
|
|
else:
|
|
|
|
b -= a
|
|
|
|
|
|
|
|
return a if b == 0 else b
|
|
|
|
|
2016-08-28 20:26:06 +03:00
|
|
|
@staticmethod
|
|
|
|
def factorize(pq):
|
2016-09-04 12:07:18 +03:00
|
|
|
"""Factorizes the given number and returns both the divisor and the number divided by the divisor"""
|
2017-08-17 18:37:27 +03:00
|
|
|
if sympy:
|
|
|
|
return tuple(sympy.ntheory.factorint(pq).keys())
|
|
|
|
else:
|
|
|
|
divisor = Factorization.find_small_multiplier_lopatin(pq)
|
|
|
|
return divisor, pq // divisor
|