Fast floating point modpow - python

I am looking to compute a^b mod m where a & b are floating point numbers and m is an non-negative integer. The trivial solution is to do b multiplications which takes O(n) time, however my numbers a & b can be largish (~10 digits before the decimal point) and I would like to do this efficiently. When a,b and m are integers we can compute the modpow quickly in log(n) time via: Exponentiation_by_squaring.
How would I use this method (or another) for floating point numbers? I am using Python to do this computation and the pow function only allows integers. Here is my attempt at doing exponentiation by squaring with Decimal numbers, but the answer is not coming out right:
from decimal import Decimal
EPS = Decimal("0.0001")
# a, b are Decimals and m is an integer
def deci_pow(a, b, m):
if abs(b) < EPS:
return Decimal(1)
tmp = deci_pow(a, b / 2, m) % m # Should this be // ?
if abs(b % 2) < EPS:
return (tmp * tmp) % m
else:
if b > 0:
return (a * tmp * tmp) % m
else:
return ((tmp * tmp)/a) % m
print(deci_pow(Decimal(2.4), Decimal(3.5), 5)) # != 1.416
When a,b,m are all integers this is what the method looks like:
# a, b, m are Integers
def integer_pow(a, b, m):
if b == 0: return 1
tmp = integer_pow(a, b // 2, m) % m
if b % 2 == 0:
return (tmp * tmp) % m
else:
if b > 0:
return (a * tmp * tmp) % m
else:
return ((tmp * tmp) / a) % m

I don't think there is an easy way to do this in general, if a and b can be 10 digits (assuming before the decimal point). The problem is that for floats x and y, you don't necessarily have the property
((x % m) * (y % m)) % m == (x * y) % m
If you tell us your specific context and why you want to do this, there might be other approaches possible.

Related

Let n be a square number. Using Python, how we can efficiently calculate natural numbers y up to a limit l such that n+y^2 is again a square number?

Using Python, I would like to implement a function that takes a natural number n as input and outputs a list of natural numbers [y1, y2, y3, ...] such that n + y1*y1 and n + y2*y2 and n + y3*y3 and so forth is again a square.
What I tried so far is to obtain one y-value using the following function:
def find_square(n:int) -> tuple[int, int]:
if n%2 == 1:
y = (n-1)//2
x = n+y*y
return (y,x)
return None
It works fine, eg. find_square(13689) gives me a correct solution y=6844. It would be great to have an algorithm that yields all possible y-values such as y=44 or y=156.
Simplest slow approach is of course for given N just to iterate all possible Y and check if N + Y^2 is square.
But there is a much faster approach using integer Factorization technique:
Lets notice that to solve equation N + Y^2 = X^2, that is to find all integer pairs (X, Y) for given fixed integer N, we can rewrite this equation to N = X^2 - Y^2 = (X + Y) * (X - Y) which follows from famous school formula of difference of squares.
Now lets rename two factors as A, B i.e. N = (X + Y) * (X - Y) = A * B, which means that X = (A + B) / 2 and Y = (A - B) / 2.
Notice that A and B should be of same odditiy, either both odd or both even, otherwise in last formulas above we can't have whole division by 2.
We will factorize N into all possible pairs of two factors (A, B) of same oddity. For fast factorization in code below I used simple to implement but yet quite fast algorithm Pollard Rho, also two extra algorithms were needed as a helper to Pollard Rho, one is Fermat Primality Test (which allows fast checking if number is probably prime) and second is Trial Division Factorization (which helps Pollard Rho to factor out small factors, which could cause Pollard Rho to fail).
Pollard Rho for composite number has time complexity O(N^(1/4)) which is very fast even for 64-bit numbers. Any faster factorization algorithm can be chosen if needed a bigger space to be searched. My fast algorithm time is dominated by speed of factorization, remaining part of algorithm is blazingly fast, just few iterations of loop with simple formulas.
If your N is a square itself (hence we know its root easily), then Pollard Rho can factor N even much faster, within O(N^(1/8)) time. Even for 128-bit numbers it means very small time, 2^16 operations, and I hope you're solving your task for less than 128 bit numbers.
If you want to process a range of possible N values then fastest way to factorize them is to use techniques similar to Sieve of Erathosthenes, using set of prime numbers, it allows to compute all factors for all N numbers within some range. Using Sieve of Erathosthenes for the case of range of Ns is much faster than factorizing each N with Pollard Rho.
After factoring N into pairs (A, B) we compute (X, Y) based on (A, B) by formulas above. And output resulting Y as a solution of fast algorithm.
Following code as an example is implemented in pure Python. Of course one can use Numba to speed it up, Numba usually gives 30-200 times speedup, for Python it achieves same speed as optimized C++. But I thought that main thing here is to implement fast algorithm, Numba optimizations can be done easily afterwards.
I added time measurement into following code. Although it is pure Python still my fast algorithm achieves 8500x times speedup compared to regular brute force approach for limit of 1 000 000.
You can change limit variable to tweak amount of searched space, or num_tests variable to tweak amount of different tests.
Following code implements both solutions - fast solution find_fast() described above plus very tiny brute force solution find_slow() which is very slow as it scans all possible candidates. This slow solution is only used to compare correctness in tests and compare speedup.
Code below uses nothing except few standard Python library modules, no external modules were used.
Try it online!
def find_slow(N):
import math
def is_square(x):
root = int(math.sqrt(float(x)) + 0.5)
return root * root == x, root
l = []
for y in range(N):
if is_square(N + y ** 2)[0]:
l.append(y)
return l
def find_fast(N):
import itertools, functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = factor(N)
mfs = {}
for e in fs:
mfs[e] = mfs.get(e, 0) + 1
fs = sorted(mfs.items())
del mfs
Ys = set()
for take_a in itertools.product(*[
(range(v + 1) if k != 2 else range(1, v)) for k, v in fs]):
A = Prod([p ** t for (p, _), t in zip(fs, take_a)])
B = N // A
assert A * B == N, (N, A, B, take_a)
if A < B:
continue
X = (A + B) // 2
Y = (A - B) // 2
assert N + Y ** 2 == X ** 2, (N, A, B, X, Y)
Ys.add(Y)
return sorted(Ys)
def trial_div_factor(n, limit = None):
# https://en.wikipedia.org/wiki/Trial_division
fs = []
while n & 1 == 0:
fs.append(2)
n >>= 1
all_checked = False
for d in range(3, (limit or n) + 1, 2):
if d * d > n:
all_checked = True
break
while True:
q, r = divmod(n, d)
if r != 0:
break
fs.append(d)
n = q
if n > 1 and all_checked:
fs.append(n)
n = 1
return fs, n
def fermat_prp(n, trials = 32):
# https://en.wikipedia.org/wiki/Fermat_primality_test
import random
if n <= 16:
return n in (2, 3, 5, 7, 11, 13)
for i in range(trials):
if pow(random.randint(2, n - 2), n - 1, n) != 1:
return False
return True
def pollard_rho_factor(n):
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
import math, random
fs, n = trial_div_factor(n, 1 << 7)
if n <= 1:
return fs
if fermat_prp(n):
return sorted(fs + [n])
for itry in range(8):
failed = False
x = random.randint(2, n - 2)
for cycle in range(1, 1 << 60):
y = x
for i in range(1 << cycle):
x = (x * x + 1) % n
d = math.gcd(x - y, n)
if d == 1:
continue
if d == n:
failed = True
break
return sorted(fs + pollard_rho_factor(d) + pollard_rho_factor(n // d))
if failed:
break
assert False, f'Pollard Rho failed! n = {n}'
def factor(N):
import functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = pollard_rho_factor(N)
assert N == Prod(fs), (N, fs)
return sorted(fs)
def test():
import random, time
limit = 1 << 20
num_tests = 20
t0, t1 = 0, 0
for i in range(num_tests):
if (round(i / num_tests * 1000)) % 100 == 0 or i + 1 >= num_tests:
print(f'test {i}, ', end = '', flush = True)
N = random.randrange(limit)
tb = time.time()
r0 = find_slow(N)
t0 += time.time() - tb
tb = time.time()
r1 = find_fast(N)
t1 += time.time() - tb
assert r0 == r1, (N, r0, r1, t0, t1)
print(f'\nTime slow {t0:.05f} sec, fast {t1:.05f} sec, speedup {round(t0 / max(1e-6, t1))} times')
if __name__ == '__main__':
test()
Output:
test 0, test 2, test 4, test 6, test 8, test 10, test 12, test 14, test 16, test 18, test 19,
Time slow 26.28198 sec, fast 0.00301 sec, speedup 8732 times
For the easiest solution, you can try this:
import math
n=13689 #or we can ask user to input a square number.
for i in range(1,9999):
if math.sqrt(n+i**2).is_integer():
print(i)

TypeError float object cannot be interpreted as an integer

I'm trying to get the result in hex format, but I get the error "TypeError: 'float' object cannot be interpreted as an integer!"
39 d = chinese_remainder(a, n)
---> 40 number = hex(d)
41 print(number)
Code:
import functools
# Euclidean extended algorithm
def egcd(a, b):
if a == 0:
return b, 0, 1
else:
d, x, y = egcd(b % a, a)
return d, y - (b // a) * x, x
"""
Functions whcih calculate the CRT (
return x in ' x = a mod n'.
"""
def chinese_remainder(a, n):
modulus = functools.reduce(lambda a, b: a * b, n)
multipliers = []
for N_i in n:
N = modulus / N_i
gcd, inverse, y = egcd(N, N_i)
multipliers.append(inverse * N % modulus)
result = 0
for multi, a_i in zip(multipliers, a):
result = (result + multi * a_i) % modulus
return result
FN = 1184749
FM = 8118474
FL = 5386565
HN = 8686891
HM = 6036033
HK = 6029230
n = [FN, FM, FL]
a = [HN, HM, HK]
d = chinese_remainder(a, n)
number = hex(d)
print(number)
The result should be like this
FAB15A7AE056200F9
But it gives me
3.3981196080447865e + 19
How to fix this so that the result is in hex format ???
Normal division / operator returns float whereas you can use floor division // to get integers.
As others suggested, you have to use floor division to variable N like this N = modulus//N_i

Converting EGCD Equation to Python

Attempting to convert this EGCD equation into python.
egcd(a, b) = (1, 0), if b = 0
= (t, s - q * t), otherwise, where
q = a / b (note: integer division)
r = a mod b
(s, t) = egcd(b, r)
The test I used was egcd(5, 37) which should return (15,-2) but is returning (19.5, -5.135135135135135)
My code is:
def egcd(a, b):
if b == 0:
return (1, 0)
else:
q = a / b # Calculate q
r = a % b # Calculate r
(s,t) = egcd(b,r) # Calculate (s, t) by calling egcd(b, r)
return (t,s-q*t) # Return (t, s-q*t)
a / b in Python 3 is "true division" the result is non-truncating floating point division even when both operands are ints.
To fix, either use // instead (which is floor division):
q = a // b
or use divmod to perform both division and remainder as a single computation, replacing both of these lines:
q = a / b
r = a % b
with just:
q, r = divmod(a, b)
Change q = a / b for q = a // b

Finding remainder mod involving exponent and division involving huge numbers

I need a fast algorithm to evaluate the following
((a^n-1)/(a-1)) % p
Both a and n are nearly equal but less to 10^6 and p is a fixed prime number (let's say p=1000003). I need to compute it under 1 second. I am using python. Wolfram Mathematica computes it instantly. It takes 35.2170000076 seconds with following code
print (((10**6)**(10**6)-1)/((10**6)-1))%1000003
If that denominator a-1 were not present, I could group the powers into smaller order and use the relation a*b (mod c) = (a (mod c) * b (mod c)) (mod c) but denominator is present.
How to evaluate this with a fast algorithm? No numpy/scipy are available.
UPDATE:: Here is the final code I came up with
def exp_div_mod(a, n, p):
r = pow(a, n, p*(a-1)) - 1
r = r - 1 if r == -1 else r
return r/(a-1)
(((a ** n) - 1) / (a-1)) % p
can be rewritten as
(((a ** n) - 1) % ((a-1)*p)) / (a-1)
This part:
(((a ** n) - 1) % ((a-1)*p))
can be computed by calculating this:
((a ** n) % ((a-1)*p))
and then adjusting for the -1 afterwards.
Raise a by to the nth power and mod by ((a-1)*p). This can be done using the Python pow() function. Then adjust for the -1 and divide by a-1.
Using the pow() function and passing a modulo value is faster than computing the full exponent and then taking the modulo, because the modulo can be applied to the partial products at each stage of the calculation, which stops the value from getting too large (106 to the power of 106 has 6 million decimal digits, with a modulo applied at each step the values never have to grow larger than the size of the modulo - about 13 digits in this example).
Code:
def exp_div_mod(a, n, p):
m = p * (a - 1)
return ((pow(a, n, m) - 1) % m) // (a - 1);
print exp_div_mod((10**6), (10**6), 1000003)
output:
444446
Note: this approach only works if a, n and p are integers.
(an−1) ⁄ (a−1) is the sum from i = 0 to n−1 of ai.
Computing the latter mod p is straightforward, based on the following:
let F(a, n) be Σ(i=0..n-1){ai} if n > 0, otherwise 0.
Now:
F(a,n) = a×F(a,n−1) + 1
F(a,2n) = (a+1)×F(a2,n)
The second identity is the divide-and-conquer recursion.
Since both of these only involve addition and multiplication, we can compute them mod p without needing an integer type larger than a×p by distributing the modulus operation. (See code below.)
With just the first recursion, we can code an iterative solution:
def sum_of_powers(a, n, p):
sum = 0
for i in range(n): sum = (a * sum + 1) % p
return sum
Using the divide-and-conquer recursion as well, we arrive at something not much more complicated:
def sum_of_powers(a, n, p):
if n % 2 == 1:
return (a * sum_of_powers(a, n-1, p) + 1) % p
elif n > 0:
return ((a + 1) * sum_of_powers(a * a % p, n // 2, p)) % p
else:
return 0
The first solution returns in less than a second with n == 106. The second one returns instantly, even with n as large as 109.
You can multiply by the modular inverse of p - 1. Due to Fermat's little theorem, you have xp-2 · x ≡ xp-1 ≡ 1 (mod p) for all 0 < x < p, so you don't even need extended Euclid to compute the inverse, just the pow function from standard Python:
(pow(a, n, p) - 1) * pow(a - 1, p - 2, p) % p
The algorithm has time complexity 𝒪(log p) because square-and-multiply is used.

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