Task: Balanced ternary

C: #include <stdio.h>
#include <string.h>

void reverse(char *p) {
    size_t len = strlen(p);
    char *r = p + len - 1;
    while (p < r) {
        *p ^= *r;
        *r ^= *p;
        *p++ ^= *r--;
    }
}

void to_bt(int n, char *b) {
    static char d[] = { '0', '+', '-' };
    static int v[] = { 0, 1, -1 };

    char *ptr = b;
    *ptr = 0;

    while (n) {
        int r = n % 3;
        if (r < 0) {
            r += 3;
        }

        *ptr = d[r];
        *(++ptr) = 0;

        n -= v[r];
        n /= 3;
    }

    reverse(b);
}

int from_bt(const char *a) {
    int n = 0;

    while (*a != '\0') {
        n *= 3;
        if (*a == '+') {
            n++;
        } else if (*a == '-') {
            n--;
        }
        a++;
    }

    return n;
}

char last_char(char *ptr) {
    char c;

    if (ptr == NULL || *ptr == '\0') {
        return '\0';
    }

    while (*ptr != '\0') {
        ptr++;
    }
    ptr--;

    c = *ptr;
    *ptr = 0;
    return c;
}

void add(const char *b1, const char *b2, char *out) {
    if (*b1 != '\0' && *b2 != '\0') {
        char c1[16];
        char c2[16];
        char ob1[16];
        char ob2[16];
        char d[3] = { 0, 0, 0 };
        char L1, L2;

        strcpy(c1, b1);
        strcpy(c2, b2);
        L1 = last_char(c1);
        L2 = last_char(c2);
        if (L2 < L1) {
            L2 ^= L1;
            L1 ^= L2;
            L2 ^= L1;
        }

        if (L1 == '-') {
            if (L2 == '0') {
                d[0] = '-';
            }
            if (L2 == '-') {
                d[0] = '+';
                d[1] = '-';
            }
        }
        if (L1 == '+') {
            if (L2 == '0') {
                d[0] = '+';
            }
            if (L2 == '-') {
                d[0] = '0';
            }
            if (L2 == '+') {
                d[0] = '-';
                d[1] = '+';
            }
        }
        if (L1 == '0') {
            if (L2 == '0') {
                d[0] = '0';
            }
        }

        add(c1, &d[1], ob1);
        add(ob1, c2, ob2);
        strcpy(out, ob2);

        d[1] = 0;
        strcat(out, d);
    } else if (*b1 != '\0') {
        strcpy(out, b1);
    } else if (*b2 != '\0') {
        strcpy(out, b2);
    } else {
        *out = '\0';
    }
}

void unary_minus(const char *b, char *out) {
    while (*b != '\0') {
        if (*b == '-') {
            *out++ = '+';
            b++;
        } else if (*b == '+') {
            *out++ = '-';
            b++;
        } else {
            *out++ = *b++;
        }
    }
    *out = '\0';
}

void subtract(const char *b1, const char *b2, char *out) {
    char buf[16];
    unary_minus(b2, buf);
    add(b1, buf, out);
}

void mult(const char *b1, const char *b2, char *out) {
    char r[16] = "0";
    char t[16];
    char c1[16];
    char c2[16];
    char *ptr = c2;

    strcpy(c1, b1);
    strcpy(c2, b2);

    reverse(c2);

    while (*ptr != '\0') {
        if (*ptr == '+') {
            add(r, c1, t);
            strcpy(r, t);
        }
        if (*ptr == '-') {
            subtract(r, c1, t);
            strcpy(r, t);
        }
        strcat(c1, "0");

        ptr++;
    }

    ptr = r;
    while (*ptr == '0') {
        ptr++;
    }
    strcpy(out, ptr);
}

int main() {
    const char *a = "+-0++0+";
    char b[16];
    const char *c = "+-++-";
    char t[16];
    char d[16];

    to_bt(-436, b);
    subtract(b, c, t);
    mult(a, t, d);

    printf("      a: %14s %10d\n", a, from_bt(a));
    printf("      b: %14s %10d\n", b, from_bt(b));
    printf("      c: %14s %10d\n", c, from_bt(c));
    printf("a*(b-c): %14s %10d\n", d, from_bt(d));

    return 0;
}




Go: package main

import (
    "fmt"
    "strings"
)




type bt []int8







func btString(s string) (*bt, bool) {
    s = strings.TrimLeft(s, "0")
    b := make(bt, len(s))
    for i, last := 0, len(s)-1; i < len(s); i++ {
        switch s[i] {
        case '-':
            b[last-i] = -1
        case '0':
            b[last-i] = 0
        case '+':
            b[last-i] = 1
        default:
            return nil, false
        }
    }
    return &b, true
}



func (b bt) String() string {
    if len(b) == 0 {
        return "0"
    }
    last := len(b) - 1
    r := make([]byte, len(b))
    for i, d := range b {
        r[last-i] = "-0+"[d+1]
    }
    return string(r)
}





func btInt(i int) *bt {
    if i == 0 {
        return new(bt)
    }
    var b bt
    var btDigit func(int)
    btDigit = func(digit int) {
        m := int8(i % 3)
        i /= 3
        switch m {
        case 2:
            m = -1
            i++
        case -2:
            m = 1
            i--
        }
        if i == 0 {
            b = make(bt, digit+1)
        } else {
            btDigit(digit + 1)
        }
        b[digit] = m
    }
    btDigit(0)
    return &b
}





func (b bt) Int() (r int, ok bool) {
    pt := 1
    for _, d := range b {
        dp := int(d) * pt
        neg := r < 0
        r += dp
        if neg {
            if r > dp {
                return 0, false
            }
        } else {
            if r < dp {
                return 0, false
            }
        }
        pt *= 3
    }
    return r, true
}


    
func (z *bt) Neg(b *bt) *bt {
    if z != b {
        if cap(*z) < len(*b) {
            *z = make(bt, len(*b))
        } else {
            *z = (*z)[:len(*b)]
        } 
    }
    for i, d := range *b {
        (*z)[i] = -d
    }
    return z 
}

func (z *bt) Add(a, b *bt) *bt {
    if len(*a) < len(*b) {
        a, b = b, a
    }
    r := *z
    r = r[:cap(r)]
    var carry int8 
    for i, da := range *a {
        if i == len(r) {
            n := make(bt, len(*a)+4)
            copy(n, r)
            r = n
        }
        sum := da + carry
        if i < len(*b) {
            sum += (*b)[i]
        }
        carry = sum / 3
        sum %= 3
        switch {
        case sum > 1:
            sum -= 3
            carry++
        case sum < -1:
            sum += 3
            carry--
        } 
        r[i] = sum 
    }
    last := len(*a)
    if carry != 0 {
        if len(r) == last {
            n := make(bt, last+4)
            copy(n, r)
            r = n
        }
        r[last] = carry
        *z = r[:last+1]
        return z
    }
    for {
        if last == 0 {
            *z = nil
            break
        }
        last--
        if r[last] != 0 {
            *z = r[:last+1]
            break
        }
    }
    return z
}

func (z *bt) Mul(a, b *bt) *bt {
    if len(*a) < len(*b) {
        a, b = b, a
    }
    var na bt
    for _, d := range *b {
        if d == -1 {
            na.Neg(a)
            break
        }
    }
    r := make(bt, len(*a)+len(*b))
    for i := len(*b) - 1; i >= 0; i-- {
        switch (*b)[i] {
        case 1:
            p := r[i:]
            p.Add(&p, a)
        case -1:
            p := r[i:]
            p.Add(&p, &na)
        }
    }
    i := len(r)
    for i > 0 && r[i-1] == 0 {
        i--
    }
    *z = r[:i]
    return z
}

func main() {
    a, _ := btString("+-0++0+")
    b := btInt(-436)
    c, _ := btString("+-++-")
    show("a:", a) 
    show("b:", b)
    show("c:", c)
    show("a(b-c):", a.Mul(a, b.Add(b, c.Neg(c))))
}   

func show(label string, b *bt) {
    fmt.Printf("%7s %12v ", label, b)
    if i, ok := b.Int(); ok {
        fmt.Printf("%7d\n", i)
    } else {
        fmt.Println("int overflow")
    }
}