116 lines
2.1 KiB
Go
116 lines
2.1 KiB
Go
package multiplystrings
|
|
|
|
func addDigits(a, b byte) (byte, byte) {
|
|
abInt := int(a-'0') + int(b-'0')
|
|
return byte(abInt/10) + '0', byte(abInt%10) + '0'
|
|
}
|
|
|
|
func addByDigit(dst *[]byte, src byte) {
|
|
for i, b := range *dst {
|
|
if src == '0' {
|
|
return
|
|
}
|
|
|
|
src, (*dst)[i] = addDigits(b, src)
|
|
}
|
|
|
|
if src != '0' {
|
|
*dst = append(*dst, src)
|
|
}
|
|
}
|
|
|
|
func add(dst *[]byte, src []byte) {
|
|
carry := byte('0')
|
|
|
|
for i := range max(len(*dst), len(src)) {
|
|
d, s := byte('0'), byte('0')
|
|
if len(*dst) > i {
|
|
d = (*dst)[i]
|
|
}
|
|
if len(src) > i {
|
|
s = src[i]
|
|
}
|
|
|
|
hi, lo := addDigits(d, s)
|
|
total := []byte{lo, hi}
|
|
addByDigit(&total, carry)
|
|
(*dst)[i], carry = total[0], total[1]
|
|
}
|
|
|
|
if carry != '0' {
|
|
*dst = append(*dst, carry)
|
|
}
|
|
}
|
|
|
|
func multiplyDigits(a, b byte) (byte, byte) {
|
|
abInt := int(a-'0') * int(b-'0')
|
|
return byte(abInt/10) + '0', byte(abInt%10) + '0'
|
|
}
|
|
|
|
func multiplyByDigit(and []byte, ier byte) []byte {
|
|
result, carry := []byte{}, byte('0')
|
|
for _, b := range and {
|
|
hi, lo := multiplyDigits(b, ier)
|
|
|
|
// Fold the incoming carry into the low digit; any overflow rolls
|
|
// into hi, which is small enough that it never overflows again.
|
|
c, lo := addDigits(lo, carry)
|
|
_, carry = addDigits(hi, c)
|
|
|
|
result = append(result, lo)
|
|
}
|
|
|
|
if carry != '0' {
|
|
result = append(result, carry)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func reverse(s string) []byte {
|
|
digits := make([]byte, len(s))
|
|
for i := range s {
|
|
digits[len(s)-1-i] = s[i]
|
|
}
|
|
|
|
return digits
|
|
}
|
|
|
|
func multiply(a, b string) string {
|
|
if a == "0" || b == "0" {
|
|
return "0"
|
|
}
|
|
|
|
and := reverse(a)
|
|
result := make([]byte, len(a)+len(b))
|
|
for i := range result {
|
|
result[i] = '0'
|
|
}
|
|
|
|
for i := range len(b) {
|
|
ier := b[len(b)-1-i]
|
|
partial := multiplyByDigit(and, ier)
|
|
|
|
// Shift left by i places (little-endian: i leading zeros).
|
|
shifted := make([]byte, i+len(partial))
|
|
for j := range i {
|
|
shifted[j] = '0'
|
|
}
|
|
copy(shifted[i:], partial)
|
|
|
|
add(&result, shifted)
|
|
}
|
|
|
|
end := len(result)
|
|
for end > 1 && result[end-1] == '0' {
|
|
end--
|
|
}
|
|
|
|
out := make([]byte, end)
|
|
for i := range end {
|
|
out[i] = result[end-1-i]
|
|
}
|
|
|
|
return string(out)
|
|
}
|