Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,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)
Expand Down
28 changes: 0 additions & 28 deletions maths/binary_exp_mod.py

This file was deleted.

160 changes: 130 additions & 30 deletions maths/binary_exponentiation.py
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
Copy link
Member

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.

>>> binary_exponentiation(-1, 3)
>>> binary_exp_recursive(3, 5)
Copy link
Member

@cclauss cclauss Oct 21, 2023

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

Copy link
Member

Choose a reason for hiding this comment

The 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 pow() does. Testing how things work if half the battle. Watching them fail is just as cool.

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}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPTIONAL: Adding a timeit benchmark would be a nice addition. Visitors love to see the side-by-side bakeoff.

61 changes: 0 additions & 61 deletions maths/binary_exponentiation_2.py

This file was deleted.