-
-
Notifications
You must be signed in to change notification settings - Fork 46.6k
Consolidate binary exponentiation files #10742
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
b3f7790
72e21be
b6ca47c
b15c87a
cf6c7d2
c2769e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,148 @@ | ||
"""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 | ||
|
||
def binary_exponentiation(a: int, n: int) -> int: | ||
For modular exponentiation, we use the fact that (a * b) % c = ((a % c) * (b % c)) % c | ||
""" | ||
|
||
|
||
def binary_exp_recursive(base: int, exponent: int) -> int: | ||
""" | ||
Compute a number raised by some quantity | ||
>>> binary_exponentiation(-1, 3) | ||
>>> binary_exp_recursive(3, 5) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about tests for a=big number and n=big number, a=float, n=float? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can do, but the n=float case won't work because the algorithm can only compute integer powers There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it won’t work but I wanted to see how it fails. Does it raise a ValueError? Does it behave like |
||
243 | ||
>>> binary_exp_recursive(-1, 3) | ||
-1 | ||
>>> binary_exponentiation(-1, 4) | ||
>>> binary_exp_recursive(0, 5) | ||
0 | ||
>>> binary_exp_recursive(3, 1) | ||
3 | ||
>>> binary_exp_recursive(3, 0) | ||
1 | ||
>>> binary_exponentiation(2, 2) | ||
4 | ||
>>> binary_exponentiation(3, 5) | ||
>>> binary_exp_recursive(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") | ||
|
||
if exponent == 0: | ||
return 1 | ||
|
||
if exponent % 2 == 1: | ||
return binary_exp_recursive(base, exponent - 1) * base | ||
|
||
b = binary_exp_recursive(base, exponent // 2) | ||
return b * b | ||
|
||
|
||
def binary_exp_iterative(base: int, exponent: int) -> int: | ||
""" | ||
>>> binary_exp_iterative(3, 5) | ||
243 | ||
>>> binary_exponentiation(10, 3) | ||
1000 | ||
>>> binary_exponentiation(5e3, 1) | ||
5000.0 | ||
>>> binary_exponentiation(-5e3, 1) | ||
-5000.0 | ||
""" | ||
if n == 0: | ||
>>> 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(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 = 1 | ||
while exponent > 0: | ||
if exponent & 1: | ||
res *= base | ||
|
||
base *= base | ||
exponent >>= 1 | ||
|
||
return res | ||
|
||
|
||
def binary_exp_mod_recursive(base: int, exponent: int, modulus: int) -> int: | ||
""" | ||
>>> binary_exp_mod_recursive(3, 4, 5) | ||
1 | ||
>>> binary_exp_mod_recursive(7, 13, 10) | ||
7 | ||
>>> 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 | ||
|
||
elif n % 2 == 1: | ||
return binary_exponentiation(a, n - 1) * a | ||
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: int, exponent: int, modulus: int) -> int: | ||
""" | ||
>>> binary_exp_mod_iterative(3, 4, 5) | ||
1 | ||
>>> binary_exp_mod_iterative(7, 13, 10) | ||
7 | ||
>>> 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 = 1 | ||
while exponent > 0: | ||
if exponent & 1: | ||
res = ((res % modulus) * (base % modulus)) % modulus | ||
|
||
base *= base | ||
exponent >>= 1 | ||
|
||
else: | ||
b = binary_exponentiation(a, n // 2) | ||
return b * b | ||
return res | ||
|
||
|
||
if __name__ == "__main__": | ||
import doctest | ||
|
||
doctest.testmod() | ||
|
||
try: | ||
BASE = int(float(input("Enter Base : ").strip())) | ||
POWER = int(input("Enter Power : ").strip()) | ||
except ValueError: | ||
print("Invalid literal for integer") | ||
BASE = int(input("Enter base: ").strip()) | ||
POWER = int(input("Enter power: ").strip()) | ||
|
||
RESULT = binary_exponentiation(BASE, POWER) | ||
print(f"{BASE}^({POWER}) : {RESULT}") | ||
RESULT = binary_exp_recursive(BASE, POWER) | ||
print(f"{BASE}^({POWER}): {RESULT}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OPTIONAL: Adding a |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove this?
exp
is a bit cryptic in the function name and a line of documentation here is useful.