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;
}







VB: Imports System.Text

Module Module1
    Sub Main()
        Dim a As New BalancedTernary("+-0++0+")
        Console.WriteLine("a: {0} = {1}", a, a.ToLong)
        Dim b As New BalancedTernary(-436)
        Console.WriteLine("b: {0} = {1}", b, b.ToLong)
        Dim c As New BalancedTernary("+-++-")
        Console.WriteLine("c: {0} = {1}", c, c.ToLong)
        Dim d = a * (b - c)
        Console.WriteLine("a * (b - c): {0} = {1}", d, d.ToLong)
    End Sub

    Class BalancedTernary
        Private Enum BalancedTernaryDigit
            MINUS = -1
            ZERO = 0
            PLUS = 1
        End Enum

        Private ReadOnly value() As BalancedTernaryDigit

        
        Public Sub New()
            ReDim value(-1)
        End Sub

        
        Public Sub New(str As String)
            ReDim value(str.Length - 1)
            For i = 1 To str.Length
                If str(i - 1) = "-" Then
                    value(i - 1) = BalancedTernaryDigit.MINUS
                ElseIf str(i - 1) = "0" Then
                    value(i - 1) = BalancedTernaryDigit.ZERO
                ElseIf str(i - 1) = "+" Then
                    value(i - 1) = BalancedTernaryDigit.PLUS
                Else
                    Throw New ArgumentException("Unknown Digit: " + str(i - 1))
                End If
            Next
            Array.Reverse(value)
        End Sub

        
        Public Sub New(l As Long)
            Dim value As New List(Of BalancedTernaryDigit)
            Dim sign = Math.Sign(l)
            l = Math.Abs(l)

            While l <> 0
                Dim remainder = CType(l Mod 3, Byte)
                If remainder = 0 OrElse remainder = 1 Then
                    value.Add(remainder)
                    l /= 3
                ElseIf remainder = 2 Then
                    value.Add(BalancedTernaryDigit.MINUS)
                    l = (l + 1) / 3
                End If
            End While

            Me.value = value.ToArray
            If sign < 0 Then
                Invert()
            End If
        End Sub

        
        Public Sub New(origin As BalancedTernary)
            ReDim value(origin.value.Length - 1)
            Array.Copy(origin.value, value, origin.value.Length)
        End Sub

        
        Private Sub New(value() As BalancedTernaryDigit)
            Dim endi = value.Length - 1
            While endi > 0 AndAlso value(endi) = BalancedTernaryDigit.ZERO
                endi -= 1
            End While
            ReDim Me.value(endi)
            Array.Copy(value, Me.value, endi + 1)
        End Sub

        
        Private Sub Invert()
            For i = 1 To value.Length
                value(i - 1) = CType(-CType(value(i - 1), Integer), BalancedTernaryDigit)
            Next
        End Sub

        
        Public Overrides Function ToString() As String
            Dim result As New StringBuilder
            Dim i = value.Length - 1
            While i >= 0
                If value(i) = BalancedTernaryDigit.MINUS Then
                    result.Append("-")
                ElseIf value(i) = BalancedTernaryDigit.ZERO Then
                    result.Append("0")
                ElseIf value(i) = BalancedTernaryDigit.PLUS Then
                    result.Append("+")
                End If

                i -= 1
            End While
            Return result.ToString
        End Function

        
        Public Function ToLong() As Long
            Dim result = 0L
            For i = 1 To value.Length
                result += value(i - 1) * Math.Pow(3.0, i - 1)
            Next
            Return result
        End Function

        
        Public Shared Operator -(origin As BalancedTernary) As BalancedTernary
            Dim result As New BalancedTernary(origin)
            result.Invert()
            Return result
        End Operator

        
        Private Shared carry = BalancedTernaryDigit.ZERO
        Private Shared Function Add(a As BalancedTernaryDigit, b As BalancedTernaryDigit) As BalancedTernaryDigit
            If a <> b Then
                carry = BalancedTernaryDigit.ZERO
                Return a + b
            Else
                carry = a
                Return -CType(b, Integer)
            End If
        End Function

        
        Public Shared Operator +(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
            Dim maxLength = Math.Max(a.value.Length, b.value.Length)
            Dim resultValue(maxLength) As BalancedTernaryDigit
            For i = 1 To maxLength
                If i - 1 < a.value.Length Then
                    resultValue(i - 1) = Add(resultValue(i - 1), a.value(i - 1))
                    resultValue(i) = carry
                Else
                    carry = BalancedTernaryDigit.ZERO
                End If

                If i - 1 < b.value.Length Then
                    resultValue(i - 1) = Add(resultValue(i - 1), b.value(i - 1))
                    resultValue(i) = Add(resultValue(i), carry)
                End If
            Next
            Return New BalancedTernary(resultValue)
        End Operator

        
        Public Shared Operator -(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
            Return a + (-b)
        End Operator

        
        Public Shared Operator *(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
            Dim longValue = a.value
            Dim shortValue = b.value
            Dim result As New BalancedTernary

            If a.value.Length < b.value.Length Then
                longValue = b.value
                shortValue = a.value
            End If

            For i = 1 To shortValue.Length
                If shortValue(i - 1) <> BalancedTernaryDigit.ZERO Then
                    Dim temp(i + longValue.Length - 2) As BalancedTernaryDigit
                    For j = 1 To longValue.Length
                        temp(i + j - 2) = CType(shortValue(i - 1) * longValue(j - 1), BalancedTernaryDigit)
                    Next
                    result += New BalancedTernary(temp)
                End If
            Next

            Return result
        End Operator
    End Class

End Module