Skip to content

Commit 21381ac

Browse files
tjgurwara99github-actions
andauthored
feat: Added a proper Modular Exponentiation algorithm (#275)
* fix: the algorithm handle for go get command * fix: changed the required import from my repo (tjgurwara99/Go) to the algorithms repo (TheAlgorithms/Go) * fix: typo * feat: Global Modular Exponentiation for uses in other files * fix: updated comment * updating DIRECTORY.md * fix: changed the benchmarking for a proper test * fix: better error handling * fix: removed unused type struct Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
1 parent c74c9b1 commit 21381ac

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

DIRECTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
* Gcd
7070
* [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go)
7171
* [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go)
72+
* Modulararithmetic
73+
* [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go)
74+
* [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go)
7275
* Power
7376
* [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go)
7477
* [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package modulararithmetic
2+
3+
import (
4+
"errors"
5+
"math"
6+
)
7+
8+
// ErrorIntOverflow For asserting that the values do not overflow in Int64
9+
var ErrorIntOverflow = errors.New("Integer Overflow")
10+
11+
// ErrorNegativeExponent for asserting that the exponent we receive is positive
12+
var ErrorNegativeExponent = errors.New("Negative Exponent Provided")
13+
14+
// ModularExponentiation returns base^exponent % mod
15+
func ModularExponentiation(base, exponent, mod int64) (int64, error) {
16+
if mod == 1 {
17+
return 0, nil
18+
}
19+
20+
if exponent < 0 {
21+
return -1, ErrorNegativeExponent
22+
}
23+
_, err := Multiply64BitInt(mod-1, mod-1)
24+
25+
if err != nil {
26+
return -1, err
27+
}
28+
29+
var result int64 = 1
30+
31+
base = base % mod
32+
33+
for exponent > 0 {
34+
if exponent%2 == 1 {
35+
result = (result * base) % mod
36+
}
37+
exponent = exponent >> 1
38+
base = (base * base) % mod
39+
}
40+
return result, nil
41+
}
42+
43+
// Multiply64BitInt Checking if the integer multiplication overflows
44+
func Multiply64BitInt(left, right int64) (int64, error) {
45+
if math.Abs(float64(left)) > float64(math.MaxInt64)/math.Abs(float64(right)) {
46+
return 0, ErrorIntOverflow
47+
}
48+
return left * right, nil
49+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package modulararithmetic
2+
3+
import "testing"
4+
5+
type cases struct {
6+
name string
7+
description string
8+
base int64
9+
exponent int64
10+
mod int64
11+
expected int64
12+
expectedError error
13+
}
14+
15+
var testCases = []cases{
16+
{
17+
name: "Test 1",
18+
description: "Test 1: 3^6 % 3 == 0",
19+
base: 3,
20+
exponent: 6,
21+
mod: 3,
22+
expected: 0,
23+
expectedError: nil,
24+
},
25+
{
26+
name: "Test 2",
27+
description: "Test 2: 33^60 % 25 == 1",
28+
base: 33,
29+
exponent: 60,
30+
mod: 25,
31+
expected: 1,
32+
expectedError: nil,
33+
},
34+
{
35+
name: "Test 3",
36+
description: "Test 3: 17^60 % 23 == 2",
37+
base: 17,
38+
exponent: 60,
39+
mod: 23,
40+
expected: 2,
41+
expectedError: nil,
42+
},
43+
{
44+
name: "Test 4",
45+
description: "Test 4: 17^60 % 1 == 0", // handling result when we get mod = 1
46+
base: 17,
47+
exponent: 60,
48+
mod: 1,
49+
expected: 0,
50+
expectedError: nil,
51+
},
52+
{
53+
name: "Error test 1",
54+
description: "Testing whether we receive the expected errors gracefully",
55+
base: 50,
56+
exponent: -1,
57+
mod: 2,
58+
expected: -1,
59+
expectedError: ErrorNegativeExponent,
60+
},
61+
}
62+
63+
func TestModularExponentiation(t *testing.T) {
64+
for _, test := range testCases {
65+
t.Run(test.name, func(t *testing.T) {
66+
result, err := ModularExponentiation(test.base, test.exponent, test.mod)
67+
if err != test.expectedError {
68+
t.Logf("Test Failed for %s", test.name)
69+
t.Logf("Unexpected error occured")
70+
t.Errorf("Expected error: %v, Recieved error: %v", test.expectedError, err)
71+
}
72+
if result != test.expected {
73+
t.Logf("Test Failed for %s", test.description)
74+
t.Fatalf("Expected: %d, Recieved: %d", test.expected, result)
75+
}
76+
})
77+
}
78+
}
79+
80+
func BenchmarkModularExponentiation(b *testing.B) {
81+
for i := 0; i < b.N; i++ {
82+
_, _ = ModularExponentiation(17, 60, 23)
83+
}
84+
}

0 commit comments

Comments
 (0)