Task: Balanced ternary



C#: using System;
using System.Text;
using System.Collections.Generic;

public class BalancedTernary
{
	public static void Main()
	{
		BalancedTernary a = new BalancedTernary("+-0++0+");
		System.Console.WriteLine("a: " + a + " = " + a.ToLong());
		BalancedTernary b = new BalancedTernary(-436);
		System.Console.WriteLine("b: " + b + " = " + b.ToLong());
		BalancedTernary c = new BalancedTernary("+-++-");
		System.Console.WriteLine("c: " + c + " = " + c.ToLong());
		BalancedTernary d = a * (b - c);
		System.Console.WriteLine("a * (b - c): " + d + " = " + d.ToLong());
	}

	private enum BalancedTernaryDigit
	{
		MINUS = -1,
		ZERO = 0,
		PLUS = 1
	}

	private BalancedTernaryDigit[] value;

	
	public BalancedTernary()
	{
		this.value = new BalancedTernaryDigit[0];
	}

	
	public BalancedTernary(String str)
	{
		this.value = new BalancedTernaryDigit[str.Length];
		for (int i = 0; i < str.Length; ++i)
		{
			switch (str[i])
			{
				case '-':
					this.value[i] = BalancedTernaryDigit.MINUS;
					break;
				case '0':
					this.value[i] = BalancedTernaryDigit.ZERO;
					break;
				case '+':
					this.value[i] = BalancedTernaryDigit.PLUS;
					break;
				default:
					throw new ArgumentException("Unknown Digit: " + str[i]);
			}
		}
		Array.Reverse(this.value);
	}

	
	public BalancedTernary(long l)
	{
		List<BalancedTernaryDigit> value = new List<BalancedTernaryDigit>();
		int sign = Math.Sign(l);
		l = Math.Abs(l);
		
		while (l != 0)
		{
			byte rem = (byte)(l % 3);
			switch (rem)
			{
				case 0:
				case 1:
					value.Add((BalancedTernaryDigit)rem);
					l /= 3;
					break;
				case 2:
					value.Add(BalancedTernaryDigit.MINUS);
					l = (l + 1) / 3;
					break;
			}
		}

		this.value = value.ToArray();
		if (sign < 0)
		{
			this.Invert();
		}
	}

	
	public BalancedTernary(BalancedTernary origin)
	{
		this.value = new BalancedTernaryDigit[origin.value.Length];
		Array.Copy(origin.value, this.value, origin.value.Length);
	}

	
	private BalancedTernary(BalancedTernaryDigit[] value)
	{
		int end = value.Length - 1;
		while (value[end] == BalancedTernaryDigit.ZERO)
			--end;
		this.value = new BalancedTernaryDigit[end + 1];
		Array.Copy(value, this.value, end + 1);
	}

	
	private void Invert()
	{
		for (int i=0; i < this.value.Length; ++i)
		{
			this.value[i] = (BalancedTernaryDigit)(-(int)this.value[i]);
		}
	}

	
	override public String ToString()
	{
		StringBuilder result = new StringBuilder();
		for (int i = this.value.Length - 1; i >= 0; --i)
		{
			switch (this.value[i])
			{
				case BalancedTernaryDigit.MINUS:
					result.Append('-');
					break;
				case BalancedTernaryDigit.ZERO:
					result.Append('0');
					break;
				case BalancedTernaryDigit.PLUS:
					result.Append('+');
					break;
			}
		}
		return result.ToString();
	}

	
	public long ToLong()
	{
		long result = 0;
		int digit;
		for (int i = 0; i < this.value.Length; ++i)
		{
			result += (long)this.value[i] * (long)Math.Pow(3.0, (double)i);
		}
		return result;
	}

	
	public static BalancedTernary operator -(BalancedTernary origin)
	{
		BalancedTernary result = new BalancedTernary(origin);
		result.Invert();
		return result;
	}

	
	private static BalancedTernaryDigit carry = BalancedTernaryDigit.ZERO;
	private static BalancedTernaryDigit Add(BalancedTernaryDigit a, BalancedTernaryDigit b)
	{
		if (a != b)
		{
			carry = BalancedTernaryDigit.ZERO;
			return (BalancedTernaryDigit)((int)a + (int)b);
		}
		else
		{
			carry = a;
			return (BalancedTernaryDigit)(-(int)b);
		}
	}

	
	public static BalancedTernary operator +(BalancedTernary a, BalancedTernary b)
	{
		int maxLength = Math.Max(a.value.Length, b.value.Length);
		BalancedTernaryDigit[] resultValue = new BalancedTernaryDigit[maxLength + 1];
		for (int i=0; i < maxLength; ++i)
		{
			if (i < a.value.Length)
			{
				resultValue[i] = Add(resultValue[i], a.value[i]);
				resultValue[i+1] = carry;
			}
			else
			{
				carry = BalancedTernaryDigit.ZERO;
			}
			
			if (i < b.value.Length)
			{
				resultValue[i] = Add(resultValue[i], b.value[i]);
				resultValue[i+1] = Add(resultValue[i+1], carry);
			}
		}
		return new BalancedTernary(resultValue);
	}

	
	public static BalancedTernary operator -(BalancedTernary a, BalancedTernary b)
	{
		return a + (-b);
	}

	
	public static BalancedTernary operator *(BalancedTernary a, BalancedTernary b)
	{
		BalancedTernaryDigit[] longValue = a.value;
		BalancedTernaryDigit[] shortValue = b.value;
		BalancedTernary result = new BalancedTernary();
		if (a.value.Length < b.value.Length)
		{
			longValue = b.value;
			shortValue = a.value;
		}

		for (int i = 0; i < shortValue.Length; ++i)
		{
			if (shortValue[i] != BalancedTernaryDigit.ZERO)
			{
				BalancedTernaryDigit[] temp = new BalancedTernaryDigit[i + longValue.Length];
				for (int j = 0; j < longValue.Length; ++j)
				{
					temp[i+j] = (BalancedTernaryDigit)((int)shortValue[i] * (int)longValue[j]);
				}
				result = result + new BalancedTernary(temp);
			}
		}
		return result;
	}
}


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