-
Notifications
You must be signed in to change notification settings - Fork 1
/
karatsuba.go
124 lines (100 loc) · 2.22 KB
/
karatsuba.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package karatsuba
import (
"math"
"strconv"
"strings"
)
// Multiply takes in two numbers and recursively multiplies them
func Multiply(a, b string) string {
// base case, single digit number
if len(a) < 2 || len(b) < 2 {
intA, _ := strconv.Atoi(a)
intB, _ := strconv.Atoi(b)
return strconv.Itoa(intA * intB)
}
if len(a)%2 == 1 {
a = "0" + a
}
if len(b)%2 == 1 {
b = "0" + b
}
// added to fix uneven length factors
a, b = addZeroFront(a, b)
// split strings at middle index
m := getMiddle(a, b)
high1, low1 := splitNum(a, m)
high2, low2 := splitNum(b, m)
// recursive calls
z0 := Multiply(low1, low2)
z1 := Multiply(add(low1, high1), add(low2, high2))
z2 := Multiply(high1, high2)
t0 := sub(sub(z1, z2), z0)
t1 := add(addZeroEnd(z0, m*2), addZeroEnd(t0, m))
t2 := add(t1, z2)
return trim(t2)
}
func getMiddle(a, b string) int {
m := math.Max(float64(len(a)), float64(len(b)))
return int(m / 2)
}
func splitNum(s string, m int) (string, string) {
high := s[m:]
low := s[:m]
return high, low
}
func addZeroFront(a, b string) (string, string) {
if len(a) < len(b) {
a = strings.Repeat("0", len(b)-len(a)) + a
} else {
b = strings.Repeat("0", len(a)-len(b)) + b
}
return a, b
}
func addZeroEnd(s string, m int) string {
return s + strings.Repeat("0", m)
}
func trim(s string) string {
for s[:1] == "0" && len(s) > 1 {
s = s[1:]
}
return s
}
func add(a, b string) string {
var sum string
var carry int
a, b = addZeroFront(a, b)
for i := len(a) - 1; i >= 0; i-- {
intA, _ := strconv.Atoi(a[i : i+1])
intB, _ := strconv.Atoi(b[i : i+1])
sumDigit := intA + intB + carry
carry = 0
if sumDigit >= 10 {
sumDigit -= 10
carry = 1
}
sum = strconv.Itoa(sumDigit) + sum
}
// handle carry after for-loop terminates
if carry != 0 {
return strconv.Itoa(carry) + sum
}
return sum
}
// does not work with negative number results
func sub(a, b string) string {
var sum string
var carry int
a, b = addZeroFront(a, b)
for i := len(a) - 1; i >= 0; i-- {
intA, _ := strconv.Atoi(a[i : i+1])
intB, _ := strconv.Atoi(b[i : i+1])
var sumDigit = intA - intB - carry
carry = 0
if sumDigit < 0 {
sumDigit += 10
carry = 1
}
sum = strconv.Itoa(sumDigit) + sum
}
return sum
}