mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00:00
Consolidate binary exponentiation files (#10742)
* Consolidate binary exponentiation files * updating DIRECTORY.md * Fix typos in doctests * Add suggestions from code review * Fix timeit benchmarks --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
parent
47c19d9b2d
commit
06edc0eea0
|
@ -578,9 +578,7 @@
|
||||||
* [Bailey Borwein Plouffe](maths/bailey_borwein_plouffe.py)
|
* [Bailey Borwein Plouffe](maths/bailey_borwein_plouffe.py)
|
||||||
* [Base Neg2 Conversion](maths/base_neg2_conversion.py)
|
* [Base Neg2 Conversion](maths/base_neg2_conversion.py)
|
||||||
* [Basic Maths](maths/basic_maths.py)
|
* [Basic Maths](maths/basic_maths.py)
|
||||||
* [Binary Exp Mod](maths/binary_exp_mod.py)
|
|
||||||
* [Binary Exponentiation](maths/binary_exponentiation.py)
|
* [Binary Exponentiation](maths/binary_exponentiation.py)
|
||||||
* [Binary Exponentiation 2](maths/binary_exponentiation_2.py)
|
|
||||||
* [Binary Multiplication](maths/binary_multiplication.py)
|
* [Binary Multiplication](maths/binary_multiplication.py)
|
||||||
* [Binomial Coefficient](maths/binomial_coefficient.py)
|
* [Binomial Coefficient](maths/binomial_coefficient.py)
|
||||||
* [Binomial Distribution](maths/binomial_distribution.py)
|
* [Binomial Distribution](maths/binomial_distribution.py)
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
def bin_exp_mod(a: int, n: int, b: int) -> int:
|
|
||||||
"""
|
|
||||||
>>> bin_exp_mod(3, 4, 5)
|
|
||||||
1
|
|
||||||
>>> bin_exp_mod(7, 13, 10)
|
|
||||||
7
|
|
||||||
"""
|
|
||||||
# mod b
|
|
||||||
assert b != 0, "This cannot accept modulo that is == 0"
|
|
||||||
if n == 0:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if n % 2 == 1:
|
|
||||||
return (bin_exp_mod(a, n - 1, b) * a) % b
|
|
||||||
|
|
||||||
r = bin_exp_mod(a, n // 2, b)
|
|
||||||
return (r * r) % b
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
BASE = int(input("Enter Base : ").strip())
|
|
||||||
POWER = int(input("Enter Power : ").strip())
|
|
||||||
MODULO = int(input("Enter Modulo : ").strip())
|
|
||||||
except ValueError:
|
|
||||||
print("Invalid literal for integer")
|
|
||||||
|
|
||||||
print(bin_exp_mod(BASE, POWER, MODULO))
|
|
|
@ -1,48 +1,196 @@
|
||||||
"""Binary Exponentiation."""
|
"""
|
||||||
|
Binary Exponentiation
|
||||||
|
|
||||||
# Author : Junth Basnet
|
This is a method to find a^b in O(log b) time complexity and is one of the most commonly
|
||||||
# Time Complexity : O(logn)
|
used methods of exponentiation. The method is also useful for modular exponentiation,
|
||||||
|
when the solution to (a^b) % c is required.
|
||||||
|
|
||||||
|
To calculate a^b:
|
||||||
|
- If b is even, then a^b = (a * a)^(b / 2)
|
||||||
|
- If b is odd, then a^b = a * a^(b - 1)
|
||||||
|
Repeat until b = 1 or b = 0
|
||||||
|
|
||||||
|
For modular exponentiation, we use the fact that (a * b) % c = ((a % c) * (b % c)) % c
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def binary_exponentiation(a: int, n: int) -> int:
|
def binary_exp_recursive(base: float, exponent: int) -> float:
|
||||||
"""
|
"""
|
||||||
Compute a number raised by some quantity
|
Computes a^b recursively, where a is the base and b is the exponent
|
||||||
>>> binary_exponentiation(-1, 3)
|
|
||||||
-1
|
>>> binary_exp_recursive(3, 5)
|
||||||
>>> binary_exponentiation(-1, 4)
|
|
||||||
1
|
|
||||||
>>> binary_exponentiation(2, 2)
|
|
||||||
4
|
|
||||||
>>> binary_exponentiation(3, 5)
|
|
||||||
243
|
243
|
||||||
>>> binary_exponentiation(10, 3)
|
>>> binary_exp_recursive(11, 13)
|
||||||
1000
|
34522712143931
|
||||||
>>> binary_exponentiation(5e3, 1)
|
>>> binary_exp_recursive(-1, 3)
|
||||||
5000.0
|
-1
|
||||||
>>> binary_exponentiation(-5e3, 1)
|
>>> binary_exp_recursive(0, 5)
|
||||||
-5000.0
|
0
|
||||||
|
>>> binary_exp_recursive(3, 1)
|
||||||
|
3
|
||||||
|
>>> binary_exp_recursive(3, 0)
|
||||||
|
1
|
||||||
|
>>> binary_exp_recursive(1.5, 4)
|
||||||
|
5.0625
|
||||||
|
>>> binary_exp_recursive(3, -1)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Exponent must be a non-negative integer
|
||||||
"""
|
"""
|
||||||
if n == 0:
|
if exponent < 0:
|
||||||
|
raise ValueError("Exponent must be a non-negative integer")
|
||||||
|
|
||||||
|
if exponent == 0:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
elif n % 2 == 1:
|
if exponent % 2 == 1:
|
||||||
return binary_exponentiation(a, n - 1) * a
|
return binary_exp_recursive(base, exponent - 1) * base
|
||||||
|
|
||||||
else:
|
b = binary_exp_recursive(base, exponent // 2)
|
||||||
b = binary_exponentiation(a, n // 2)
|
return b * b
|
||||||
return b * b
|
|
||||||
|
|
||||||
|
def binary_exp_iterative(base: float, exponent: int) -> float:
|
||||||
|
"""
|
||||||
|
Computes a^b iteratively, where a is the base and b is the exponent
|
||||||
|
|
||||||
|
>>> binary_exp_iterative(3, 5)
|
||||||
|
243
|
||||||
|
>>> binary_exp_iterative(11, 13)
|
||||||
|
34522712143931
|
||||||
|
>>> binary_exp_iterative(-1, 3)
|
||||||
|
-1
|
||||||
|
>>> binary_exp_iterative(0, 5)
|
||||||
|
0
|
||||||
|
>>> binary_exp_iterative(3, 1)
|
||||||
|
3
|
||||||
|
>>> binary_exp_iterative(3, 0)
|
||||||
|
1
|
||||||
|
>>> binary_exp_iterative(1.5, 4)
|
||||||
|
5.0625
|
||||||
|
>>> binary_exp_iterative(3, -1)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Exponent must be a non-negative integer
|
||||||
|
"""
|
||||||
|
if exponent < 0:
|
||||||
|
raise ValueError("Exponent must be a non-negative integer")
|
||||||
|
|
||||||
|
res: int | float = 1
|
||||||
|
while exponent > 0:
|
||||||
|
if exponent & 1:
|
||||||
|
res *= base
|
||||||
|
|
||||||
|
base *= base
|
||||||
|
exponent >>= 1
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def binary_exp_mod_recursive(base: float, exponent: int, modulus: int) -> float:
|
||||||
|
"""
|
||||||
|
Computes a^b % c recursively, where a is the base, b is the exponent, and c is the
|
||||||
|
modulus
|
||||||
|
|
||||||
|
>>> binary_exp_mod_recursive(3, 4, 5)
|
||||||
|
1
|
||||||
|
>>> binary_exp_mod_recursive(11, 13, 7)
|
||||||
|
4
|
||||||
|
>>> binary_exp_mod_recursive(1.5, 4, 3)
|
||||||
|
2.0625
|
||||||
|
>>> binary_exp_mod_recursive(7, -1, 10)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Exponent must be a non-negative integer
|
||||||
|
>>> binary_exp_mod_recursive(7, 13, 0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Modulus must be a positive integer
|
||||||
|
"""
|
||||||
|
if exponent < 0:
|
||||||
|
raise ValueError("Exponent must be a non-negative integer")
|
||||||
|
if modulus <= 0:
|
||||||
|
raise ValueError("Modulus must be a positive integer")
|
||||||
|
|
||||||
|
if exponent == 0:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if exponent % 2 == 1:
|
||||||
|
return (binary_exp_mod_recursive(base, exponent - 1, modulus) * base) % modulus
|
||||||
|
|
||||||
|
r = binary_exp_mod_recursive(base, exponent // 2, modulus)
|
||||||
|
return (r * r) % modulus
|
||||||
|
|
||||||
|
|
||||||
|
def binary_exp_mod_iterative(base: float, exponent: int, modulus: int) -> float:
|
||||||
|
"""
|
||||||
|
Computes a^b % c iteratively, where a is the base, b is the exponent, and c is the
|
||||||
|
modulus
|
||||||
|
|
||||||
|
>>> binary_exp_mod_iterative(3, 4, 5)
|
||||||
|
1
|
||||||
|
>>> binary_exp_mod_iterative(11, 13, 7)
|
||||||
|
4
|
||||||
|
>>> binary_exp_mod_iterative(1.5, 4, 3)
|
||||||
|
2.0625
|
||||||
|
>>> binary_exp_mod_iterative(7, -1, 10)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Exponent must be a non-negative integer
|
||||||
|
>>> binary_exp_mod_iterative(7, 13, 0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Modulus must be a positive integer
|
||||||
|
"""
|
||||||
|
if exponent < 0:
|
||||||
|
raise ValueError("Exponent must be a non-negative integer")
|
||||||
|
if modulus <= 0:
|
||||||
|
raise ValueError("Modulus must be a positive integer")
|
||||||
|
|
||||||
|
res: int | float = 1
|
||||||
|
while exponent > 0:
|
||||||
|
if exponent & 1:
|
||||||
|
res = ((res % modulus) * (base % modulus)) % modulus
|
||||||
|
|
||||||
|
base *= base
|
||||||
|
exponent >>= 1
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
from timeit import timeit
|
||||||
|
|
||||||
doctest.testmod()
|
a = 1269380576
|
||||||
|
b = 374
|
||||||
|
c = 34
|
||||||
|
|
||||||
try:
|
runs = 100_000
|
||||||
BASE = int(float(input("Enter Base : ").strip()))
|
print(
|
||||||
POWER = int(input("Enter Power : ").strip())
|
timeit(
|
||||||
except ValueError:
|
f"binary_exp_recursive({a}, {b})",
|
||||||
print("Invalid literal for integer")
|
setup="from __main__ import binary_exp_recursive",
|
||||||
|
number=runs,
|
||||||
RESULT = binary_exponentiation(BASE, POWER)
|
)
|
||||||
print(f"{BASE}^({POWER}) : {RESULT}")
|
)
|
||||||
|
print(
|
||||||
|
timeit(
|
||||||
|
f"binary_exp_iterative({a}, {b})",
|
||||||
|
setup="from __main__ import binary_exp_iterative",
|
||||||
|
number=runs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
timeit(
|
||||||
|
f"binary_exp_mod_recursive({a}, {b}, {c})",
|
||||||
|
setup="from __main__ import binary_exp_mod_recursive",
|
||||||
|
number=runs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
timeit(
|
||||||
|
f"binary_exp_mod_iterative({a}, {b}, {c})",
|
||||||
|
setup="from __main__ import binary_exp_mod_iterative",
|
||||||
|
number=runs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
"""
|
|
||||||
Binary Exponentiation
|
|
||||||
This is a method to find a^b in O(log b) time complexity
|
|
||||||
This is one of the most commonly used methods of exponentiation
|
|
||||||
It's also useful when the solution to (a^b) % c is required because a, b, c may be
|
|
||||||
over the computer's calculation limits
|
|
||||||
|
|
||||||
Let's say you need to calculate a ^ b
|
|
||||||
- RULE 1 : a ^ b = (a*a) ^ (b/2) ---- example : 4 ^ 4 = (4*4) ^ (4/2) = 16 ^ 2
|
|
||||||
- RULE 2 : IF b is odd, then a ^ b = a * (a ^ (b - 1)), where b - 1 is even
|
|
||||||
Once b is even, repeat the process until b = 1 or b = 0, because a^1 = a and a^0 = 1
|
|
||||||
|
|
||||||
For modular exponentiation, we use the fact that (a*b) % c = ((a%c) * (b%c)) % c
|
|
||||||
Now apply RULE 1 or 2 as required
|
|
||||||
|
|
||||||
@author chinmoy159
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def b_expo(a: int, b: int) -> int:
|
|
||||||
"""
|
|
||||||
>>> b_expo(2, 10)
|
|
||||||
1024
|
|
||||||
>>> b_expo(9, 0)
|
|
||||||
1
|
|
||||||
>>> b_expo(0, 12)
|
|
||||||
0
|
|
||||||
>>> b_expo(4, 12)
|
|
||||||
16777216
|
|
||||||
"""
|
|
||||||
res = 1
|
|
||||||
while b > 0:
|
|
||||||
if b & 1:
|
|
||||||
res *= a
|
|
||||||
|
|
||||||
a *= a
|
|
||||||
b >>= 1
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def b_expo_mod(a: int, b: int, c: int) -> int:
|
|
||||||
"""
|
|
||||||
>>> b_expo_mod(2, 10, 1000000007)
|
|
||||||
1024
|
|
||||||
>>> b_expo_mod(11, 13, 19)
|
|
||||||
11
|
|
||||||
>>> b_expo_mod(0, 19, 20)
|
|
||||||
0
|
|
||||||
>>> b_expo_mod(15, 5, 4)
|
|
||||||
3
|
|
||||||
"""
|
|
||||||
res = 1
|
|
||||||
while b > 0:
|
|
||||||
if b & 1:
|
|
||||||
res = ((res % c) * (a % c)) % c
|
|
||||||
|
|
||||||
a *= a
|
|
||||||
b >>= 1
|
|
||||||
|
|
||||||
return res
|
|
Loading…
Reference in New Issue
Block a user