Task: Balanced ternary


C++: #include <iostream>
#include <string>
#include <climits>
using namespace std;

class BalancedTernary {
protected:
	
	string value;

	
	int charToInt(char c) const {
		if (c == '0')
			return 0;
		return 44 - c;
	}

	
	string negate(string s) const {
		for (int i = 0; i < s.length(); ++i) {
			if (s[i] == '+')
				s[i] = '-';
			else if (s[i] == '-')
				s[i] = '+';
		}
		return s;
	}

public:
	
	BalancedTernary() {
		value = "0";
	}

	
	BalancedTernary(string s) {
		value = string(s.rbegin(), s.rend());
	}

	
	BalancedTernary(long long n) {
		if (n == 0) {
			value = "0";
			return;
		}

		bool neg = n < 0;
		if (neg) 
			n = -n;

		value = "";
		while (n != 0) {
			int r = n % 3;
			if (r == 0)
				value += "0";
			else if (r == 1)
				value += "+";
			else {
				value += "-";
				++n;
			}

			n /= 3;
		}

		if (neg)
			value = negate(value);
	}

	
	BalancedTernary(const BalancedTernary &n) {
		value = n.value;
	}

	
	BalancedTernary operator+(BalancedTernary n) const {
		n += *this;
		return n;
	}

	BalancedTernary& operator+=(const BalancedTernary &n) {
		static char *add = "0+-0+-0";
		static char *carry = "--000++";

		int lastNonZero = 0;
		char c = '0';
		for (int i = 0; i < value.length() || i < n.value.length(); ++i) {
			char a = i < value.length() ? value[i] : '0';
			char b = i < n.value.length() ? n.value[i] : '0';

			int sum = charToInt(a) + charToInt(b) + charToInt(c) + 3;
			c = carry[sum];

			if (i < value.length())
				value[i] = add[sum];
			else
				value += add[sum];

			if (add[sum] != '0')
				lastNonZero = i;
		}

		if (c != '0')
			value += c;
		else
			value = value.substr(0, lastNonZero + 1); 

		return *this;
	}

	
	BalancedTernary operator-() const {
		BalancedTernary result;
		result.value = negate(value);
		return result;
	}

	
	BalancedTernary operator-(const BalancedTernary &n) const {
		return operator+(-n);
	}

	BalancedTernary& operator-=(const BalancedTernary &n) {
		return operator+=(-n);
	}

	
	BalancedTernary operator*(BalancedTernary n) const {
		n *= *this;
		return n;
	}

	BalancedTernary& operator*=(const BalancedTernary &n) {
		BalancedTernary pos = *this;
		BalancedTernary neg = -pos; 
		value = "0";

		for (int i = 0; i < n.value.length(); ++i) {
			if (n.value[i] == '+')
				operator+=(pos);
			else if (n.value[i] == '-')
				operator+=(neg);
			pos.value = '0' + pos.value;
			neg.value = '0' + neg.value;
		}

		return *this;
	}

	
	friend ostream& operator<<(ostream &out, const BalancedTernary &n) {
		out << n.toString();
		return out;
	}

	
	string toString() const {
		return string(value.rbegin(), value.rend());
	}

	
	long long toInt() const {
		long long result = 0;
		for (long long i = 0, pow = 1; i < value.length(); ++i, pow *= 3)
			result += pow * charToInt(value[i]);
		return result;
	}

	
	bool tryInt(long long &out) const {
		long long result = 0;
		bool ok = true;

		for (long long i = 0, pow = 1; i < value.length() && ok; ++i, pow *= 3) {
			if (value[i] == '+') {
				ok &= LLONG_MAX - pow >= result; 
				result += pow;
			} else if (value[i] == '-') {
				ok &= LLONG_MIN + pow <= result; 
				result -= pow;
			}
		}

		if (ok)
			out = result;
		return ok;
	}
};

int main() {
	BalancedTernary a("+-0++0+");
	BalancedTernary b(-436);
	BalancedTernary c("+-++-");

	cout << "a = " << a << " = " << a.toInt() << endl;
	cout << "b = " << b << " = " << b.toInt() << endl;
	cout << "c = " << c << " = " << c.toInt() << endl;

	BalancedTernary d = a * (b - c);

	cout << "a * (b - c) = " << d << " = " << d.toInt() << endl;

	BalancedTernary e("+++++++++++++++++++++++++++++++++++++++++");

	long long n;
	if (e.tryInt(n))
		cout << "e = " << e << " = " << n << endl;
	else
		cout << "e = " << e << " is too big to fit in a long long" << endl;

	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")
    }
}