mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-23 21:11: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)
|
||||
* [Base Neg2 Conversion](maths/base_neg2_conversion.py)
|
||||
* [Basic Maths](maths/basic_maths.py)
|
||||
* [Binary Exp Mod](maths/binary_exp_mod.py)
|
||||
* [Binary Exponentiation](maths/binary_exponentiation.py)
|
||||
* [Binary Exponentiation 2](maths/binary_exponentiation_2.py)
|
||||
* [Binary Multiplication](maths/binary_multiplication.py)
|
||||
* [Binomial Coefficient](maths/binomial_coefficient.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
|
||||
# Time Complexity : O(logn)
|
||||
This is a method to find a^b in O(log b) time complexity and is one of the most commonly
|
||||
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
|
||||
>>> binary_exponentiation(-1, 3)
|
||||
-1
|
||||
>>> binary_exponentiation(-1, 4)
|
||||
1
|
||||
>>> binary_exponentiation(2, 2)
|
||||
4
|
||||
>>> binary_exponentiation(3, 5)
|
||||
Computes a^b recursively, where a is the base and b is the exponent
|
||||
|
||||
>>> binary_exp_recursive(3, 5)
|
||||
243
|
||||
>>> binary_exponentiation(10, 3)
|
||||
1000
|
||||
>>> binary_exponentiation(5e3, 1)
|
||||
5000.0
|
||||
>>> binary_exponentiation(-5e3, 1)
|
||||
-5000.0
|
||||
>>> binary_exp_recursive(11, 13)
|
||||
34522712143931
|
||||
>>> binary_exp_recursive(-1, 3)
|
||||
-1
|
||||
>>> binary_exp_recursive(0, 5)
|
||||
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
|
||||
|
||||
elif n % 2 == 1:
|
||||
return binary_exponentiation(a, n - 1) * a
|
||||
if exponent % 2 == 1:
|
||||
return binary_exp_recursive(base, exponent - 1) * base
|
||||
|
||||
else:
|
||||
b = binary_exponentiation(a, n // 2)
|
||||
b = binary_exp_recursive(base, exponent // 2)
|
||||
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__":
|
||||
import doctest
|
||||
from timeit import timeit
|
||||
|
||||
doctest.testmod()
|
||||
a = 1269380576
|
||||
b = 374
|
||||
c = 34
|
||||
|
||||
try:
|
||||
BASE = int(float(input("Enter Base : ").strip()))
|
||||
POWER = int(input("Enter Power : ").strip())
|
||||
except ValueError:
|
||||
print("Invalid literal for integer")
|
||||
|
||||
RESULT = binary_exponentiation(BASE, POWER)
|
||||
print(f"{BASE}^({POWER}) : {RESULT}")
|
||||
runs = 100_000
|
||||
print(
|
||||
timeit(
|
||||
f"binary_exp_recursive({a}, {b})",
|
||||
setup="from __main__ import binary_exp_recursive",
|
||||
number=runs,
|
||||
)
|
||||
)
|
||||
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