// grug math is an unbounded precision math library for integers. It is not designed to be performant in any means. But as an example of how one works. package math import "strconv" type Number []rune func NewNumber() *Number { return &Number{} } func (*Number) FromString(s string) *Number { for _, a := range s { if !(a >= '0' && a <= '9') { return nil } } var n Number = []rune(s) i:=0 for range n[:len(n)-1] { if n[i] == 0 || n[i] == '0' { i++ } else { break } } n = n[i:] return &n } func (*Number) FromInt(i int) *Number { s := strconv.Itoa(i) var n Number = []rune(s) return &n } func (n *Number) String() string { if n == nil || len(*n) == 0 { return "NaN" } return string(*n) } func (n *Number) Add(a *Number) *Number { if n == nil || a == nil { return nil } lenN, lenA := len(*n), len(*a) sum := make(Number, max(lenN, lenA)+1) for i := range sum[:len(sum)-1] { ii := len(sum) - i - 1 switch { case lenN == lenA: j := (*n)[lenN-i-1] k := (*a)[lenA-i-1] sum[ii-1], sum[ii] = add(j, k, sum[ii]) case lenN > lenA: j := (*n)[lenN-i-1] k := '0' if i < lenA { k = (*a)[lenA-i-1] } sum[ii-1], sum[ii] = add(j, k, sum[ii]) case lenN < lenA: j := '0' if i < lenN { j = (*n)[lenN-i-1] } k := (*a)[lenA-i-1] sum[ii-1], sum[ii] = add(j, k, sum[ii]) } } // Trim the extra 0 if present if sum[0] == 0 || sum[0] == '0' { sum = sum[1:] } return &sum } func (n *Number) Sub(s *Number) *Number { if n == nil || s == nil { return nil } lenN, lenA := len(*n), len(*s) sum := make(Number, max(lenN, lenA)+1) for i := range sum[:len(sum)-1] { ii := len(sum) - i - 1 switch { case lenN == lenA: j := (*n)[lenN-i-1] k := (*s)[lenA-i-1] c := '0' if i+1 < lenN { c = (*n)[lenN-i-2] } sum[ii-1], sum[ii] = sub(j, k, c) case lenN > lenA: j := (*n)[lenN-i-1] k := '0' if i < lenA { k = (*s)[lenA-i-1] } c := '0' if i+1 < lenN { c = (*n)[lenN-i-2] } sum[ii-1], sum[ii] = sub(j, k, c) if i+1 < lenN { (*n)[lenN-i-2] =sum[ii-1] } case lenN < lenA: j := '0' if i < lenN { j = (*n)[lenN-i-1] } k := (*s)[lenA-i-1] c := '0' if i+1 < lenN { c = (*n)[lenN-i-2] } sum[ii-1], sum[ii] = sub(j, k, c) } } // Trim the extra 0 if present i:=0 for range sum[:len(sum)-1] { if sum[i] == 0 || sum[i] == '0' { i++ } else { break } } sum = sum[i:] return &sum } func friends(r rune) (int32, int32) { return 1, 10 - int32(r-'0') } func add(a, b, c rune) (rune, rune) { up, dn := friends(b) if c == 0 { c = '0' } a = a + c - '0' if a-dn < '0' { return '0', a + b - '0' } return c + up, a - dn } func sub(a, b, c rune) (rune, rune) { dn, up := friends(b) if c == 0 { c = '0' } if a+up > '9' { return c, a - b + '0' } return c - dn, a + up }