# Balanced ternary

(Redirected from Balanced Ternary)
Balanced ternary
You are encouraged to solve this task according to the task description, using any language you may know.

Balanced ternary is a way of representing numbers. Unlike the prevailing binary representation, a balanced ternary integer is in base 3, and each digit can have the values 1, 0, or −1.

Examples

Decimal 11 = 32 + 31 − 30, thus it can be written as "++−"

Decimal 6 = 32 − 31 + 0 × 30, thus it can be written as "+−0"

Implement balanced ternary representation of integers with the following:

1. Support arbitrarily large integers, both positive and negative;
2. Provide ways to convert to and from text strings, using digits '+', '-' and '0' (unless you are already using strings to represent balanced ternary; but see requirement 5).
3. Provide ways to convert to and from native integer type (unless, improbably, your platform's native integer type is balanced ternary). If your native integers can't support arbitrary length, overflows during conversion must be indicated.
4. Provide ways to perform addition, negation and multiplication directly on balanced ternary integers; do not convert to native integers first.
5. Make your implementation efficient, with a reasonable definition of "efficient" (and with a reasonable definition of "reasonable").

Test case With balanced ternaries a from string "+-0++0+", b from native integer -436, c "+-++-":

• write out a, b and c in decimal notation;
• calculate a × (bc), write out the result in both ternary and decimal notations.

Note: The pages generalised floating point addition and generalised floating point multiplication have code implementing arbitrary precision floating point balanced ternary.

## 11l

Translation of: Python
```T BalancedTernary
. -:str2dig = [‘+’ = 1, ‘-’ = -1, ‘0’ = 0]
. -:dig2str = [1 = ‘+’, -1 = ‘-’, 0 = ‘0’]
. -:table = [(0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1)]

[Int] digits

F (inp)
I all(inp.map(d -> d C (0, 1, -1)))
.digits = copy(inp)
E
X.throw ValueError(‘BalancedTernary: Wrong input digits.’)

F :from_str(inp)
R BalancedTernary(reversed(inp).map(c -> .:str2dig[c]))

. F :int2ternary(n)
I n == 0
R [Int]()
V n3 = ((n % 3) + 3) % 3
I n3 == 0 {R  [0] [+] .:int2ternary(n -I/ 3)}
I n3 == 1 {R  [1] [+] .:int2ternary(n -I/ 3)}
I n3 == 2 {R [-1] [+] .:int2ternary((n + 1) -I/ 3)}
X.throw RuntimeError(‘’)

F :from_int(inp)
R BalancedTernary(.:int2ternary(inp))

F to_int()
R reversed(.digits).reduce(0, (y, x) -> x + 3 * y)

F String()
I .digits.empty
R ‘0’
R reversed(.digits).map(d -> .:dig2str[d]).join(‘’)

. F :neg(digs)
R digs.map(d -> -d)

F -()
R BalancedTernary(.:neg(.digits))

. F :add(a, b, =c = 0)
I !(!a.empty & !b.empty)
I c == 0
R I !a.empty {a} E b
E
R .:add([c], I !a.empty {a} E b)
E
(V d, c) = .:table[3 + (I !a.empty {a[0]} E 0) + (I !b.empty {b[0]} E 0) + c]
V res = .:add(a[1..], b[1..], c)
I !res.empty | d != 0
R [d] [+] res
E
R res

F +(b)

F -(b)
R (.) + (-b)

F *(b)
F _mul([Int] a, b) -> [Int]
I !(!a.empty & !b.empty)
R [Int]()
E
[Int] x
I   a[0] == -1 {x = .:neg(b)}
E I a[0] ==  0 {}
E I a[0] ==  1 {x = b}
E
assert(0B)
V y = [0] [+] @_mul(a[1..], b)

R BalancedTernary(_mul(.digits, b.digits))

V a = BalancedTernary.from_str(‘+-0++0+’)
print(‘a: ’a.to_int()‘ ’a)

V b = BalancedTernary.from_int(-436)
print(‘b: ’b.to_int()‘ ’b)

V c = BalancedTernary.from_str(‘+-++-’)
print(‘c: ’c.to_int()‘ ’c)

V r = a * (b - c)
print(‘a * (b - c): ’r.to_int()‘ ’r)```
Output:
```a: 523 +-0++0+
b: -436 -++-0--
c: 65 +-++-
a * (b - c): -262023 ----0+--0++0
```

```with Ada.Finalization;

package BT is

type Balanced_Ternary is private;

-- conversions
function To_Balanced_Ternary (Num : Integer) return Balanced_Ternary;
function To_Balanced_Ternary (Str : String)  return Balanced_Ternary;
function To_Integer (Num : Balanced_Ternary)  return Integer;
function To_string (Num : Balanced_Ternary)   return String;

-- Arithmetics
-- unary minus
function "-" (Left : in Balanced_Ternary)
return Balanced_Ternary;

-- subtraction
function "-" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary;

function "+" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary;
-- multiplication
function "*" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary;

private
-- a balanced ternary number is a unconstrained array of (1,0,-1)
-- dinamically allocated, least significant trit leftmost
type Trit is range -1..1;
type Trit_Array is array (Positive range <>) of Trit;
pragma Pack(Trit_Array);

type Trit_Access is access Trit_Array;

with record
Ref : Trit_access;
end record;

procedure Initialize (Object : in out Balanced_Ternary);
procedure Adjust     (Object : in out Balanced_Ternary);
procedure Finalize   (Object : in out Balanced_Ternary);

end BT;
```

```with Ada.Unchecked_Deallocation;

package body BT is

procedure Free is new Ada.Unchecked_Deallocation (Trit_Array, Trit_Access);

-- Conversions
-- String to BT
function To_Balanced_Ternary (Str: String) return Balanced_Ternary is
J : Positive := 1;
Tmp : Trit_Access;
begin
Tmp := new Trit_Array (1..Str'Last);
for I in reverse Str'Range loop
case Str(I) is
when '+' => Tmp (J) := 1;
when '-' => Tmp (J) := -1;
when '0' => Tmp (J) := 0;
when others => raise Constraint_Error;
end case;
J := J + 1;
end loop;
return (Ada.Finalization.Controlled with Ref => Tmp);
end To_Balanced_Ternary;

-- Integer to BT
function To_Balanced_Ternary (Num: Integer) return Balanced_Ternary is
K      : Integer := 0;
D      : Integer;
Value  : Integer := Num;
Tmp    : Trit_Array(1..19); -- 19 trits is enough to contain
-- a 32 bits signed integer
begin
loop
D := (Value mod 3**(K+1))/3**K;
if D = 2 then D := -1; end if;
Value := Value - D*3**K;
K := K + 1;
Tmp(K) := Trit(D);
exit when Value = 0;
end loop;
with Ref => new Trit_Array'(Tmp(1..K)));
end To_Balanced_Ternary;

-- BT to Integer --
-- If the BT number is too large Ada will raise CONSTRAINT ERROR
function To_Integer (Num : Balanced_Ternary) return Integer is
Value : Integer := 0;
Pos : Integer := 1;
begin
for I in Num.Ref.all'Range loop
Value := Value + Integer(Num.Ref(I)) * Pos;
Pos := Pos * 3;
end loop;
return Value;
end To_Integer;

-- BT to String --
function To_String (Num : Balanced_Ternary) return String is
I : constant Integer := Num.Ref.all'Last;
Result : String (1..I);
begin
for J in Result'Range loop
case Num.Ref(I-J+1) is
when 0  => Result(J) := '0';
when -1 => Result(J) := '-';
when 1  => Result(J) := '+';
end case;
end loop;
return Result;
end To_String;

-- unary minus --
function "-" (Left : in Balanced_Ternary)
return Balanced_Ternary is
Result : constant Balanced_Ternary := Left;
begin
for I in Result.Ref.all'Range loop
Result.Ref(I) := - Result.Ref(I);
end loop;
return Result;
end "-";

Carry : Trit;

function Add (Left, Right : in Trit)
return Trit is
begin
if Left /= Right then
Carry := 0;
return Left + Right;
else
Carry := Left;
return -Right;
end if;

function "+" (Left, Right : in Trit_Array)
return Balanced_Ternary is
Max_Size : constant Integer :=
Integer'Max(Left'Last, Right'Last);
Tmp_Left, Tmp_Right : Trit_Array(1..Max_Size) := (others => 0);
Result : Trit_Array(1..Max_Size+1) := (others => 0);
begin
Tmp_Left (1..Left'Last) := Left;
Tmp_Right(1..Right'Last) := Right;
for I in Tmp_Left'Range loop
Result(I+1) := Carry;
end loop;
-- remove trailing zeros
for I in reverse Result'Range loop
if Result(I) /= 0 then
with Ref => new Trit_Array'(Result(1..I)));
end if;
end loop;
with Ref => new Trit_Array'(1 => 0));
end "+";

function "+" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary is
begin
return Left.Ref.all + Right.Ref.all;
end "+";

-- Subtraction
function "-" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary is
begin
return Left + (-Right);
end "-";

-- multiplication
function "*" (Left, Right : in Balanced_Ternary)
return Balanced_Ternary is
A, B : Trit_Access;
Result : Balanced_Ternary;
begin
if Left.Ref.all'Length > Right.Ref.all'Length then
A := Right.Ref; B := Left.Ref;
else
B := Right.Ref; A := Left.Ref;
end if;
for I in A.all'Range loop
if A(I) /= 0 then
declare
Tmp_Result : Trit_Array (1..I+B.all'Length-1) := (others => 0);
begin
for J in B.all'Range loop
Tmp_Result(I+J-1) := B(J) * A(I);
end loop;
Result := Result.Ref.all + Tmp_Result;
end;
end if;
end loop;
return Result;
end "*";

procedure Adjust (Object : in out Balanced_Ternary) is
begin
Object.Ref := new Trit_Array'(Object.Ref.all);

procedure Finalize  (Object : in out Balanced_Ternary) is
begin
Free (Object.Ref);
end Finalize;

procedure Initialize (Object : in out Balanced_Ternary) is
begin
Object.Ref := new Trit_Array'(1 => 0);
end Initialize;

end BT;
```

```with Ada.Text_Io; use Ada.Text_Io;
with BT; use BT;

procedure TestBT is
Result, A, B, C : Balanced_Ternary;
begin
A := To_Balanced_Ternary("+-0++0+");
B := To_Balanced_Ternary(-436);
C := To_Balanced_Ternary("+-++-");

Result := A * (B - C);

Put("a = "); Put(To_integer(A), 4); New_Line;
Put("b = "); Put(To_integer(B), 4); New_Line;
Put("c = "); Put(To_integer(C), 4); New_Line;
Put("a * (b - c) = "); Put(To_integer(Result), 4);
Put_Line (" " & To_String(Result));
end TestBT;
```

Output:

```a =  523
b = -436
c =   65
a * (b - c) = -262023 ----0+--0++0
```

## AppleScript

To demonstrate the possibility, the integerFromBT and negateBT handlers here work by being tricksy with the characters' Unicode numbers. It's a more efficient way to deal with the characters. But I'm not sure how this'll be taken vis-à-vis not converting to native integers first, so the remaining handlers use a strictly if-then string comparison approach. Applescript's quite happy to convert automatically between integers, reals, numeric strings, and single-item lists containing numbers, so BTFromInteger accepts any of these forms, but the numbers represented must be whole-number values and must be small enough not to error AppleScript's as integer coercion. This coercion is error free for numbers in the range -(2 ^ 31) to 2 ^ 31 - 1, although actual integer class objects can only represent numbers in the range -(2 ^ 29) to 2 ^ 29 - 1. IntegerFromBT doesn't currently impose any integer-class size limit on its output.

```-- Build a balanced ternary, as text, from an integer value or acceptable AppleScript substitute.
on BTFromInteger(n)
try
if (n mod 1 is not 0) then error (n as text) & " isn't an integer value"
set n to n as integer
on error errMsg
display alert "BTFromInteger handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
if (n is 0) then return "0"
-- Positive numbers' digits will be indexed from the beginning of a list containing them, negatives' from the end.
-- AppleScript indices are 1-based, so get the appropriate 1 or -1 add-in.
set one to 1
if (n < 0) then set one to -1
set digits to {"0", "+", "-", "0"}
-- Build the text digit by digit.
set bt to ""
repeat until (n = 0)
set nMod3 to n mod 3
set bt to (item (nMod3 + one) of digits) & bt
set n to n div 3 + nMod3 div 2 -- + nMod3 div 2 adds in a carry when nMod3 is either 2 or -2.
end repeat

return bt
end BTFromInteger

-- Calculate a balanced ternary's integer value from its characters' Unicode numbers.
on integerFromBT(bt)
checkInput(bt, "integerFromBT")
set n to 0
repeat with thisID in (get bt's id)
set n to n * 3
-- Unicode 48 is "0", 43 is "+", 45 is "-".
if (thisID < 48) then set n to n + (44 - thisID)
end repeat

return n
end integerFromBT

-- Add two balanced ternaries together.
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, longerLength, shorterLength} to {bt2, bt1, shorterLength, longerLength}

-- Add the shorter number's digits into a list of the longer number's digits, adding in carries too where appropriate.
set resultList to bt1's characters
repeat with i from -1 to -shorterLength by -1
set {carry, item i of resultList} to sumDigits(item i of resultList, character i of bt2)
repeat with j from (i - 1) to -longerLength by -1
if (carry is "0") then exit repeat
set {carry, item j of resultList} to sumDigits(carry, item j of resultList)
end repeat
if (carry is not "0") then set beginning of bt1 to carry
end repeat
-- Zap any leading zeros resulting from the cancelling out of the longer number's MSD(s).
set j to -(count resultList)
repeat while ((item j of resultList is "0") and (j < -1))
set item j of resultList to ""
set j to j + 1
end repeat

return join(resultList, "")

-- Multiply one balanced ternary by another.
on multiplyBTs(bt1, bt2)
checkInput({bt1, bt2}, "multiplyBTs")
-- Longer and shorter aren't critical here, but it's more efficient to loop through the lesser number of digits.
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, shorterLength} to {bt2, bt1, longerLength}

set multiplicationResult to "0"
repeat with i from -1 to -shorterLength by -1
set d2 to character i of bt2
if (d2 is not "0") then
set subresult to ""
-- With each non-"0" subresult, begin with the appropriate number of trailing zeros.
repeat (-1 - i) times
set subresult to "0" & subresult
end repeat
-- Prepend the longer ternary as is.
set subresult to bt1 & subresult
-- Negate the result if the current multiplier from the shorter ternary is "-".
if (d2 is "-") then set subresult to negateBT(subresult)
-- Add the subresult to the total so far.
end if
end repeat

return multiplicationResult
end multiplyBTs

-- Negate a balanced ternary by substituting the characters obtained through subtracting its sign characters' Unicode numbers from 88.
on negateBT(bt)
checkInput(bt, "negateBT")
set characterIDs to bt's id
repeat with thisID in characterIDs
if (thisID < 48) then set thisID's contents to 88 - thisID
end repeat

return string id characterIDs
end negateBT

(* Private handlers. *)

on checkInput(params as list, handlerName)
try
repeat with thisParam in params
if (thisParam's class is text) then
if (join(split(thisParam, {"-", "+", "0"}), "") > "") then error "\"" & thisParam & "\" isn't a balanced ternary number."
else
error "The parameter isn't text."
end if
end repeat
on error errMsg
display alert handlerName & " handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
end checkInput

-- "Add" two balanced ternaries and return both the carry and the result for the column.
on sumDigits(d1, d2)
if (d1 is "0") then
return {"0", d2}
else if (d2 is "0") then
return {"0", d1}
else if (d1 = d2) then
if (d1 = "+") then
return {"+", "-"}
else
return {"-", "+"}
end if
else
return {"0", "0"}
end if
end sumDigits

on join(lst, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set txt to lst as text
set AppleScript's text item delimiters to astid

return txt
end join

on split(txt, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set lst to txt's text items
set AppleScript's text item delimiters to astid

return lst
end split

-- Test code:
set a to "+-0++0+"
set b to BTFromInteger(-436) --> "-++-0--"
set c to "+-++-"

set line1 to "a = " & integerFromBT(a)
set line2 to "b = " & integerFromBT(b)
set line3 to "c = " & integerFromBT(c)
tell multiplyBTs(a, addBTs(b, negateBT(c))) to ¬
set line4 to "a * (b - c) = " & it & " or " & my integerFromBT(it)

return line1 & linefeed & line2 & linefeed & line3 & linefeed & line4
```
Output:
```"a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 or -262023"
```

## ATS

```(*
** This one is
** translated into ATS from the Ocaml entry
*)

(* ****** ****** *)
//
// How to compile:
// patscc -DATS_MEMALLOC_LIBC -o bternary bternary.dats
//
(* ****** ****** *)

#include

(* ****** ****** *)

datatype btd = P | Z | N; typedef btern = List0(btd)

(* ****** ****** *)

fun
btd2int (d: btd): int =
(case+ d of P() => 1 | Z() => 0 | N() => ~1)

(* ****** ****** *)

fun
btd2string (d:btd): string =
(
case+ d of P() => "+" | Z() => "0" | N() => "-"
)

(* ****** ****** *)

fun
btern2string
(
ds: btern
) : string =
strptr2string(res) where
{
val xs = list_map_cloref (ds, lam d => btd2string(d))
val xs = list_vt_reverse (xs)
val res = stringlst_concat(\$UNSAFE.castvwtp1{List(string)}(xs))
val () = list_vt_free<string> (xs)
}

(* ****** ****** *)

fun
from_string
(inp: string): btern = let
//
fun
loop{n:nat}
(
inp: string(n), ds: btern
) : btern =
(
//
if isneqz(inp)
then let
val d =
(case- c of '+' => P | '0' => Z | '-' => N): btd
// end of [val]
in
loop (inp.tail(), list_cons(d, ds))
end // end of [then]
else ds // end of [else]
//
) (* end of [loop] *)
//
in
loop (g1ofg0(inp), list_nil)
end // end of [from_string]

(* ****** ****** *)

fun
to_int (ds: btern): int =
(
case+ ds of
| list_nil () => 0
| list_cons (d, ds) => 3*to_int(ds) + btd2int(d)
) (* end of [to_int] *)

fun
from_int (n: int): btern =
(
if
n = 0
then list_nil
else let
val r = n mod 3
in
if r = 0
then list_cons (Z, from_int (n/3))
else if (r = 1 || r = ~2)
then list_cons (P, from_int ((n-1)/3))
else list_cons (N, from_int ((n+1)/3))
end // end of [else]
) (* end of [from_int] *)

(* ****** ****** *)

fun
neg_btern
(ds: btern): btern =
list_vt2t
(
list_map_cloref<btd><btd>
(ds, lam d => case+ d of P() => N() | Z() => Z() | N() => P())
) (* end of [neg_btern] *)

(* ****** ****** *)
//
extern
fun
and
sub_btern_btern: (btern, btern) -> btern
overload - with sub_btern_btern of 100
//
extern
fun
mul_btern_btern: (btern, btern) -> btern
overload * with mul_btern_btern of 110
//
(* ****** ****** *)

#define :: list_cons

(* ****** ****** *)

local

fun aux0 (ds: btern): btern =
(
case+ ds of nil() => ds | _ => Z()::ds
)

fun succ(ds:btern) = ds+list_sing(P())
fun pred(ds:btern) = ds+list_sing(N())

in (* in-of-local *)

implement
(ds1, ds2) =
(
case+ (ds1, ds2) of
| (nil(), _) => ds2
| (_, nil()) => ds1
| (P()::ds1, N()::ds2) => aux0 (ds1+ds2)
| (Z()::ds1, Z()::ds2) => aux0 (ds1+ds2)
| (N()::ds1, P()::ds2) => aux0 (ds1+ds2)
| (P()::ds1, P()::ds2) => N() :: succ(ds1 + ds2)
| (N()::ds1, N()::ds2) => P() :: pred(ds1 + ds2)
| (Z()::ds1, btd::ds2) => btd :: (ds1 + ds2)
| (btd::ds1, Z()::ds2) => btd :: (ds1 + ds2)
)

implement
sub_btern_btern (ds1, ds2) = ds1 + (~ds2)

implement
mul_btern_btern (ds1, ds2) =
(
case+ ds2 of
| nil() => nil()
| Z()::ds2 => aux0 (ds1 * ds2)
| P()::ds2 => aux0 (ds1 * ds2) + ds1
| N()::ds2 => aux0 (ds1 * ds2) - ds1
)

end // end of [local]

(* ****** ****** *)

typedef charptr = \$extype"char*"

(* ****** ****** *)

implement main0 () =
{
//
val a =
from_string "+-0++0+"
//
val b = from_int (~436)
val c = from_string "+-++-"
//
val d = a * (b - c)
//
val () =
\$extfcall
(
void
, "printf"
, "a = %d\nb = %d\nc = %d\na * (b - c) = %s = %d\n"
, to_int(a)
, to_int(b)
, to_int(c)
, \$UNSAFE.cast{charptr}(btern2string(d))
, to_int(d)
) (* end of [val] *)
//
} (* end of [main0] *)```

Output:

```a =  523
b = -436
c =   65
a * (b - c) = -262023 ----0+--0++0
```

## AutoHotkey

```BalancedTernary(n){
k = 0
if abs(n)<2
return n=1?"+":n=0?"0":"-"
if n<1
negative := true, n:= -1*n
while !break {
d := Mod(n, 3**(k+1)) / 3**k
d := d=2?-1:d
n := n - (d * 3**k)
r := (d=-1?"-":d=1?"+":0) . r
k++
if (n = 3**k)
r := "+" . r	, break := true
}
if negative {
StringReplace, r, r, -,n, all
StringReplace, r, r, `+,-, all
StringReplace, r, r, n,+, all
}
return r
}
```

Examples:

```data =
(
523
-436
65
-262023
)
loop, Parse, data, `n
result .= A_LoopField " : " BalancedTernary(A_LoopField) "`n"
MsgBox % result
return
```

Outputs:

```523 	: +-0++0+
-436 	: -++-0--
65 	: +-++-
-262023	: ----0+--0++0```

## Bruijn

The default syntax sugar for numbers in bruijn is balanced ternary. The implementation of respective arithmetic operators is in `std/Number/Ternary` and `std/Math`. Converting between bases can be accomplished using `std/Number/Conversion`. The following is a library excerpt to show how to define the most common operators (succ,pred,add,sub,mul,eq) efficiently. They can be easily converted to the notation of pure lambda calculus (as originally by Torben Mogensen in "An Investigation of Compact and Efficient Number Representations in the Pure Lambda Calculus").

```:import std/Combinator .
:import std/Logic .
:import std/Pair .

# negative trit indicating coefficient of (-1)
t⁻ [[[2]]]

# positive trit indicating coefficient of (+1)
t⁺ [[[1]]]

# zero trit indicating coefficient of 0
t⁰ [[[0]]]

# shifts a negative trit into a balanced ternary number
↑⁻‣ [[[[[2 (4 3 2 1 0)]]]]]

# shifts a positive trit into a balanced ternary number
↑⁺‣ [[[[[1 (4 3 2 1 0)]]]]]

# shifts a zero trit into a balanced ternary number
↑⁰‣ [[[[[0 (4 3 2 1 0)]]]]]

# shifts a specified trit into a balanced ternary number
…↑… [[[[[[5 2 1 0 (4 3 2 1 0)]]]]]]

# negates a balanced ternary number
-‣ [[[[[4 3 1 2 0]]]]]

# increments a balanced ternary number (can introduce leading 0s)
++‣ [~(0 z a⁻ a⁺ a⁰)]
z (+0) : (+1)
a⁻ &[[↑⁻1 : ↑⁰1]]
a⁺ &[[↑⁺1 : ↑⁻0]]
a⁰ &[[↑⁰1 : ↑⁺1]]

# decrements a balanced ternary number (can introduce leading 0s)
--‣ [~(0 z a⁻ a⁺ a⁰)]
z (+0) : (-1)
a⁻ &[[↑⁻1 : ↑⁺0]]
a⁺ &[[↑⁺1 : ↑⁰1]]
a⁰ &[[↑⁰1 : ↑⁻1]]

# converts the normal balanced ternary representation into abstract form
→^‣ [0 z a⁻ a⁺ a⁰]
z (+0)
a⁻ [[[[[2 4]]]]]
a⁺ [[[[[1 4]]]]]
a⁰ [[[[[0 4]]]]]

# converts the abstracted balanced ternary representation back to normal
→_‣ y [[0 z a⁻ a⁺ a⁰]]
z (+0)
a⁻ [↑⁻(2 0)]
a⁺ [↑⁺(2 0)]
a⁰ [↑⁰(2 0)]

…+… [[[c (0 z a⁻ a⁺ a⁰)] 1 →^0]]
b⁻ [1 ↑⁺(3 0 t⁻) ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁰)]
b⁰ [1 ↑ (3 0 t⁰)]
b⁺ [1 ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁺) ↑⁺(3 0 t⁰)]
a⁻ [[[1 (b⁻ 1) b⁻' b⁰ b⁻]]]
b⁻' [1 ↑⁰(3 0 t⁻) ↑⁻(3 0 t⁰) ↑⁺(3 0 t⁻)]
a⁺ [[[1 (b⁺ 1) b⁰ b⁺' b⁺]]]
b⁺' [1 ↑⁺(3 0 t⁰) ↑⁰(3 0 t⁺) ↑⁻(3 0 t⁺)]
a⁰ [[[1 (b⁰ 1) b⁻ b⁺ b⁰]]]
z [[0 --(→_1) ++(→_1) →_1]]
c [[1 0 t⁰]]

# subtracts two balanced ternary numbers (can introduce leading 0s)
…-… [[1 + -0]]

# multiplicates two balanced ternary numbers (can introduce leading 0s)
…⋅… [[1 z a⁻ a⁺ a⁰]]
z (+0)
a⁻ [↑⁰0 - 1]
a⁺ [↑⁰0 + 1]
a⁰ [↑⁰0]

# true if balanced ternary number is zero
=?‣ [0 true [false] [false] i]

# true if two balanced ternary numbers are equal
…=?… [[[0 z a⁻ a⁺ a⁰] 1 →^0]]
z [=?(→_0)]
a⁻ [[0 false [2 0] [false] [false]]]
a⁺ [[0 false [false] [2 0] [false]]]
a⁰ [[0 (1 0) [false] [false] [2 0]]]

main [[0]]

# --- tests/examples ---

:test ((-42) + (-1) =? (-43)) (true)
:test ((+1) + (+2) =? (+3)) (true)
:test ((-42) - (-1) =? (-41)) (true)
:test ((+1) - (+2) =? (-1)) (true)
:test ((-1) ⋅ (+42) =? (-42)) (true)
:test ((+3) ⋅ (+11) =? (+33)) (true)```

## C

Translation of: Perl
```#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';
}
}

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

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 == '+') {
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;
}
```
Output:
```      a:        +-0++0+        523
b:        -++-0--       -436
c:          +-++-         65
a*(b-c):   ----0+--0++0    -262023```

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

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

// create from String
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);
}

// convert long integer
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:
l /= 3;
break;
case 2:
l = (l + 1) / 3;
break;
}
}

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

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

// only for internal use
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);
}

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

// convert to string
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();
}

// convert to long
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;
}

// unary minus
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);
}
}

// addition of balanced ternary numbers
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+1] = carry;
}
else
{
carry = BalancedTernaryDigit.ZERO;
}

if (i < b.value.Length)
{
}
}
return new BalancedTernary(resultValue);
}

// subtraction of balanced ternary numbers
public static BalancedTernary operator -(BalancedTernary a, BalancedTernary b)
{
return a + (-b);
}

// multiplication of balanced ternary numbers
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;
}
}
```

output:

```a: +-0++0+ = 523
b: -++-0-- = -436
c: +-++- = 65
a * (b - c): ----0+--0++0 = -262023```

## C++

```#include <iostream>
#include <string>
#include <climits>
using namespace std;

class BalancedTernary {
protected:
// Store the value as a reversed string of +, 0 and - characters
string value;

// Helper function to change a balanced ternary character to an integer
int charToInt(char c) const {
if (c == '0')
return 0;
return 44 - c;
}

// Helper function to negate a string of ternary characters
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:
// Default constructor
BalancedTernary() {
value = "0";
}

// Construct from a string
BalancedTernary(string s) {
value = string(s.rbegin(), s.rend());
}

// Construct from an integer
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);
}

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

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

BalancedTernary& operator+=(const BalancedTernary &n) {
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())
else

lastNonZero = i;
}

if (c != '0')
value += c;
else
value = value.substr(0, lastNonZero + 1); // Chop off leading zeroes

return *this;
}

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

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

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

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

BalancedTernary& operator*=(const BalancedTernary &n) {
BalancedTernary pos = *this;
BalancedTernary neg = -pos; // Storing an extra copy to avoid negating repeatedly
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;
}

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

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

// Convert to integer
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;
}

// Convert to integer if possible
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; // Clear ok if the result overflows
result += pow;
} else if (value[i] == '-') {
ok &= LLONG_MIN + pow <= result; // Clear ok if the result overflows
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;
}
```

Output

```a = +-0++0+ = 523
b = -++-0-- = -436
c = +-++- = 65
a * (b - c) = ----0+--0++0 = -262023
e = +++++++++++++++++++++++++++++++++++++++++ is too big to fit in a long long
```

## Common Lisp

```;;; balanced ternary
;;; represented as a list of 0, 1 or -1s, with least significant digit first

;;; convert ternary to integer
(defun bt-integer (b)
(reduce (lambda (x y) (+ x (* 3 y))) b :from-end t :initial-value 0))

;;; convert integer to ternary
(defun integer-bt (n)
(if (zerop n) nil
(case (mod n 3)
(0 (cons  0 (integer-bt (/ n 3))))
(1 (cons  1 (integer-bt (floor n 3))))
(2 (cons -1 (integer-bt (floor (1+ n) 3)))))))

;;; convert string to ternary
(defun string-bt (s)
(loop with o = nil for c across s do
(setf o (cons (case c (#\+ 1) (#\- -1) (#\0 0)) o))
finally (return o)))

;;; convert ternary to string
(defun bt-string (bt)
(if (not bt) "0"
(let* ((l (length bt))
(s (make-array l :element-type 'character)))
(mapc (lambda (b)
(setf (aref s (decf l))
(case b (-1 #\-) (0 #\0) (1 #\+))))
bt)
s)))

;;; arithmetics
(defun bt-neg (a) (map 'list #'- a))
(defun bt-sub (a b) (bt-add a (bt-neg b)))

(let ((tbl #((0 -1) (1 -1) (-1 0) (0 0) (1 0) (-1 1) (0 1))))
(values-list (aref tbl (+ 3 a b c)))))

(defun bt-add (a b &optional (c 0))
(if (not (and a b))
(if (zerop c) (or a b)
(bt-add (list c) (or a b)))
(multiple-value-bind (d c)
(bt-add-digits (if a (car a) 0) (if b (car b) 0) c)
(let ((res (bt-add (cdr a) (cdr b) c)))
(if (or res (not (zerop d)))
(cons d res))))))

(defun bt-mul (a b)
(if (not (and a b))
nil
(-1 (bt-neg b))
( 0 nil)
( 1 b))
(cons 0 (bt-mul (cdr a) b)))))

;;; division with quotient/remainder, for completeness
(defun bt-truncate (a b)
(let ((n (- (length a) (length b)))
(d (car (last b))))
(if (minusp n)
(values nil a)
(labels ((recur (a b x)
(multiple-value-bind (quo rem)
(if (plusp x) (recur a (cons 0 b) (1- x))
(values nil a))

(loop with g = (car (last rem))
with quo = (cons 0 quo)
while (= (length rem) (length b)) do
(cond ((= g d) (setf rem (bt-sub rem b)
((= g (- d)) (setf rem (bt-add rem b)
(setf x (car (last rem)))
finally (return (values quo rem))))))

(recur a b n)))))

;;; test case
(let* ((a (string-bt "+-0++0+"))
(b (integer-bt -436))
(c (string-bt "+-++-"))
(d (bt-mul a (bt-sub b c))))
(format t "a~5d~8t~a~%b~5d~8t~a~%c~5d~8t~a~%a × (b − c) = ~d ~a~%"
(bt-integer a) (bt-string a)
(bt-integer b) (bt-string b)
(bt-integer c) (bt-string c)
(bt-integer d) (bt-string d)))
```

output

```a  523  +-0++0+
b -436  -++-0--
c   65  +-++-
a × (b − c) = -262023 ----0+--0++0
```

## D

Translation of: Python
```import std.stdio, std.bigint, std.range, std.algorithm;

struct BalancedTernary {
// Represented as a list of 0, 1 or -1s,
// with least significant digit first.
enum Dig : byte { N=-1, Z=0, P=+1 } // Digit.
const Dig[] digits;

// This could also be a BalancedTernary template argument.
static immutable string dig2str = "-0+";

immutable static Dig[dchar] str2dig; // = ['+': Dig.P, ...];
nothrow static this() {
str2dig = ['+': Dig.P, '-':  Dig.N, '0': Dig.Z];
}

immutable pure nothrow static Dig[2][] table =
[[Dig.Z, Dig.N], [Dig.P, Dig.N], [Dig.N, Dig.Z],
[Dig.Z, Dig.Z], [Dig.P, Dig.Z], [Dig.N, Dig.P],
[Dig.Z, Dig.P]];

this(in string inp) const pure {
this.digits = inp.retro.map!(c => str2dig[c]).array;
}

this(in long inp) const pure nothrow {
this.digits = _bint2ternary(inp.BigInt);
}

this(in BigInt inp) const pure nothrow {
this.digits = _bint2ternary(inp);
}

this(in BalancedTernary inp) const pure nothrow {
// No need to dup, they are virtually immutable.
this.digits = inp.digits;
}

private this(in Dig[] inp) pure nothrow {
this.digits = inp;
}

static Dig[] _bint2ternary(in BigInt n) pure nothrow {
static py_div(T1, T2)(in T1 a, in T2 b) pure nothrow {
if (a < 0) {
return (b < 0) ?
-a / -b :
-(-a / b) - (-a % b != 0 ? 1 : 0);
} else {
return (b < 0) ?
-(a / -b) - (a % -b != 0 ? 1 : 0) :
a / b;
}
}

if (n == 0) return [];
// This final switch in D v.2.064 is fake, not enforced.
final switch (((n % 3) + 3) % 3) { // (n % 3) is the remainder.
case 0: return Dig.Z ~ _bint2ternary(py_div(n, 3));
case 1: return Dig.P ~ _bint2ternary(py_div(n, 3));
case 2: return Dig.N ~ _bint2ternary(py_div(n + 1, 3));
}
}

@property BigInt toBint() const pure nothrow {
return reduce!((y, x) => x + 3 * y)(0.BigInt, digits.retro);
}

string toString() const pure nothrow {
if (digits.empty) return "0";
return digits.retro.map!(d => dig2str[d + 1]).array;
}

static const(Dig)[] neg_(in Dig[] digs) pure nothrow {
return digs.map!(a => -a).array;
}

BalancedTernary opUnary(string op:"-")() const pure nothrow {
return BalancedTernary(neg_(this.digits));
}

static const(Dig)[] add_(in Dig[] a, in Dig[] b, in Dig c=Dig.Z)
pure nothrow {
const a_or_b = a.length ? a : b;
if (a.empty || b.empty) {
if (c == Dig.Z)
return a_or_b;
else
} else {
// (const d, c) = table[...];
const dc = table[3 + (a.length ? a[0] : 0) +
(b.length ? b[0] : 0) + c];
const res = add_(a[1 .. \$], b[1 .. \$], dc[1]);
if (res.length || dc[0] != Dig.Z)
return [dc[0]] ~ res;
else
return res;
}
}

BalancedTernary opBinary(string op:"+")(in BalancedTernary b)
const pure nothrow {
}

BalancedTernary opBinary(string op:"-")(in BalancedTernary b)
const pure nothrow {
return this + (-b);
}

static const(Dig)[] mul_(in Dig[] a, in Dig[] b) pure nothrow {
if (a.empty || b.empty) {
return [];
} else {
const y = Dig.Z ~ mul_(a[1 .. \$], b);
final switch (a[0]) {
}
}
}

BalancedTernary opBinary(string op:"*")(in BalancedTernary b)
const pure nothrow {
return BalancedTernary(mul_(this.digits, b.digits));
}
}

void main() {
immutable a = BalancedTernary("+-0++0+");
writeln("a: ", a.toBint, ' ', a);

immutable b = BalancedTernary(-436);
writeln("b: ", b.toBint, ' ', b);

immutable c = BalancedTernary("+-++-");
writeln("c: ", c.toBint, ' ', c);

const /*immutable*/ r = a * (b - c);
writeln("a * (b - c): ", r.toBint, ' ', r);
}
```
Output:
```a: 523 +-0++0+
b: -436 -++-0--
c: 65 +-++-
a * (b - c): -262023 ----0+--0++0```

## Elixir

Translation of: Erlang
```defmodule Ternary do
def to_string(t), do: ( for x <- t, do: to_char(x) ) |> List.to_string

def from_string(s), do: ( for x <- to_char_list(s), do: from_char(x) )

defp to_char(-1), do: ?-
defp to_char(0), do: ?0
defp to_char(1), do: ?+

defp from_char(?-), do: -1
defp from_char(?0), do: 0
defp from_char(?+), do: 1

def to_ternary(n) when n > 0, do: to_ternary(n,[])
def to_ternary(n), do: neg(to_ternary(-n))

defp to_ternary(0,acc), do: acc
defp to_ternary(n,acc) when rem(n, 3) == 0, do: to_ternary(div(n, 3), [0|acc])
defp to_ternary(n,acc) when rem(n, 3) == 1, do: to_ternary(div(n, 3), [1|acc])
defp to_ternary(n,acc), do: to_ternary(div((n+1), 3), [-1|acc])

def from_ternary(t), do: from_ternary(t,0)

defp from_ternary([],acc), do: acc
defp from_ternary([h|t],acc), do: from_ternary(t, acc*3 + h)

def mul(a,b), do: mul(b,a,[])

defp mul(_,[],acc), do: acc
defp mul(b,[a|as],acc) do
bp = case a do
-1 -> neg(b)
0 -> [0]
1 -> b
end
a = add(bp, acc ++ [0])
mul(b,as,a)
end

defp neg(t), do: ( for h <- t, do: -h )

def add(a,b) when length(a) < length(b),
do: add(List.duplicate(0, length(b)-length(a)) ++ a, b)

end

end

as = "+-0++0+"; at = Ternary.from_string(as); a = Ternary.from_ternary(at)
b = -436; bt = Ternary.to_ternary(b); bs = Ternary.to_string(bt)
cs = "+-++-"; ct = Ternary.from_string(cs); c = Ternary.from_ternary(ct)
rt = Ternary.mul(at,Ternary.sub(bt,ct))
r = Ternary.from_ternary(rt)
rs = Ternary.to_string(rt)
IO.puts "a = #{as} -> #{a}"
IO.puts "b = #{bs} -> #{b}"
IO.puts "c = #{cs} -> #{c}"
IO.puts "a x (b - c) = #{rs} -> #{r}"
```
Output:
```a = +-0++0+ -> 523
b = -++-0-- -> -436
c = +-++- -> 65
a x (b - c) = 0----0+--0++0 -> -262023
```

## Erlang

```-module(ternary).
-compile(export_all).

test() ->
AS = "+-0++0+", AT = from_string(AS), A = from_ternary(AT),
B = -436, BT = to_ternary(B), BS = to_string(BT),
CS = "+-++-", CT = from_string(CS), C = from_ternary(CT),
RT = mul(AT,sub(BT,CT)),
R = from_ternary(RT),
RS = to_string(RT),
io:fwrite("A = ~s -> ~b~n",[AS, A]),
io:fwrite("B = ~s -> ~b~n",[BS, B]),
io:fwrite("C = ~s -> ~b~n",[CS, C]),
io:fwrite("A x (B - C) = ~s -> ~b~n", [RS, R]).

to_string(T) -> [to_char(X) || X <- T].

from_string(S) -> [from_char(X) || X <- S].

to_char(-1) -> \$-;
to_char(0) -> \$0;
to_char(1) -> \$+.

from_char(\$-) -> -1;
from_char(\$0) -> 0;
from_char(\$+) -> 1.

to_ternary(N) when N > 0 ->
to_ternary(N,[]);
to_ternary(N) ->
neg(to_ternary(-N)).

to_ternary(0,Acc) ->
Acc;
to_ternary(N,Acc) when N rem 3 == 0 ->
to_ternary(N div 3, [0|Acc]);
to_ternary(N,Acc) when N rem 3 == 1 ->
to_ternary(N div 3, [1|Acc]);
to_ternary(N,Acc) ->
to_ternary((N+1) div 3, [-1|Acc]).

from_ternary(T) -> from_ternary(T,0).

from_ternary([],Acc) ->
Acc;
from_ternary([H|T],Acc) ->
from_ternary(T,Acc*3 + H).

mul(A,B) -> mul(B,A,[]).

mul(_,[],Acc) ->
Acc;
mul(B,[A|As],Acc) ->
BP = case A of
-1 -> neg(B);
0 ->  [0];
1 ->  B
end,
A1 = Acc++[0],
mul(B,As,A2).

neg(T) -> [ -H || H <- T].

add(A,B) when length(A) < length(B) ->
add(A,B) when length(A) > length(B) ->

Acc;
[C|Acc];

```

Output

```234> ternary:test().
A = +-0++0+ -> 523
B = -++-0-- -> -436
C = +-++- -> 65
A x (B - C) = 0----0+--0++0 -> -262023
ok
```

## Factor

Translation of: Ruby
Translation of: Common Lisp
Works with: Factor version 0.98
```USING: kernel combinators locals formatting lint literals
sequences assocs strings arrays
math math.functions math.order ;
IN: rosetta-code.bt
{ 0 CHAR: 0 }
{ 1 CHAR: + }
{ -1 CHAR: - }
}

<PRIVATE

: bt-add-digits ( a b c -- d e )
+ + 3 +
{ { 0 -1 } { 1 -1 } { -1 0 } { 0 0 } { 1 0 } { -1 1 } { 0 1 } }
nth first2
;

PRIVATE>

! Conversion
: bt>integer ( seq -- x ) 0 [ swap 3 * + ] reduce ;
: integer>bt ( x -- x ) [ dup zero? not ] [
dup 3 rem {
{ 0 [ 3 / 0 ] }
{ 1 [ 3 / round 1 ] }
{ 2 [ 1 + 3 / round -1 ] }
} case
] produce nip reverse
;
: bt>string ( seq -- str ) [ addlookup at ] map >string ;
: string>bt ( str -- seq ) [ addlookup value-at ] { } map-as ;

! Arithmetic
: bt-neg ( a -- -a ) [ neg ] map ;
:: bt-add ( u v -- w )
u v max-length :> maxl
u v [ maxl 0 pad-head reverse ] bi@ :> ( u v )
0 :> carry!
u v { } [ carry bt-add-digits carry! prefix ] 2reduce
carry prefix [ zero? ] trim-head
;
: bt-sub ( u v -- w ) bt-neg bt-add ;
:: bt-mul ( u v -- w ) u { } [
{
{ -1 [ v bt-neg ] }
{ 0  [ { } ] }
{ 1  [ v ] }
] reduce
;

[let
"+-0++0+" string>bt :> a
-436 integer>bt     :> b
"+-++-" string>bt   :> c
b c bt-sub a bt-mul :> d
"a" a bt>integer a bt>string "%s: %d, %s\n" printf
"b" b bt>integer b bt>string "%s: %d, %s\n" printf
"c" c bt>integer c bt>string "%s: %d, %s\n" printf
"a*(b-c)" d bt>integer d bt>string "%s: %d, %s\n" printf
]
```
```a: 523, +-0++0+
b: -436, -++-0--
c: 65, +-++-
a*(b-c): -262023, ----0+--0++0
```

## FreeBASIC

Translation of: Liberty BASIC
```#define MAX(a, b) iif((a) > (b), (a), (b))
Dim Shared As Integer pow, signo
Dim Shared As String t
t = "-0+"

Function deci(cadena As String) As Integer
Dim As Integer i, deci1
Dim As String c1S
pow = 1
For i = Len(cadena) To 1 Step -1
signo = Instr(t, c1S)-2
deci1 = deci1 + pow * signo
pow *= 3
Next i
Return deci1
End Function

Function ternary(n As Integer) As String
Dim As String ternario
Dim As Integer i, k
While Abs(n) > 3^k/2
k += 1
Wend
k -= 1

pow = 3^k
For i = k To 0 Step -1
signo = (n>0) - (n<0)
signo *= (Abs(n) > pow/2)
ternario += Mid(t,signo+2,1)
n -= signo*pow
pow /= 3
Next
If ternario = "" Then ternario = "0"
Return ternario
End Function

Function negate(cadena As String) As String
Dim As String negar = ""
For i As Integer = 1 To Len(cadena)
negar += Mid(t, 4-Instr(t, Mid(cadena,i,1)), 1)
Next i
Return negar
End Function

Dim As String relleno = cadenaA
While Len(relleno) < n
relleno = "0" + relleno
Wend
Return relleno
End Function

Dim As Integer i, x, y, z
Dim As String resultado = ""
Dim As Byte llevar = 0
For i = l To 1 Step -1
z = x + y + llevar

If Abs(z) < 2 Then
llevar = 0
Elseif z > 0 Then
llevar = 1: z -= 3
Elseif z < 0 Then
llevar = -1: z += 3
End If

Next i

i = 0
i += 1
Wend
End Function

End Function

Dim As String resultado = ""
Dim As String tS = "", cambio = ""
For i As Integer = Len(cadenaA) To 1 Step -1
Case "0": tS = "0"
End Select

cambio += "0"
Next i
End Function

Dim As String cadenaA = "+-0++0+"
Dim As Integer a = deci(cadenaA)

Dim As Integer b = -436
Dim As String cadenaB = ternary(b)

Dim As String cadenaC = "+-++-"
Dim As Integer c = deci(cadenaC)

'calcular en ternario
Print "a*(b-c):", deci(resS), resS

Print !"\nComprobamos:"
Print "a*(b-c): ", a * (b - c)
Sleep```
Output:
```      a:       523          +-0++0+
b:      -436          -++-0--
c:       65           +-++-
a*(b-c):      -262023       ----0+--0++0
Comprobamos:
a*(b-c):      -262023
```

## Glagol

```ОТДЕЛ Сетунь+;
ИСПОЛЬЗУЕТ
Параметр ИЗ "...\Отделы\Обмен\",
Текст ИЗ "...\Отделы\Числа\",
Вывод ИЗ "...\Отделы\Обмен\";

ПЕР
зч: РЯД 10 ИЗ ЗНАК;
счпоз: ЦЕЛ;
число: ЦЕЛ;
память: ДОСТУП К НАБОР
ячейки: РЯД 20 ИЗ ЦЕЛ;
размер: УЗКЦЕЛ;
отрицательное: КЛЮЧ
КОН;

ЗАДАЧА СоздатьПамять;
УКАЗ
СОЗДАТЬ(память);
память.размер := 0;
память.отрицательное := ОТКЛ
КОН СоздатьПамять;

ЗАДАЧА ДобавитьВПамять(что: ЦЕЛ);
УКАЗ
память.ячейки[память.размер] := что;
УВЕЛИЧИТЬ(память.размер)
КОН ДобавитьВПамять;

ЗАДАЧА ОбратитьПамять;
ПЕР
зчсл: ЦЕЛ;
сч: ЦЕЛ;
УКАЗ
ОТ сч := 0 ДО память.размер ДЕЛИТЬ 2 - 1 ВЫП
зчсл := память.ячейки[сч];
память.ячейки[сч] := память.ячейки[память.размер-сч-1];
память.ячейки[память.размер-сч-1] := зчсл
КОН
КОН ОбратитьПамять;

ЗАДАЧА ВывестиПамять;
ПЕР
сч: ЦЕЛ;
УКАЗ
ОТ сч := 0 ДО память.размер-1 ВЫП
ЕСЛИ память.ячейки[сч] < 0 ТО
Вывод.Цепь("-")
АЕСЛИ память.ячейки[сч] > 0 ТО
Вывод.Цепь("+")
ИНАЧЕ Вывод.Цепь("0") КОН
КОН
КОН ВывестиПамять;

ЗАДАЧА УдалитьПамять;
УКАЗ
память := ПУСТО
КОН УдалитьПамять;

ЗАДАЧА Перевести(число: ЦЕЛ);
ПЕР
о: ЦЕЛ;
з: КЛЮЧ;
ЗАДАЧА ВПамять(что: ЦЕЛ);
УКАЗ
ЕСЛИ память.отрицательное ТО
ЕСЛИ что < 0 ТО ДобавитьВПамять(1)
АЕСЛИ что > 0 ТО ДобавитьВПамять(-1)
ИНАЧЕ ДобавитьВПамять(0) КОН
ИНАЧЕ
ДобавитьВПамять(что)
КОН
КОН ВПамять;
УКАЗ
ЕСЛИ число < 0 ТО память.отрицательное := ВКЛ КОН;
число := МОДУЛЬ(число);
з := ОТКЛ;
ПОКА число > 0 ВЫП
о := число ОСТАТОК 3;
число := число ДЕЛИТЬ 3;
ЕСЛИ з ТО
ЕСЛИ о = 2 ТО ВПамять(0) АЕСЛИ о = 1 ТО ВПамять(-1) ИНАЧЕ ВПамять(1); з := ОТКЛ КОН
ИНАЧЕ
ЕСЛИ о = 2 ТО ВПамять(-1); з := ВКЛ ИНАЧЕ ВПамять(о) КОН
КОН
КОН;
ЕСЛИ з ТО ВПамять(1) КОН;
ОбратитьПамять;
ВывестиПамять(ВКЛ);
КОН Перевести;

ЗАДАЧА ВЧисло(): ЦЕЛ;
ПЕР
сч, мн: ЦЕЛ;
результат: ЦЕЛ;
УКАЗ
результат := 0;
мн := 1;
ОТ сч := 0 ДО память.размер-1 ВЫП
УВЕЛИЧИТЬ(результат, память.ячейки[память.размер-сч-1]*мн);
мн := мн * 3
КОН;
ВОЗВРАТ результат
КОН ВЧисло;

УКАЗ
Параметр.Текст(1, зч); счпоз := 0;
число := Текст.ВЦел(зч, счпоз);
СоздатьПамять;
Перевести(число);
Вывод.ЧЦел(" = %d.", ВЧисло(), 0, 0, 0);
УдалитьПамять

КОН Сетунь.
```

A crude English/Pidgin Algol translation of the above Category:Glagol code.

```PROGRAM Setun+;
USES
Parameter IS "...\Departments\Exchange\"
Text IS "...\Departments\Numbers\"
Output IS "...\Departments\Exchange\";

VAR
AF: RANGE 10 IS SIGN;
mfpos: INT;
number: INT;
cell: RANGE 20 IS INT;
size: UZKEL;
negative: BOOL
END;

PROC Create.Memory;
BEGIN
CREATE(memory);
memory.size := 0;
memory.negative := FALSE
END Create.Memory;

BEGIN
memory.cells[memory.size] := that;
ZOOM(memory.size)

PROC Invert.Memory;
VAR
zchsl: INT;
account: INT;
BEGIN
FOR cq := 0 TO memory.size DIVIDE 2 - 1 DO
zchsl := memory.cells[cq];
memory.cells[cq] := memory.cells[memory.size-size-1];
memory.cells[memory.size-MF-1] := zchsl
END
END Invert.Memory;

PROC Withdraw.Memory;
VAR
account: INT;
BEGIN
FOR cq := 0 TO memory.size-1 DO
IF memory.cells[cq] < 0 THEN
Output.Append("-")
ANDIF memory.cells[cq] > 0 THEN
Output.Append("+")
ELSE Output.Append("0") END
END
END Withdraw.Memory;

PROC Remove.Memory;
BEGIN
memory := Empty
END Remove.Memory;

PROC Translate(number: INT)
VAR
s: BOOL;
PROC B.Memory(that: INT)
BEGIN
IF memory.negative THEN
IF that < 0 THEN Add.Memory(1)
ANDIF that > 0 THEN Add.Memory(1)
ELSE
END
END B.Memory;
BEGIN
IF number < 0 THEN memory.negative := TRUE END;
number := UNIT(number)
s := FALSE;
WHILE number > 0 DO
number := number DIVIDE 3;
IF s THEN
IF about = 2 THEN B.Memory(0) ANDIF about = 1 THEN B.Memory(1) ELSE B.Memory(1) s := FALSE END
ELSE
IF about = 2 THEN B.Memory(-1) s := TRUE ELSE B.Memory(a) END
END
END;
IF s THEN B.Memory(1) END;
Invert.Memory;
Withdraw.Memory(TRUE)
END Translate;

PROC InNumber(): INT;
VAR
MF, MN: INT;
result: INT;
BEGIN
result := 0
pl := 1;
FOR cq := 0 TO memory.size-1 DO
ZOOM(result, memory.Cells[memory.size-cq-1] * mn);
pl := pl * 3
END;
RETURN result;
END InNumber;

BEGIN
Parameter.Text(1, AF); mfpos := 0;
number := Text.Whole(AF, mfpos);
Create.Memory;
Translate(number);
Output.ChTarget(" = %d.", InNumber(), 0, 0, 0);
Remove.Memory
END Setun.```

## Go

```package main

import (
"fmt"
"strings"
)

// R1: representation is a slice of int8 digits of -1, 0, or 1.
// digit at index 0 is least significant.  zero value of type is
// representation of the number 0.
type bt []int8

// R2: string conversion:

// btString is a constructor.  valid input is a string of any length
// consisting of only '+', '-', and '0' characters.
// leading zeros are allowed but are trimmed and not represented.
// false return means input was invalid.
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
}

// String method converts the other direction, returning a string of
// '+', '-', and '0' characters representing the number.
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)
}

// R3: integer conversion
// int chosen as "native integer"

// btInt is a constructor like btString.
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
}

// Int method converts the other way, returning the value as an int type.
// !ok means overflow occurred during conversion, not necessarily that the
// value is not representable as an int.  (Of course there are other ways
// of doing it but this was chosen as "reasonable.")
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
}

// R4: negation, addition, and multiplication

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:]
case -1:
p := r[i:]
}
}
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)
}

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")
}
}
```
Output:
```     a:      +-0++0+     523
b:      -++-0--    -436
c:        +-++-      65
a(b-c): ----0+--0++0 -262023
```

## Groovy

Solution:

```enum T {
m('-', -1), z('0', 0), p('+', 1)

final String symbol
final int value

private T(String symbol, int value) {
this.symbol = symbol
this.value = value
}

static T get(Object key) {
switch (key) {
case [m.value, m.symbol] : return m
case [z.value, z.symbol] : return z
case [p.value, p.symbol] : return p
default:                   return null
}
}

T negative() {
T.get(-this.value)
}

String toString() { this.symbol }
}

class BalancedTernaryInteger {

static final MINUS = new BalancedTernaryInteger(T.m)
static final ZERO  = new BalancedTernaryInteger(T.z)
static final PLUS  = new BalancedTernaryInteger(T.p)
private static final LEADING_ZEROES = /^0+/

final String value

BalancedTernaryInteger(String bt) {
assert bt && bt.toSet().every { T.get(it) }
}

BalancedTernaryInteger(BigInteger i) {
this(i == 0 ? T.z.symbol : valueFromInt(i));
}

BalancedTernaryInteger(T...tArray) {
this(tArray.sum{ it.symbol });
}

BalancedTernaryInteger(List<T> tList) {
this(tList.sum{ it.symbol });
}

private static String valueFromInt(BigInteger i) {
assert i != null
if (i < 0) return negate(valueFromInt(-i))
if (i == 0) return ''
int bRem = (((i % 3) - 2) ?: -3) + 2
valueFromInt((i - bRem).intdiv(3)) + T.get(bRem)
}

private static String negate(String bt) {
bt.collect{ T.get(it) }.inject('') { str, t ->
str + (-t)
}
}

private static final Map INITIAL_SUM_PARTS = [carry:T.z, sum:[]]
private static final prepValueLen = { int len, String s ->
s.padLeft(len + 1, T.z.symbol).collect{ T.get(it) }
}
private static final partCarrySum = { partialSum, carry, trit ->
[carry: carry, sum: [trit] + partialSum]
}
private static final partSum = { parts, trits ->
def carrySum = partCarrySum.curry(parts.sum)
switch ((trits + parts.carry).sort()) {
case [[T.m, T.m, T.m]]:                  return carrySum(T.m, T.z) //-3
case [[T.m, T.m, T.z]]:                  return carrySum(T.m, T.p) //-2
case [[T.m, T.z, T.z], [T.m, T.m, T.p]]: return carrySum(T.z, T.m) //-1
case [[T.z, T.z, T.z], [T.m, T.z, T.p]]: return carrySum(T.z, T.z) //+0
case [[T.z, T.z, T.p], [T.m, T.p, T.p]]: return carrySum(T.z, T.p) //+1
case [[T.z, T.p, T.p]]:                  return carrySum(T.p, T.m) //+2
case [[T.p, T.p, T.p]]: default:         return carrySum(T.p, T.z) //+3
}
}

BalancedTernaryInteger plus(BalancedTernaryInteger that) {
assert that != null
if (this == ZERO) return that
if (that == ZERO) return this
def prep = prepValueLen.curry([value.size(), that.value.size()].max())
List values = [prep(value), prep(that.value)].transpose()
new BalancedTernaryInteger(values[-1..(-values.size())].inject(INITIAL_SUM_PARTS, partSum).sum)
}

BalancedTernaryInteger negative() {
!this ? this : new BalancedTernaryInteger(negate(value))
}

BalancedTernaryInteger minus(BalancedTernaryInteger that) {
assert that != null
this + -that
}

private static final INITIAL_PRODUCT_PARTS = [sum:ZERO, pad:'']
private static final sigTritCount = { it.value.replaceAll(T.z.symbol,'').size() }

}

private BalancedTernaryInteger partialProduct(T multiplier, String pad){
switch (multiplier) {
case T.z:          return ZERO
}
}

BalancedTernaryInteger multiply(BalancedTernaryInteger that) {
assert that != null
if (that == ZERO)  return ZERO
if (that == PLUS)  return this
if (that == MINUS) return -this
if (this.value.size() == 1 || sigTritCount(this) < sigTritCount(that)) {
return that.multiply(this)
}
that.value.collect{ T.get(it) }[-1..(-value.size())].inject(INITIAL_PRODUCT_PARTS) { parts, multiplier ->
}.sum
}

BigInteger asBigInteger() {
value.collect{ T.get(it) }.inject(0) { i, trit -> i * 3 + trit.value }
}

def asType(Class c) {
switch (c) {
case Integer:              return asBigInteger() as Integer
case Long:                 return asBigInteger() as Long
case [BigInteger, Number]: return asBigInteger()
case Boolean:              return this != ZERO
default:                   return super.asType(c)
}
}

boolean equals(Object that) {
switch (that) {
case BalancedTernaryInteger: return this.value == that?.value
default:                     return super.equals(that)
}
}

int hashCode() { this.value.hashCode() }

String toString() { value }
}
```

Test:

```BalancedTernaryInteger a = new BalancedTernaryInteger('+-0++0+')
BalancedTernaryInteger b = new BalancedTernaryInteger(-436)
BalancedTernaryInteger c = new BalancedTernaryInteger(T.p, T.m, T.p, T.p, T.m)
BalancedTernaryInteger bmc = new BalancedTernaryInteger(-436 - (c as Integer))
BalancedTernaryInteger atbmc = new BalancedTernaryInteger((a as Integer) * (-436 - (c as Integer)))

printf ("%9s = %12s %8d\n", 'a', "\${a}", a as Number)
printf ("%9s = %12s %8d\n", 'b', "\${b}", b as Number)
printf ("%9s = %12s %8d\n", 'c', "\${c}", c as Number)
assert (b-c) == bmc
printf ("%9s = %12s %8d\n", 'b-c', "\${b-c}", (b-c) as Number)
assert (a * (b-c)) == atbmc
printf ("%9s = %12s %8d\n", 'a * (b-c)', "\${a * (b-c)}", (a * (b-c)) as Number)

println "\nDemonstrate failure:"
assert (a * (b-c)) == a
```

Output:

```        a =      +-0++0+      523
b =      -++-0--     -436
c =        +-++-       65
b-c =      -+0-++0     -501
a * (b-c) = ----0+--0++0  -262023

Demonstrate failure:
Caught: Assertion failed:

assert (a * (b-c)) == a
| |  |||   |  |
| |  |||   |  +-0++0+
| |  |||   false
| |  ||+-++-
| |  |-+0-++0
| |  -++-0--
| ----0+--0++0
+-0++0+
...```

BTs are represented internally as lists of digits in integers from -1 to 1, but displayed as "+-0" strings.

```data BalancedTernary = Bt [Int]

zeroTrim a = if null s then [0] else s where
s = fst \$ foldl f ([],[]) a
f (x,y) 0 = (x, y++[0])
f (x,y) z = (x++y++[z], [])

btList (Bt a) = a

instance Eq BalancedTernary where
(==) a b = btList a == btList b

btNormalize = listBt . _carry 0 where
_carry c [] = if c == 0 then [] else [c]
_carry c (a:as) = r:_carry cc as where
(cc, r) = f \$ (a+c) `quotRem` 3 where
f (x,  2) = (x + 1, -1)
f (x, -2) = (x - 1,  1)
f x = x

listBt = Bt . zeroTrim

instance Show BalancedTernary where
show = reverse . map (\d->case d of -1->'-'; 0->'0'; 1->'+') . btList

strBt = Bt . zeroTrim.reverse.map (\c -> case c of '-' -> -1; '0' -> 0; '+' -> 1)

intBt :: Integral a => a -> BalancedTernary
intBt = fromIntegral . toInteger

btInt = foldr (\a z -> a + 3 * z) 0 . btList

listAdd a b = take (max (length a) (length b)) \$ zipWith (+) (a++[0,0..]) (b++[0,0..])

-- mostly for operators, also small stuff to make GHC happy
instance Num BalancedTernary where
negate = Bt . map negate . btList
(+) x y = btNormalize \$ listAdd (btList x) (btList y)
(*) x y = btNormalize \$ mul_ (btList x) (btList y) where
mul_ _ [] = []
mul_ as b = foldr (\a z -> listAdd (map (a*) b) (0:z)) [] as

-- we don't need to define binary "-" by hand

signum (Bt a) = if a == [0] then 0 else Bt [last a]
abs x = if signum x == Bt [-1] then negate x else x

fromInteger = btNormalize . f where
f 0 = []
f x = fromInteger (rem x 3) : f (quot x 3)

main = let	(a,b,c) = (strBt "+-0++0+", intBt (-436), strBt "+-++-")
r = a * (b - c)
in do
print \$ map btInt [a,b,c]
print \$ r
print \$ btInt r
```

## Icon and Unicon

Translation of: java

Works in both languages:

```procedure main()
a := "+-0++0+"
write("a = +-0++0+"," = ",cvtFromBT("+-0++0+"))
write("b = -436 = ",b := cvtToBT(-436))
c := "+-++-"
write("c = +-++- = ",cvtFromBT("+-++-"))
d := mul(a,sub(b,c))
write("a(b-c) = ",d," = ",cvtFromBT(d))
end

procedure bTrim(s)
return s[upto('+-',s):0] | "0"
end

procedure cvtToBT(n)
if n=0 then return "0"
if n<0 then return map(cvtToBT(-n),"+-","-+")
return bTrim(case n%3 of {
0: cvtToBT(n/3)||"0"
1: cvtToBT(n/3)||"+"
2: cvtToBT((n+1)/3)||"-"
})
end

procedure cvtFromBT(n)
sum := 0
i := -1
every c := !reverse(n) do {
sum +:= case c of {
"+" : 1
"-" : -1
"0" : 0
}*(3^(i+:=1))
}
return sum
end

procedure neg(n)
return map(n,"+-","-+")
end

if *b > *a then a :=: b
b := repl("0",*a-*b)||b
c := "0"
sum := ""
every place := 1 to *a do {
c := if *ds > 1 then c := ds[1] else "0"
sum := ds[-1]||sum
}
return bTrim(c||sum)
end

if *sum1 = 1 then return sum2
if *sum2 = 1 then return sum1[1]||sum2
return sum1[1]
end

return case(a||b) of {
"00"|"0+"|"0-": b
"+0"|"-0"     : a
"++"          : "+-"
"+-"|"-+"     : "0"
"--"          : "-+"
}
end

procedure sub(a,b)
end

procedure mul(a,b)
if b[1] == "-" then {
b := neg(b)
negate := "yes"
}
b := cvtFromBT(b)
i := "+"
mul := "0"
while cvtFromBT(i) <= b do {
}
return (\negate,map(mul,"+-","-+")) | mul
end
```

Output:

```->bt
a = +-0++0+ = 523
b = -436 = -++-0--
c = +-++- = 65
a(b-c) = ----0+--0++0 = -262023
->
```

## J

Implementation:

```trigits=: 1+3 <.@^. 2 * 1&>.@|
trinOfN=: |.@((_1 + ] #: #.&1@] + [) #&3@trigits) :. nOfTrin
nOfTrin=: p.&3 :. trinOfN
trinOfStr=: 0 1 _1 {~ '0+-'&i.@|. :. strOfTrin
strOfTrin=: {&'0+-'@|. :. trinOfStr

carry=: +//.@:(trinOfN"0)^:_

neg=: -
```

trinary numbers are represented as a sequence of polynomial coefficients. The coefficient values are limited to 1, 0, and -1. The polynomial's "variable" will always be 3 (which happens to illustrate an interesting absurdity in the terminology we use to describe polynomials -- one which might be an obstacle for learning, for some people).

`trigits` computes the number of trinary "digits" (that is, the number of polynomial coefficients) needed to represent an integer. pseudocode: `1+floor(log3(2*max(1,abs(n)))`. Note that floating point inaccuracies combined with comparison tolerance may lead to a [harmless] leading zero when converting incredibly large numbers.

foo`Of`Bar converts a bar into a foo. These functions are all invertable (so we can map from one domain to another, perform an operation, and map back using J's under). This aspect is not needed for this task and the definitions could be made simpler by removing it (removing the `:. obverse` clauses), but it made testing and debugging easier.

`carry` performs carry propagation. (Intermediate results will have overflowed trinary representation and become regular integers, so we convert them back into trinary and then perform a polynomial sum, repeating until the result is the same as the argument.)

`trimLead0` removes leading zeros from a sequence of polynomial coefficients.

`add` adds these polynomials.
`neg` negates these polynomials. Note that it's just a name for J's `-`.
`mul` multiplies these polynomials.

Definitions for example:

```a=: trinOfStr '+-0++0+'
b=: trinOfN -436
c=: trinOfStr '+-++-'
```

Required example:

```   nOfTrin&> a;b;c
523 _436 65

strOfTrin a mul b (add -) c
----0+--0++0
nOfTrin   a mul b (add -) c
_262023
```

## Java

```/*
* Test case
* With balanced ternaries a from string "+-0++0+", b from native integer -436, c "+-++-":
* Write out a, b and c in decimal notation;
* Calculate a × (b − c), write out the result in both ternary and decimal notations.
*/
public class BalancedTernary
{
public static void main(String[] args)
{
BTernary a=new BTernary("+-0++0+");
BTernary b=new BTernary(-436);
BTernary c=new BTernary("+-++-");

System.out.println("a="+a.intValue());
System.out.println("b="+b.intValue());
System.out.println("c="+c.intValue());
System.out.println();

//result=a*(b-c)
BTernary result=a.mul(b.sub(c));

System.out.println("result= "+result+" "+result.intValue());
}

public static class BTernary
{
String value;
public BTernary(String s)
{
int i=0;
while(s.charAt(i)=='0')
i++;
this.value=s.substring(i);
}
public BTernary(int v)
{
this.value="";
this.value=convertToBT(v);
}

private String convertToBT(int v)
{
if(v<0)
return flip(convertToBT(-v));
if(v==0)
return "";
int rem=mod3(v);
if(rem==0)
return convertToBT(v/3)+"0";
if(rem==1)
return convertToBT(v/3)+"+";
if(rem==2)
return convertToBT((v+1)/3)+"-";
return "You can't see me";
}
private String flip(String s)
{
String flip="";
for(int i=0;i<s.length();i++)
{
if(s.charAt(i)=='+')
flip+='-';
else if(s.charAt(i)=='-')
flip+='+';
else
flip+='0';
}
return flip;
}
private int mod3(int v)
{
if(v>0)
return v%3;
v=v%3;
return (v+3)%3;
}

public int intValue()
{
int sum=0;
String s=this.value;
for(int i=0;i<s.length();i++)
{
char c=s.charAt(s.length()-i-1);
int dig=0;
if(c=='+')
dig=1;
else if(c=='-')
dig=-1;
sum+=dig*Math.pow(3, i);
}
return sum;
}

{
String a=this.value;
String b=that.value;

String longer=a.length()>b.length()?a:b;
String shorter=a.length()>b.length()?b:a;

while(shorter.length()<longer.length())
shorter=0+shorter;

a=longer;
b=shorter;

char carry='0';
String sum="";
for(int i=0;i<a.length();i++)
{
int place=a.length()-i-1;
if(digisum.length()!=1)
carry=digisum.charAt(0);
else
carry='0';
sum=digisum.charAt(digisum.length()-1)+sum;
}
sum=carry+sum;

return new BTernary(sum);
}
private String addDigits(char a,char b,char carry)
{
//System.out.println(carry+" "+sum1+" "+sum2);
if(sum1.length()==1)
return sum2;
if(sum2.length()==1)
return sum1.charAt(0)+sum2;
return sum1.charAt(0)+"";
}
{
String sum="";
if(a=='0')
sum=b+"";
else if (b=='0')
sum=a+"";
else if(a=='+')
{
if(b=='+')
sum="+-";
else
sum="0";
}
else
{
if(b=='+')
sum="0";
else
sum="-+";
}
return sum;
}

public BTernary neg()
{
return new BTernary(flip(this.value));
}

public BTernary sub(BTernary that)
{
}

public BTernary mul(BTernary that)
{
BTernary one=new BTernary(1);
BTernary zero=new BTernary(0);
BTernary mul=new BTernary(0);

int flipflag=0;
if(that.compareTo(zero)==-1)
{
that=that.neg();
flipflag=1;
}

if(flipflag==1)
mul=mul.neg();
return mul;
}

public boolean equals(BTernary that)
{
return this.value.equals(that.value);
}
public int compareTo(BTernary that)
{
if(this.intValue()>that.intValue())
return 1;
else if(this.equals(that))
return 0;
return -1;
}

public String toString()
{
return value;
}
}
}
```

Output:

```a=523
b=-436
c=65

result= ----0+--0++0 -262023
```

## jq

Works with: jq

Works with gojq, the Go implementation of jq

```### Generic utilities

# Emit a stream of the constituent characters of the input string
def chars: explode[] | [.] | implode;

# Flip "+" and "-" in the input string, and change other characters to 0
def flip:
{"+": "-", "-": "+"} as \$t
| reduce chars as \$c (""; . + (\$t[\$c] // "0") );

### Balanced ternaries (BT)

# Input is assumed to be an integer (use `new` if checking is required)
def toBT:
# Helper - input should be an integer
def mod3:
if . > 0 then . % 3
else ((. % 3) + 3) % 3
end;

if . < 0 then - . | toBT | flip
else if . == 0 then ""
else mod3 as \$rem
| if   \$rem == 0 then (. / 3 | toBT) + "0"
elif \$rem == 1 then (. / 3 | toBT) + "+"
else                ((. + 1) / 3 | toBT) + "-"
end
end
| sub("^00*";"")
| if . == "" then "0" end
end ;

# Input: BT
def integer:
. as \$in
| length as \$len
| { sum: 0,
pow: 1 }
| reduce range (0;\$len) as \$i (.;
\$in[\$len-\$i-1: \$len-\$i] as \$c
| (if \$c == "+" then 1 elif \$c == "-" then -1 else 0 end) as \$digit
| if \$digit != 0 then .sum += \$digit * .pow else . end
| .pow *= 3 )
| .sum ;

# If the input is a string, check it is a valid BT, and trim leading 0s;
# if the input is an integer, convert it to a BT;
# otherwise raise an error.
def new:
if type == "string" and all(chars; IN("0", "+", "-"))
then sub("^00*"; "") | if . == "" then "0" end
elif type == "number" and trunc == .
then toBT
else "'new' given invalid input: \(.)" | error
end;

# . + \$b
def plus(\$b):
# Helper functions:
def at(\$i): .[\$i:\$i+1];

# \$a and \$b should each be "0", "+" or "-"
if \$a == "0" then \$b
elif \$b == "0" then \$a
elif \$a == "+"
then if \$b == "+" then "+-" else "0" end
elif \$b == "+" then "0" else "-+"
end;

| if (\$sum1|length) == 1
then \$sum2
elif (\$sum2|length) == 1
then \$sum1[0:1] + \$sum2
else \$sum1[0:1]
end;

{ longer:  (if length > (\$b|length) then . else \$b end),
shorter: (if length > (\$b|length) then \$b else . end) }
| until ( (.shorter|length) >= (.longer|length); .shorter = "0" + .shorter )
| .a = .longer
| .b = .shorter
| .carry = "0"
| .sum = ""
| reduce range(0; .a|length) as \$i (.;
( (.a|length) - \$i - 1) as \$place
| addDigits3(.a | at(\$place); .b | at(\$place); .carry) as \$digisum
| .carry = (if (\$digisum|length) != 1 then \$digisum[0:1] else "0" end)
| .sum = \$digisum[-1:] + .sum )
| .carry + .sum
| new;

def minus: flip;

# . - \$b
def minus(\$b): plus(\$b | flip);

def mult(\$b):
(1 | new) as \$one
| (0 | new) as \$zero
| { a: .,
\$b,
mul: \$zero,
flipFlag: false }
| if .b[0:1] == "-"  # i.e. .b < 0
then .b |= minus
| .flipFlag = true
end
| .i = \$one
| .in = 1
| (.b | integer) as \$bn
| until ( .in > \$bn;
.a as \$a
| .mul |= plus(\$a)
| .i |= plus(\$one)
| .in += 1 )
| if .flipFlag then .mul | minus else .mul end ;

### Illustration

def a: "+-0++0+";
def b: -436 | new;
def c:  "+-++-";

(a | integer) as \$an
| (b | integer) as \$bn
| (c | integer) as \$cn
| (\$an * (\$bn - \$cn)) as \$in
| (a | mult( (b | minus(c)))) as \$i
| "a = \(\$an)",
"b = \(\$bn)",
"c = \(\$cn)",
"a * (b - c) = \(\$i) ~ \(\$in) => \(\$in|new)"```
Output:
```a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 ~ -262023 => ----0+--0++0
```

## Julia

Works with: Julia version 0.6
Translation of: Python
```struct BalancedTernary <: Signed
digits::Vector{Int8}
end
BalancedTernary() = zero(BalancedTernary)
BalancedTernary(n) = convert(BalancedTernary, n)

const sgn2chr = Dict{Int8,Char}(-1 => '-', 0 => '0', +1 => '+')
Base.show(io::IO, bt::BalancedTernary) = print(io, join(sgn2chr[x] for x in reverse(bt.digits)))
Base.copy(bt::BalancedTernary) = BalancedTernary(copy(bt.digits))
Base.zero(::Type{BalancedTernary}) = BalancedTernary(Int8[0])
Base.iszero(bt::BalancedTernary) = bt.digits == Int8[0]
Base.convert(::Type{T}, bt::BalancedTernary) where T<:Number = sum(3 ^ T(ex - 1) * s for (ex, s) in enumerate(bt.digits))
function Base.convert(::Type{BalancedTernary}, n::Signed)
r = BalancedTernary(Int8[])
if iszero(n) push!(r.digits, 0) end
while n != 0
if mod(n, 3) == 0
push!(r.digits, 0)
n = fld(n, 3)
elseif mod(n, 3) == 1
push!(r.digits, 1)
n = fld(n, 3)
else
push!(r.digits, -1)
n = fld(n + 1, 3)
end
end
return r
end
const chr2sgn = Dict{Char,Int8}('-' => -1, '0' => 0, '+' => 1)
function Base.convert(::Type{BalancedTernary}, s::AbstractString)
return BalancedTernary(getindex.(chr2sgn, collect(reverse(s))))
end

macro bt_str(s)
convert(BalancedTernary, s)
end

const table = NTuple{2,Int8}[(0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1)]
if isempty(a) || isempty(b)
if c == 0 return isempty(a) ? b : a end
return _add([c], isempty(a) ? b : a)
else
d, c = table[4 + (isempty(a) ? 0 : a[1]) + (isempty(b) ? 0 : b[1]) + c]
if !isempty(r) || d != 0
return unshift!(r, d)
else
return r
end
end
end
function Base.:+(a::BalancedTernary, b::BalancedTernary)
return isempty(v) ? BalancedTernary(0) : BalancedTernary(v)
end
Base.:-(bt::BalancedTernary) = BalancedTernary(-bt.digits)
Base.:-(a::BalancedTernary, b::BalancedTernary) = a + (-b)
function _mul(a::Vector{Int8}, b::Vector{Int8})
if isempty(a) || isempty(b)
return Int8[]
else
if a[1] == -1 x = (-BalancedTernary(b)).digits
elseif a[1] == 0 x = Int8[]
elseif a[1] == 1 x = b end
y = append!(Int8[0], _mul(a[2:end], b))
end
end
function Base.:*(a::BalancedTernary, b::BalancedTernary)
v = _mul(a.digits, b.digits)
return isempty(v) ? BalancedTernary(0) : BalancedTernary(v)
end

a = bt"+-0++0+"
println("a: \$(Int(a)), \$a")
b = BalancedTernary(-436)
println("b: \$(Int(b)), \$b")
c = BalancedTernary("+-++-")
println("c: \$(Int(c)), \$c")
r = a * (b - c)
println("a * (b - c): \$(Int(r)), \$r")

@assert Int(r) == Int(a) * (Int(b) - Int(c))
```
Output:
```a: 523, +-0++0+
b: -436, -++-0--
c: 65, +-++-
a * (b - c): -262023, ----0+--0++0```

## Koka

Based on the OCaml version

```type btdigit
Pos
Zero
Neg

alias btern = list<btdigit>

fun to_string(n: btern): string
join(
n.reverse.map fn(d)
match d
Pos -> "+"
Zero -> "0"
Neg -> "-"
)

fun from_string(s: string): exn btern
var sl := Nil
s.foreach fn(c)
match c
'+' -> sl := Cons(Pos, sl)
'0' -> sl := Cons(Zero, sl)
'-' -> sl := Cons(Neg, sl)
_ -> throw("Invalid Character")
sl

fun to_int(n: btern): int
match n
Nil -> 0
Cons(Zero, Nil) -> 0
Cons(Pos, rst) -> 1+3*rst.to_int
Cons(Neg, rst) -> -1+3*rst.to_int
Cons(Zero, rst) -> 3*rst.to_int

fun from_int(n: int): <exn> btern
if n == 0 then [] else
match n % 3
0 -> Cons(Zero, from_int((n/3).unsafe-decreasing))
1 -> Cons(Pos, from_int(((n - 1)/3).unsafe-decreasing))
2 -> Cons(Neg, from_int(((n+1)/3).unsafe-decreasing))
_ -> throw("Impossible")

fun (+)(n1: btern, n2: btern): <exn,div> btern
match (n1, n2)
([], a) -> a
(a, []) -> a
(Cons(Pos, t1), Cons(Neg, t2)) ->
val sum = t1 + t2
if sum.is-nil then [] else Cons(Zero, sum)
(Cons(Neg, t1), Cons(Pos, t2)) ->
val sum = t1 + t2
if sum.is-nil then [] else Cons(Zero, sum)
(Cons(Zero, t1), Cons(Zero, t2)) ->
val sum = t1 + t2
if sum.is-nil then [] else Cons(Zero, sum)
(Cons(Pos, t1), Cons(Pos, t2)) -> Cons(Neg, t1 + t2 + [Pos])
(Cons(Neg, t1), Cons(Neg, t2)) -> Cons(Pos, t1 + t2 + [Neg])
(Cons(Zero, t1), Cons(h, t2)) -> Cons(h, t1 + t2)
(Cons(h, t1), Cons(Zero, t2)) -> Cons(h, t1 + t2)
_ -> throw("Impossible")

fun neg(n: btern)
n.map fn(d)
match d
Pos -> Neg
Zero -> Zero
Neg -> Pos

fun (-)(n1: btern, n2: btern): <exn,div> btern
n1 + neg(n2)

fun (*)(n1, n2)
match n2
[] -> []
[Pos] -> n1
[Neg] -> n1.neg
(Cons(Pos, t)) -> Cons(Zero, t*n1) + n1
(Cons(Neg, t)) -> Cons(Zero, t*n1) - n1
(Cons(Zero, t)) -> Cons(Zero, t*n1)

fun main()
val a = "+-0++0+".from_string
val b = (-436).from_int
val c = "+-++-".from_string
val d = a * (b - c)
println("a = " ++ a.to_int.show ++ "\nb = " ++ b.to_string ++ "\nc = " ++ c.to_int.show ++ "\na * (b - c) = " ++ d.to_string ++ " = " ++ d.to_int.show )
```
Output:
```a = 523
b = -++-0--
c = 65
a * (b - c) = ----0+--0++0 = -262023
```

## Kotlin

This is based on the Java entry. However, I've added 'BigInteger' support as this is a current requirement of the task description even though it's not actually needed to process the test case:

```// version 1.1.3

import java.math.BigInteger

val bigZero = BigInteger.ZERO
val bigOne = BigInteger.ONE
val bigThree = BigInteger.valueOf(3L)

data class BTernary(private var value: String) : Comparable<BTernary> {

init {
require(value.all { it in "0+-" })
value = value.trimStart('0')
}

constructor(v: Int) : this(BigInteger.valueOf(v.toLong()))

constructor(v: BigInteger) : this("") {
value = toBT(v)
}

private fun toBT(v: BigInteger): String {
if (v < bigZero) return flip(toBT(-v))
if (v == bigZero) return ""
val rem = mod3(v)
return when (rem) {
bigZero -> toBT(v / bigThree) + "0"
bigOne  -> toBT(v / bigThree) + "+"
else    -> toBT((v + bigOne) / bigThree) + "-"
}
}

private fun flip(s: String): String {
val sb = StringBuilder()
for (c in s) {
sb.append(when (c) {
'+'  -> "-"
'-'  -> "+"
else -> "0"
})
}
return sb.toString()
}

private fun mod3(v: BigInteger): BigInteger {
if (v > bigZero) return v % bigThree
return ((v % bigThree) + bigThree) % bigThree
}

fun toBigInteger(): BigInteger {
val len = value.length
var sum = bigZero
var pow = bigOne
for (i in 0 until len) {
val c = value[len - i - 1]
val dig = when (c) {
'+'  -> bigOne
'-'  -> -bigOne
else -> bigZero
}
if (dig != bigZero) sum += dig * pow
pow *= bigThree
}
return sum
}

private fun addDigits(a: Char, b: Char, carry: Char): String {
return when {
sum1.length == 1 -> sum2
sum2.length == 1 -> sum1.take(1) + sum2
else             -> sum1.take(1)
}
}

private fun addDigits(a: Char, b: Char): String =
when {
a == '0' -> b.toString()
b == '0' -> a.toString()
a == '+' -> if (b == '+') "+-" else "0"
else     -> if (b == '+') "0" else "-+"
}

operator fun plus(other: BTernary): BTernary {
var a = this.value
var b = other.value
val longer = if (a.length > b.length) a else b
var shorter = if (a.length > b.length) b else a
while (shorter.length < longer.length) shorter = "0" + shorter
a = longer
b = shorter
var carry = '0'
var sum = ""
for (i in 0 until a.length) {
val place = a.length - i - 1
val digisum = addDigits(a[place], b[place], carry)
carry = if (digisum.length != 1) digisum[0] else '0'
sum = digisum.takeLast(1) + sum
}
sum = carry.toString() + sum
return BTernary(sum)
}

operator fun unaryMinus() = BTernary(flip(this.value))

operator fun minus(other: BTernary) = this + (-other)

operator fun times(other: BTernary): BTernary {
var that = other
val one = BTernary(1)
val zero = BTernary(0)
var mul = zero
var flipFlag = false
if (that < zero) {
that = -that
flipFlag = true
}
var i = one
while (i <= that) {
mul += this
i += one
}
if (flipFlag) mul = -mul
return mul
}

override operator fun compareTo(other: BTernary) =
this.toBigInteger().compareTo(other.toBigInteger())

override fun toString() = value
}

fun main(args: Array<String>) {
val a = BTernary("+-0++0+")
val b = BTernary(-436)
val c = BTernary("+-++-")
println("a = \${a.toBigInteger()}")
println("b = \${b.toBigInteger()}")
println("c = \${c.toBigInteger()}")
val bResult = a * (b - c)
val iResult = bResult.toBigInteger()
println("a * (b - c) = \$bResult = \$iResult")
}
```
Output:
```a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 = -262023
```

## Liberty BASIC

```global tt\$
tt\$="-0+"   '-1 0 1; +2 -> 1 2 3, instr

'Test case:
'With balanced ternaries a from string "+-0++0+", b from native integer -436, c "+-++-":
'* write out a, b and c in decimal notation;
'* calculate a * (b - c), write out the result in both ternary and decimal notations.

a\$="+-0++0+"
a=deci(a\$)
print "a",a, a\$

b=-436
b\$=ternary\$(b)
print "b",b, b\$

c\$="+-++-"
c=deci(c\$)
print "c",c, c\$

'calculate in ternary

res\$=multTernary\$(a\$, subTernary\$(b\$, c\$))
print "a * (b - c)", res\$
print "In decimal:",deci(res\$)

print "Check:"
print "a * (b - c)", a * (b - c)
end

function deci(s\$)
pow = 1
for i = len(s\$) to 1 step -1
c\$ = mid\$(s\$,i,1)
'select case c\$
'    case "+":sign= 1
'    case "-":sign=-1
'    case "0":sign= 0
'end select
sign = instr(tt\$,c\$)-2
deci = deci+pow*sign
pow = pow*3
next
end function

function ternary\$(n)
while abs(n)>3^k/2
k=k+1
wend
k=k-1

pow = 3^k
for i = k to 0 step -1
sign = (n>0) - (n<0)
sign = sign * (abs(n)>pow/2)
ternary\$ = ternary\$+mid\$(tt\$,sign+2,1)
n = n - sign*pow
pow = pow/3
next
if  ternary\$ = "" then  ternary\$ ="0"
end function

function multTernary\$(a\$, b\$)

c\$ = ""
t\$ = ""
shift\$ = ""
for i = len(a\$) to 1 step -1

select case mid\$(a\$,i,1)
case "+": t\$ = b\$
case "0": t\$ = "0"
case "-": t\$ = negate\$(b\$)
end select

shift\$ = shift\$ +"0"
'print d, t\$, c\$
next
multTernary\$ = c\$
end function

function subTernary\$(a\$, b\$)
end function

function negate\$(s\$)
negate\$=""
for i = 1 to len(s\$)
'print mid\$(s\$,i,1), instr(tt\$, mid\$(s\$,i,1)), 4-instr(tt\$, mid\$(s\$,i,1))
negate\$=negate\$+mid\$(tt\$, 4-instr(tt\$, mid\$(s\$,i,1)), 1)
next
end function

'add a\$ + b\$, for now only positive
l = max(len(a\$), len(b\$))
c\$ = "" 'result
carry = 0
for i = l to 1 step -1
a = instr(tt\$,mid\$(a\$,i,1))-2
b = instr(tt\$,mid\$(b\$,i,1))-2     '-1 0 1
c = a+b+carry

select case
case abs(c)<2
carry = 0
case c>0
carry =1: c=c-3
case c<0
carry =-1: c=c+3
end select

'print a, b, c
c\$ = mid\$(tt\$,c+2,1)+c\$
next
if carry<>0 then c\$ = mid\$(tt\$,carry+2,1) +c\$
'print c\$
i=0
while mid\$(c\$,i+1,1)="0"
i=i+1
wend
c\$=mid\$(c\$,i+1)
if c\$="" then c\$="0"
end function

wend
end function```
Output:
```a             523           +-0++0+
b             -436          -++-0--
c             65            +-++-
a * (b - c)   ----0+--0++0
In decimal:   -262023
Check:
a * (b - c)   -262023
```

## Lua

Translation of: C
```function to_bt(n)
local d = { '0', '+', '-' }
local v = { 0, 1, -1 }

local b = ""

while n ~= 0 do
local r = n % 3
if r < 0 then
r = r + 3
end

b = b .. d[r + 1]

n = n - v[r + 1]
n = math.floor(n / 3)
end

return b:reverse()
end

function from_bt(s)
local n = 0

for i=1,s:len() do
local c = s:sub(i,i)
n = n * 3
if c == '+' then
n = n + 1
elseif c == '-' then
n = n - 1
end
end

return n
end

function last_char(s)
return s:sub(-1,-1)
end

local out = "oops"
if b1 ~= "" and b2 ~= "" then
local d = ""

local L1 = last_char(b1)
local c1 = b1:sub(1,-2)
local L2 = last_char(b2)
local c2 = b2:sub(1,-2)
if L2 < L1 then
L2, L1 = L1, L2
end

if L1 == '-' then
if L2 == '0' then
d = "-"
end
if L2 == '-' then
d = "+-"
end
elseif L1 == '+' then
if L2 == '0' then
d = "+"
elseif L2 == '-' then
d = "0"
elseif L2 == '+' then
d = "-+"
end
elseif L1 == '0' then
if L2 == '0' then
d = "0"
end
end

out = ob2 .. d:sub(1,1)
elseif b1 ~= "" then
out = b1
elseif b2 ~= "" then
out = b2
else
out = ""
end

return out
end

function unary_minus(b)
local out = ""

for i=1, b:len() do
local c = b:sub(i,i)
if c == '-' then
out = out .. '+'
elseif c == '+' then
out = out .. '-'
else
out = out .. c
end
end

return out
end

function subtract(b1,b2)
end

function mult(b1,b2)
local r = "0"
local c1 = b1
local c2 = b2:reverse()

for i=1,c2:len() do
local c = c2:sub(i,i)
if c == '+' then
elseif c == '-' then
r = subtract(r, c1)
end
c1 = c1 .. '0'
end

while r:sub(1,1) == '0' do
r = r:sub(2)
end

return r
end

function main()
local a = "+-0++0+"
local b = to_bt(-436)
local c = "+-++-"
local d = mult(a, subtract(b, c))

print(string.format("      a: %14s %10d", a, from_bt(a)))
print(string.format("      b: %14s %10d", b, from_bt(b)))
print(string.format("      c: %14s %10d", c, from_bt(c)))
print(string.format("a*(b-c): %14s %10d", d, from_bt(d)))
end

main()
```
Output:
```      a:        +-0++0+        523
b:        -++-0--       -436
c:          +-++-         65
a*(b-c):   ----0+--0++0    -262023```

## Mathematica / Wolfram Language

```frombt = FromDigits[StringCases[#, {"+" -> 1, "-" -> -1, "0" -> 0}],
3] &;
tobt = If[Quotient[#, 3, -1] == 0,
"", #0@Quotient[#, 3, -1]] <> (Mod[#,
3, -1] /. {1 -> "+", -1 -> "-", 0 -> "0"}) &;
btnegate = StringReplace[#, {"+" -> "-", "-" -> "+"}] &;
StringJoin[
Fold[Sort@{#1[[1]],
Sequence @@ #2} /. {{x_, x_, x_} :> {x,
"0" <> #1[[2]]}, {"-", "+", x_} | {x_, "-", "+"} | {x_,
"0", "0"} :> {"0", x <> #1[[2]]}, {"+", "+", "0"} -> {"+",
"-" <> #1[[2]]}, {"-", "-", "0"} -> {"-",
"+" <> #1[[2]]}} &, {"0", ""},
Reverse@Transpose@PadLeft[Characters /@ {#1, #2}] /. {0 ->
"0"}]], StartOfString ~~ "0" .. ~~ x__ :> x] &;
btmultiply =
btadd[Switch[StringTake[#2, -1], "0", "0", "+", #1, "-",
btnegate@#1],
If[StringLength@#2 == 1,
"0", #0[#1, StringDrop[#2, -1]] <> "0"]] &;
```

Examples:

```frombt[a = "+-0++0+"]
b = tobt@-436
frombt[c = "+-++-"]
btmultiply[a, btsubtract[b, c]]
```

Outputs:

```523

"-++-0--"

65

"----0+--0++0"```

## МК-61/52

Translation of: Glagol
```ЗН	П2	Вx	|x|	П0	0	П3	П4	1	П5
ИП0	/-/	x<0	80
ИП0	^	^	3	/	[x]	П0	3	*	-	П1
ИП3	x#0	54
ИП1	x=0	38	ИП2	ПП	88	0	П3	БП	10
ИП1	1	-	x=0	49	ИП2	/-/	ПП	88	БП	10
0	ПП	88	БП	10
ИП1	x=0	62	0	ПП	88	БП	10
ИП1	1	-	x=0	72	ИП2	ПП	88	БП	10
ИП2	/-/	ПП	88	1	П3	БП	10
ИП3	x#0	86	ИП2	ПП	88	ИП4	С/П
8	+	ИП5	*	ИП4	+	П4	ИП5	1	0	*	П5	В/О```

Note: the "-", "0", "+" denotes by digits, respectively, the "7", "8", "9".

## Nim

```import std/[strformat, tables]

type

# Trit definition.
Trit = range[-1'i8..1'i8]

# Balanced ternary number as a sequence of trits stored in little endian way.
BTernary = seq[Trit]

const

# Textual representation of trits.
Trits: array[Trit, char] = ['-', '0', '+']

# Symbolic names used for trits.
TN = Trit(-1)
TZ = Trit(0)
TP = Trit(1)

# Table to convert the result of classic addition to balanced ternary numbers.
AddTable = {-2: @[TP, TN], -1: @[TN], 0: @[TZ], 1: @[TP], 2: @[TN, TP]}.toTable()

# Mapping from modulo to trits (used for conversion from int to balanced ternary).
ModTrits: array[-2..2, Trit] = [TP, TN, TZ, TP, TN]

#---------------------------------------------------------------------------------------------------

func normalize(bt: var BTernary) =
## Remove the extra zero trits at head of a BTernary number.
var i = bt.high
while i >= 0 and bt[i] == 0:
dec i
bt.setlen(if i < 0: 1 else: i + 1)

#---------------------------------------------------------------------------------------------------

func `+`*(a, b: BTernary): BTernary =

# Prepare operands.
var (a, b) = (a, b)
if a.len < b.len:
a.setLen(b.len)
else:
b.setLen(a.len)

# Perform addition trit per trit.
var carry = TZ
for i in 0..<a.len:
var s = AddTable[a[i] + b[i]]
if carry != TZ:
s = s + @[carry]
carry = if s.len > 1: s[1] else: TZ

# Append the carry to the result if it is not null.
if carry != TZ:

#---------------------------------------------------------------------------------------------------

func `+=`*(a: var BTernary; b: BTernary) {.inline.} =
## Increment a BTernary number.
a = a + b

#---------------------------------------------------------------------------------------------------

func `-`(a: BTernary): BTernary =
## Negate a BTernary number.
result.setLen(a.len)
for i, t in a:
result[i] = -t

#---------------------------------------------------------------------------------------------------

func `-`*(a, b: BTernary): BTernary {.inline.} =
## Subtract a BTernary number to another.
a + -b

#---------------------------------------------------------------------------------------------------

func `-=`*(a: var BTernary; b: BTernary) {.inline.} =
## Decrement a BTernary number.
a = a + -b

#---------------------------------------------------------------------------------------------------

func `*`*(a, b: BTernary): BTernary =
## Multiply two BTernary numbers.

var start: BTernary
let na = -a

# Loop on each trit of "b" and add directly a whole row.
for t in b:
case t
of TP: result += start & a
of TN: result += start & na
result.normalize()

#---------------------------------------------------------------------------------------------------

func toTrit*(c: char): Trit =
## Convert a char to a trit.
case c
of '-': -1
of '0': 0
of '+': 1
else:
raise newException(ValueError, fmt"Invalid trit: '{c}'")

#---------------------------------------------------------------------------------------------------

func `\$`*(bt: BTernary): string =
## Return the string representation of a BTernary number.
result.setLen(bt.len)
for i, t in bt:
result[^(i + 1)] = Trits[t]

#---------------------------------------------------------------------------------------------------

func toBTernary*(s: string): BTernary =
## Build a BTernary number from its string representation.
result.setLen(s.len)
for i, c in s:
result[^(i + 1)] = c.toTrit()

#---------------------------------------------------------------------------------------------------

func toInt*(bt: BTernary): int =
## Convert a BTernary number to an integer.
## An overflow error is raised if the result cannot fit in an integer.
var m = 1
for t in bt:
result += m * t
m *= 3

#---------------------------------------------------------------------------------------------------

func toBTernary(val: int): BTernary =
## Convert an integer to a BTernary number.
var val = val
while true:
let trit = ModTrits[val mod 3]
val = (val - trit) div 3
if val == 0:
break

#———————————————————————————————————————————————————————————————————————————————————————————————————

when isMainModule:

let a = "+-0++0+".toBTernary
let b = -436.toBTernary
let c = "+-++-".toBTernary

echo "Balanced ternary numbers:"
echo fmt"a = {a}"
echo fmt"b = {b}"
echo fmt"c = {c}"
echo ""

echo "Their decimal representation:"
echo fmt"a = {a.toInt: 4d}"
echo fmt"b = {b.toInt: 4d}"
echo fmt"c = {c.toInt: 4d}"
echo ""

let x = a * (b - c)
echo "a × (b - c):"
echo fmt"– in ternary: {x}"
echo fmt"– in decimal: {x.toInt}"
```
Output:
```Balanced ternary numbers:
a = +-0++0+
b = -++-0--
c = +-++-

Their decimal representation:
a =  523
b = -436
c =   65

a × (b - c):
– in ternary: ----0+--0++0
– in decimal: -262023```

## OCaml

```type btdigit = Pos | Zero | Neg
type btern = btdigit list

let to_string n =
String.concat ""
(List.rev_map (function Pos -> "+" | Zero -> "0" | Neg -> "-") n)

let from_string s =
let sl = ref [] in
let digit = function '+' -> Pos | '-' -> Neg | '0' -> Zero
| _ -> failwith "invalid digit" in
String.iter (fun c -> sl := (digit c) :: !sl) s; !sl

let rec to_int = function
| [Zero] | [] -> 0
| Pos :: t -> 1 + 3 * to_int t
| Neg :: t -> -1 + 3 * to_int t
| Zero :: t -> 3 * to_int t

let rec from_int n =
if n = 0 then [] else
match n mod 3 with
| 0 -> Zero :: from_int (n/3)
| 1 | -2 -> Pos :: from_int ((n-1)/3)
| 2 | -1 -> Neg :: from_int ((n+1)/3)

let rec (+~) n1 n2 = match (n1,n2) with
| ([], a) | (a,[]) -> a
| (Pos::t1, Neg::t2) | (Neg::t1, Pos::t2) | (Zero::t1, Zero::t2) ->
let sum = t1 +~ t2 in if sum = [] then [] else Zero :: sum
| (Pos::t1, Pos::t2) -> Neg :: t1 +~ t2 +~ [Pos]
| (Neg::t1, Neg::t2) -> Pos :: t1 +~ t2 +~ [Neg]
| (Zero::t1, h::t2) | (h::t1, Zero::t2) -> h :: t1 +~ t2

let neg = List.map (function Pos -> Neg | Neg -> Pos | Zero -> Zero)
let (-~) a b = a +~ (neg b)

let rec ( *~) n1 = function
| [] -> []
| [Pos] -> n1
| [Neg] -> neg n1
| Pos::t -> (Zero :: t *~ n1) +~ n1
| Neg::t -> (Zero :: t *~ n1) -~ n1
| Zero::t -> Zero :: t *~ n1

let a = from_string "+-0++0+"
let b = from_int (-436)
let c = from_string "+-++-"
let d = a *~ (b -~ c)
let _ =
Printf.printf "a = %d\nb = %d\nc = %d\na * (b - c) = %s = %d\n"
(to_int a) (to_int b) (to_int c) (to_string d) (to_int d);
```

Output:

```a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 = -262023```

## Perl

```use strict;
use warnings;

my @d = qw( 0 + - );
my @v = qw( 0 1 -1 );

sub to_bt {
my \$n = shift;
my \$b = '';
while( \$n ) {
my \$r = \$n%3;
\$b .= \$d[\$r];
\$n -= \$v[\$r];
\$n /= 3;
}
return scalar reverse \$b;
}

sub from_bt {
my \$n = 0;
for( split //, shift ) { # Horner
\$n *= 3;
\$n += "\${_}1" if \$_;
}
return \$n;
}

'-0' => [ '-', '' ],
'+0' => [ '+', '' ],
'+-' => [ '0', '' ],
'00' => [ '0', '' ],
'--' => [ '+', '-' ],
'++' => [ '-', '+' ],
);

my (\$b1, \$b2) = @_;
return (\$b1 or \$b2 ) unless (\$b1 and \$b2);
my \$d = \$addtable{ join '', sort substr( \$b1, -1, 1, '' ), substr( \$b2, -1, 1, '' ) };
}

sub unary_minus {
my \$b = shift;
\$b =~ tr/-+/+-/;
return \$b;
}

sub subtract {
my (\$b1, \$b2) = @_;
return add( \$b1, unary_minus \$b2 );
}

sub mult {
my (\$b1, \$b2) = @_;
my \$r = '0';
for( reverse split //, \$b2 ){
\$r = add \$r, \$b1      if \$_ eq '+';
\$r = subtract \$r, \$b1 if \$_ eq '-';
\$b1 .= '0';
}
\$r =~ s/^0+//;
return \$r;
}

my \$a = "+-0++0+";
my \$b = to_bt( -436 );
my \$c = "+-++-";
my \$d = mult( \$a, subtract( \$b, \$c ) );
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 );
```
Output:
```      a:        +-0++0+        523
b:        -++-0--       -436
c:          +-++-         65
a*(b-c):   ----0+--0++0    -262023
```

## Phix

Using strings to represent balanced ternary. Note that as implemented dec2bt and bt2dec are limited to Phix integers (~+/-1,000,000,000), but it would probably be pretty trivial (albeit quite a bit slower) to replace them with (say) ba2bt and bt2ba which use/yield bigatoms.

```with javascript_semantics
function bt2dec(string bt)
integer res = 0
for i=1 to length(bt) do
res = 3*res+(bt[i]='+')-(bt[i]='-')
end for
return res
end function

function negate(string bt)
for i=1 to length(bt) do
if bt[i]!='0' then
bt[i] = '+'+'-'-bt[i]
end if
end for
return bt
end function

function dec2bt(integer n)
string res = "0"
if n!=0 then
integer neg = n<0
if neg then n = -n end if
res = ""
while n!=0 do
integer r = mod(n,3)
res = "0+-"[r+1]&res
n = floor((n+(r=2))/3)
end while
if neg then res = negate(res) end if
end if
return res
end function

-- res,carry for a+b+carry lookup tables (not the fastest way to do it, I'm sure):
{"-0-","+-"},{"-00","-0"},{"-0+","00"},
{"-+-","-0"},{"-+0","00"},{"-++","+0"},
{"0--","+-"},{"0-0","-0"},{"0-+","00"},
{"00-","-0"},{"000","00"},{"00+","+0"},
{"0+-","00"},{"0+0","+0"},{"0++","-+"},
{"+--","-0"},{"+-0","00"},{"+-+","+0"},
{"+0-","00"},{"+00","+0"},{"+0+","-+"},
{"++-","+0"},{"++0","-+"},{"+++","0+"}})

carry = '0', ch
else
end if
end if
for i=length(a) to 1 by -1 do
a[i] = cc[1]
carry = cc[2]
end for
if carry!='0' then
a = carry&a
else
while length(a)>1 and a[1]='0' do
a = a[2..\$]
end while
end if
return a
end function

function bt_mul(string a, string b)
string pos = a, neg = negate(a), res = "0"
for i=length(b) to 1 by -1 do
integer ch = b[i]
if ch='+' then
elsif ch='-' then
end if
pos = pos&'0'
neg = neg&'0'
end for
return res
end function

string a = "+-0++0+", b = dec2bt(-436), c = "+-++-",
printf(1,"%7s:  %12s  %9d\n",{"a",a,bt2dec(a)})
printf(1,"%7s:  %12s  %9d\n",{"b",b,bt2dec(b)})
printf(1,"%7s:  %12s  %9d\n",{"c",c,bt2dec(c)})
printf(1,"%7s:  %12s  %9d\n",{"a*(b-c)",res,bt2dec(res)})
```
Output:
```       a:        +-0++0+        523
b:        -++-0--       -436
c:          +-++-         65
a*(b-c):   ----0+--0++0    -262023
```

Proof of arbitrary large value support is provided by calculating 1000! and 999! and using a naive subtraction loop to effect division. The limit for factorials that can be held in native integers is a mere 12, and for atoms 170, mind you, inaccurate above 22. The timings show it manages a 5000+digit multiplication and subtraction in about 0.2s, which I say is "reasonable", given that I didn't try very hard, as evidenced by that daft addition lookup table!

```with javascript_semantics
atom t0 = time()
string f999 = dec2bt(1)
for i=2 to 999 do
f999 = bt_mul(f999,dec2bt(i))
end for
string f1000 = bt_mul(f999,dec2bt(1000))

printf(1,"In balanced ternary, f999 has %d digits and f1000 has %d digits\n",{length(f999),length(f1000)})

integer count = 0
f999 = negate(f999)
while f1000!="0" do
count += 1
end while
printf(1,"It took %d subtractions to reach 0. (%3.2fs)\n",{count,time()-t0})
```
Output:
```In balanced ternary, f999 has 5376 digits and f1000 has 5383 digits
It took 1000 subtractions to reach 0. (9.30s)
```

## PicoLisp

```(seed (in "/dev/urandom" (rd 8)))

(setq *G '((0 -1) (1 -1) (-1 0) (0 0) (1 0) (-1 1) (0 1)))

# For humans
(de negh (L)
(mapcar
'((I)
(case I
(- '+)
(+ '-)
(T 0) ) )
L ) )

(de trih (X)
(if (num? X)
(let (S (lt0 X)  X (abs X)  R NIL)
(if (=0 X)
(push 'R 0)
(until (=0 X)
(push 'R
(case (% X 3)
(0 0)
(1 '+)
(2 (inc 'X) '-) ) )
(setq X (/ X 3)) ) )
(if S (pack (negh R)) (pack R)) )
(let M 1
(sum
'((C)
(prog1
(unless (= C "0") ((intern C) M))
(setq M (* 3 M)) ) )
(flip (chop X)) ) ) ) )

# For robots
(de neg (L)
(mapcar
'((I)
(case I (-1 1) (1 -1) (T 0)) )
L ) )

(de tri (X)
(if (num? X)
(let (S (lt0 X)  X (abs X)  R NIL)
(if (=0 X)
(push 'R 0)
(until (=0 X)
(push 'R
(case (% X 3)
(0 0)
(1 1)
(2 (inc 'X) (- 1)) ) )
(setq X (/ X 3)) ) )
(flip (if S (neg R) R)) )
(let M 1
(sum
'((C)
(prog1 (* C M) (setq M (* 3 M))) )
X ) ) ) )

(let
(L (max (length D1) (length D2))
D1 (need (- L) D1 0)
D2 (need (- L) D2 0)
C 0 )
(mapcon
'((L1 L2)
(let R
(get
*G
(+ 4 (+ (car L1) (car L2) C)) )
(ifn (cdr L1)
R
(cons (car R)) ) ) )
D1
D2 ) ) )

(de mul (D1 D2)
(ifn (and D1 D2)
0
(case (car D1)
(0 0)
(1 D2)
(-1 (neg D2)) )
(cons 0 (mul (cdr D1) D2) ) ) ) )

(de sub (D1 D2)

# Random testing
(let (X 0  Y 0  C 2048)
(do C
(setq
X (rand (- C) C)
Y (rand (- C) C) )
(test X (trih (trih X)))
(test X (tri (tri X)))
(test
(+ X Y)
(tri (add (tri X) (tri Y))) )
(test
(- X Y)
(tri (sub (tri X) (tri Y))) )
(test
(* X Y)
(tri (mul (tri X) (tri Y))) ) ) )

(println 'A (trih 523) (trih "+-0++0+"))
(println 'B (trih -436) (trih "-++-0--"))
(println 'C (trih 65) (trih "+-++-"))
(let R
(tri
(mul
(tri (trih "+-0++0+"))
(sub (tri -436) (tri (trih "+-++-"))) ) )
(println 'R (trih R) R) )

(bye)```

## Prolog

Works with SWI-Prolog and library clpfd written by Markus Triska.
Three modules, one for the conversion, one for the addition and one for the multiplication.

The conversion.
Library clpfd is used so that bt_convert works in both ways Decimal => Ternary and Ternary ==> Decimal.

```:- module('bt_convert.pl', [bt_convert/2,
op(950, xfx, btconv),
btconv/2]).

:- use_module(library(clpfd)).

:- op(950, xfx, btconv).

X btconv Y :-
bt_convert(X, Y).

% bt_convert(?X, ?L)
bt_convert(X, L) :-
(   (nonvar(L), \+is_list(L)) ->string_to_list(L, L1);  L1 = L),
convert(X, L1),
(   var(L) -> string_to_list(L, L1); true).

% map numbers toward digits +, - 0
plus_moins( 1, 43).
plus_moins(-1, 45).
plus_moins( 0, 48).

convert(X, [48| L]) :-
var(X),
(   L \= [] -> convert(X, L); X = 0, !).

convert(0, L) :-
var(L), !, string_to_list(L, [48]).

convert(X, L) :-
(   (nonvar(X), X > 0)
;   (var(X), X #> 0,
L = [43|_],
maplist(plus_moins, L1, L))),
!,
convert(X, 0, [], L1),
(   nonvar(X) -> maplist(plus_moins, L1, LL),  string_to_list(L, LL)
;   true).

convert(X, L) :-
(  nonvar(X) -> Y is -X
;  X #< 0,
maplist(plus_moins, L2, L),
maplist(mult(-1), L2, L1)),
convert(Y, 0, [], L1),
(   nonvar(X) ->
maplist(mult(-1), L1, L2),
maplist(plus_moins, L2, LL),
string_to_list(L, LL)
;   X #= -Y).

mult(X, Y, Z) :-
Z #= X * Y.

convert(0, 0, L, L) :-  !.

convert(0, 1, L, [1 | L]) :- !.

convert(N, C, LC, LF) :-
R #= N mod 3 + C,
R #> 1 #<==> C1,
N1 #= N / 3,
R1 #= R - 3 * C1, % C1 #= 1,
convert(N1, C1, [R1 | LC], LF).
```

The same predicate is used for addition and substraction.

```:- module('bt_add.pl', [bt_add/3,
op(900, xfx, btplus),
op(900, xfx, btmoins),
btplus/2,
btmoins/2,
strip_nombre/3
]).

:- op(900, xfx, btplus).
:- op(900, xfx, btmoins).

% define operator btplus
A is X btplus Y :-

% define operator btmoins
% no need to define a predicate for the substraction
A is X btmoins Y :-
X is Y btplus A.

% R is X + Y
% X, Y, R are strings
% At least 2 args must be instantiated
(   nonvar(X) -> string_to_list(X, X1);  true),
(   nonvar(Y) -> string_to_list(Y, Y1);  true),
(   nonvar(R) -> string_to_list(R, R1);  true),
(   var(X) -> string_to_list(X, X1); true),
(   var(Y) -> string_to_list(Y, Y1); true),
(   var(R) -> string_to_list(R, R1); true).

% R is X + Y
% X, Y, R are lists
% initialisation :  X and Y must have the same length
% we add zeros at the beginning of the shortest list
(   nonvar(X) -> length(X, LX);  length(R, LR)),
(   nonvar(Y) ->  length(Y, LY);  length(R, LR)),
(   var(X) -> LX is max(LY, LR) , length(X1, LX), Y1 = Y ; X1 = X),
(   var(Y) -> LY is max(LX, LR) , length(Y1, LY), X1 = X ; Y1 = Y),

Delta is abs(LX - LY),
(   LX < LY -> normalise(Delta, X1, X2), Y1 = Y2
;   LY < LX -> normalise(Delta, Y1, Y2), X1 = X2
;   X1 = X2, Y1 = Y2),

% if R is instancied, it must have, at least, the same length than X or Y
Max is max(LX, LY),
(   (nonvar(R), length(R, LR), LR < Max) -> Delta1 is Max - LR, normalise(Delta1, R, R2)
;   nonvar(R) -> R = R2
;   true),

(   C = 48 -> strip_nombre(R2, R, []),
(	  var(X) -> strip_nombre(X2, X, []) ; true),
(	  var(Y) -> strip_nombre(Y2, Y, []) ; true)
;   var(R) -> strip_nombre([C|R2], R, [])
;   ( select(C, [45,43], [Ca]),
( var(X) -> strip_nombre([Ca | X2], X, [])
;	strip_nombre([Ca | Y2], Y, [])))).

% here we actually compute the sum

bt_add([H1|T1], [H2|T2], C3, [R2 | L]) :-
ternary_sum(H1, H2, R1, C1),
ternary_sum(R1, C, R2, C2),
ternary_sum(C1, C2, C3, _).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ternary_sum
% @arg1 : V1
% @arg2 : V2
% @arg3 : R is V1 + V2
% @arg4 : Carry
ternary_sum(43, 43, 45, 43).

ternary_sum(43, 45, 48, 48).

ternary_sum(45, 43, 48, 48).

ternary_sum(45, 45, 43, 45).

ternary_sum(X, 48, X, 48).

ternary_sum(48, X, X, 48).

% if L has a length smaller than N, complete L with 0 (code 48)
normalise(0, L, L) :- !.
normalise(N, L1, L) :-
N1 is N - 1,
normalise(N1, [48 | L1], L).

% contrary of normalise
% special case of number 0 !
strip_nombre([48]) --> {!}, "0".

% enlève les zéros inutiles
strip_nombre([48 | L]) -->
strip_nombre(L).

strip_nombre(L) -->
L.
```

The multiplication.
We give a predicate euclide(?A, +B, ?Q, ?R) which computes both the multiplication and the division, but it is very inefficient.
The predicates multiplication(+B, +Q, -A) and division(+A, +B, -Q, -R) are much more efficient.

```:- module('bt_mult.pl', [op(850, xfx, btmult),
btmult/2,
multiplication/3
]).

:- op(850, xfx, btmult).
A is B btmult C :-
multiplication(B, C, A).

neg(A, B) :-
maplist(opp, A, B).

opp(48, 48).
opp(45, 43).
opp(43, 45).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% the multiplication (efficient)
% multiplication(+BIn, +QIn, -AOut)
% Aout is BIn * QIn
% BIn, QIn, AOut are strings
multiplication(BIn, QIn, AOut) :-
string_to_list(BIn, B),
string_to_list(QIn, Q),

% We work with positive numbers
(   B = [45 | _] -> Pos0 = false, neg(B,BP) ; BP = B, Pos0 = true),
(   Q = [45 | _] -> neg(Q, QP), select(Pos0, [true, false], [Pos1]); QP = Q, Pos1 = Pos0),

multiplication_(BP, QP, [48], A),
(   Pos1 = false -> neg(A, A1); A1 = A),
string_to_list(AOut, A1).

multiplication_(_B, [], A, A).

multiplication_(B, [H | T], A, AF) :-
multiplication_1(B, H, B1),
append(A, [48], A1),
multiplication_(B, T, A2, AF).

% by 1 (digit '+' code 43)
multiplication_1(B, 43, B).

% by 0 (digit '0' code 48)
multiplication_1(_, 48, [48]).

% by -1 (digit '-' code 45)
multiplication_1(B, 45, B1) :- neg(B, B1).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% the division (efficient)
% division(+AIn, +BIn, -QOut, -ROut)
%
division(AIn, BIn, QOut, ROut) :-
string_to_list(AIn, A),
string_to_list(BIn, B),
length(B, LB),
length(A, LA),
Len is LA - LB,
(   Len < 0 -> Q = [48], R = A
;   neg(B, NegB), division_(A, B, NegB, LB, Len, [], Q, R)),
string_to_list(QOut, Q),
string_to_list(ROut, R).

division_(A, B, NegB, LenB, LenA, QC, QF, R) :-
% if the remainder R is negative (last number A), we must decrease the quotient Q, annd add B to R
(   LenA = -1 -> (A = [45 | _]  -> positive(A, B, QC, QF, R) ;	QF = QC, A = R)
;   extract(LenA, _, A, AR, AF),
length(AR, LR),

(	LR >= LenB -> ( AR = [43 | _] ->
bt_add1(AR, NegB, S), Q0 = [43],
% special case : R has the same length than B
% and his first digit is + (1)
% we must do another one substraction
(   (length(S, LenB), S = [43|_]) ->
Q00 = [45]
;   S1 = S, QC1 = QC, Q00 = Q0)

; bt_add1(AR, B, S1), Q00 = [45], QC1 = QC),
append(QC1, Q00, Q1),
append(S1, AF, A1),
strip_nombre(A1, A2, []),
LenA1 is LenA - 1,
division_(A2, B, NegB, LenB, LenA1, Q1, QF, R)

;   append(QC, [48], Q1), LenA1 is LenA - 1,
division_(A, B, NegB, LenB, LenA1, Q1, QF, R))).

% extract(+Len, ?N1, +L, -Head, -Tail)
% remove last N digits from the list L
% put them in Tail.
extract(Len, Len, [], [], []).

extract(Len, N1, [H|T], AR1, AF1) :-
extract(Len, N, T, AR, AF),
N1 is N-1,
(   N > 0 -> AR = AR1, AF1 = [H | AF]; AR1 = [H | AR], AF1 = AF).

positive(R, _, Q, Q, R) :- R = [43 | _].

positive(S, B, Q, QF, R ) :-
positive(S1, B, Q1, QF, R).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% "euclidian" division (inefficient)
% euclide(?A, +BIn, ?Q, ?R)
% A = B * Q + R
euclide(A, B, Q, R) :-
mult(A, B, Q, R).

mult(AIn, BIn, QIn, RIn) :-
(   nonvar(AIn) -> string_to_list(AIn, A); A = AIn),
(   nonvar(BIn) -> string_to_list(BIn, B); B = BIn),
(   nonvar(QIn) -> string_to_list(QIn, Q); Q = QIn),
(   nonvar(RIn) -> string_to_list(RIn, R); R = RIn),

% we use positive numbers
(   B = [45 | _] -> Pos0 = false, neg(B,BP) ; BP = B, Pos0 = true),
(   (nonvar(Q), Q = [45 | _]) -> neg(Q, QP), select(Pos0, [true, false], [Pos1])
;   nonvar(Q) -> Q = QP , Pos1 = Pos0
;   Pos1 = Pos0),
(   (nonvar(A), A = [45 | _]) -> neg(A, AP)
;   nonvar(A) -> AP = A
;   true),

% is R instancied ?
( nonvar(R) -> R1 = R; true),
% multiplication ? we add B to A and substract 1 (digit '-') to Q
(   nonvar(Q) -> BC = BP, Ajout = [45],
(	nonvar(R) ->  bt_add1(BC, R, AP) ; AP = BC)
% division ? we substract B to A and add 1 (digit '+') to Q
;    neg(BP, BC), Ajout = [43], QP = [48]),

% do the real job
mult_(BC, QP, AP, R1, Resultat, Ajout),

(   var(QIn) -> (Pos1 = false -> neg(Resultat, QT); Resultat = QT), string_to_list(QIn, QT)
;   true),
(   var(AIn) -> (Pos1 = false -> neg(Resultat, AT); Resultat = AT), string_to_list(AIn, AT)
;   true),
(   var(RIn) -> string_to_list(RIn, R1); true).

% @arg1 : divisor
% @arg2 : quotient
% @arg3 : dividend
% @arg4 : remainder
% @arg5 : Result :  receive either the dividend A
%                           either the quotient Q
mult_(B, Q, A, R, Resultat, Ajout) :-
(  Q1 = [48] -> Resultat = A % a multiplication
;  ( A1 = [45 | _], Ajout = [43]) -> Resultat = Q, R = A  % a division
;  mult_(B, Q1, A1, R, Resultat, Ajout)) .
```

Example of output :

``` ?- A btconv "+-0++0+".
A = 523.

?- -436 btconv B.
B = "-++-0--".

?- C btconv "+-++-".
C = 65.

?- X is "-++-0--" btmoins "+-++-", Y is "+-0++0+" btmult X, Z btconv Y.
X = "-+0-++0",
Y = "----0+--0++0",
Z = -262023 .
```

## Python

Translation of: Common Lisp
```class BalancedTernary:
# Represented as a list of 0, 1 or -1s, with least significant digit first.

str2dig = {'+': 1, '-': -1, '0': 0} # immutable
dig2str = {1: '+', -1: '-', 0: '0'} # immutable
table = ((0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1)) # immutable

def __init__(self, inp):
if isinstance(inp, str):
self.digits = [BalancedTernary.str2dig[c] for c in reversed(inp)]
elif isinstance(inp, int):
self.digits = self._int2ternary(inp)
elif isinstance(inp, BalancedTernary):
self.digits = list(inp.digits)
elif isinstance(inp, list):
if all(d in (0, 1, -1) for d in inp):
self.digits = list(inp)
else:
raise ValueError("BalancedTernary: Wrong input digits.")
else:
raise TypeError("BalancedTernary: Wrong constructor input.")

@staticmethod
def _int2ternary(n):
if n == 0: return []
if (n % 3) == 0: return [0] + BalancedTernary._int2ternary(n // 3)
if (n % 3) == 1: return [1] + BalancedTernary._int2ternary(n // 3)
if (n % 3) == 2: return [-1] + BalancedTernary._int2ternary((n + 1) // 3)

def to_int(self):
return reduce(lambda y,x: x + 3 * y, reversed(self.digits), 0)

def __repr__(self):
if not self.digits: return "0"
return "".join(BalancedTernary.dig2str[d] for d in reversed(self.digits))

@staticmethod
def _neg(digs):
return [-d for d in digs]

def __neg__(self):
return BalancedTernary(BalancedTernary._neg(self.digits))

@staticmethod
if not (a and b):
if c == 0:
return a or b
else:
else:
(d, c) = BalancedTernary.table[3 + (a[0] if a else 0) + (b[0] if b else 0) + c]
if res or d != 0:
return [d] + res
else:
return res

def __sub__(self, b):
return self + (-b)

@staticmethod
def _mul(a, b):
if not (a and b):
return []
else:
if   a[0] == -1: x = BalancedTernary._neg(b)
elif a[0] ==  0: x = []
elif a[0] ==  1: x = b
else: assert False
y = [0] + BalancedTernary._mul(a[1:], b)

def __mul__(self, b):
return BalancedTernary(BalancedTernary._mul(self.digits, b.digits))

def main():
a = BalancedTernary("+-0++0+")
print "a:", a.to_int(), a

b = BalancedTernary(-436)
print "b:", b.to_int(), b

c = BalancedTernary("+-++-")
print "c:", c.to_int(), c

r = a * (b - c)
print "a * (b - c):", r.to_int(), r

main()
```
Output:
```a: 523 +-0++0+
b: -436 -++-0--
c: 65 +-++-
a * (b - c): -262023 ----0+--0++0```

## Racket

```#lang racket

;; Represent a balanced-ternary number as a list of 0's, 1's and -1's.
;;
;; e.g. 11 = 3^2 + 3^1 - 3^0 ~ "++-" ~ '(-1 1 1)
;;       6 = 3^2 - 3^1       ~ "+-0" ~ '(0 -1 1)
;;
;; Note: the list-rep starts with the least signifcant tert, while
;;       the string-rep starts with the most significsnt tert.

(define (bt->integer t)
(if (null? t)
0
(+ (first t) (* 3 (bt->integer (rest t))))))

(define (integer->bt n)
(letrec ([recur (λ (b r) (cons b (convert (floor (/ r 3)))))]
[convert (λ (n) (if (zero? n) null
(case (modulo n 3)
[(0) (recur 0 n)]
[(1) (recur 1 n)]
(convert n)))

(define (bt->string t)
(if (or (null? a) (not (= (first a) 0))) a (strip-leading-zeroes (rest a))))
(string-join (map (λ (u)
(case u
[(1) "+"]
[(-1) "-"]
[(0) "0"]))

(define (string->bt s)
(reverse
(map (λ (c)
(case c
[(#\+) 1]
[(#\-) -1]
[(#\0) 0]))
(string->list s))))

(define (bt-negate t)
(map (λ (u) (- u)) t))

(define (bt-add a b [c 0])
(cond [(and (null? a) (null? b)) (if (zero? c) null (list c))]
[(null? b) (if (zero? c) a (bt-add a (list c)))]
[(null? a) (bt-add b a c)]
[else (let* ([t (+ (first a) (first b) c)]
[carry (if (> (abs t) 1) (sgn t) 0)]
[v (case (abs t)
[(3) 0]
[(2) (- (sgn t))]
[else t])])
(cons v (bt-add (rest a) (rest b) carry)))]))

(define (bt-multiply a b)
(cond [(null? a) null]
[(null? b) null]
[(-1) (bt-negate b)]
[(0) null]
[(1) b])
(cons 0 (bt-multiply (rest a) b)))]))

; test case
(let* ([a (string->bt "+-0++0+")]
[b (integer->bt -436)]
[c (string->bt "+-++-")]
[d (bt-multiply a (bt-add b (bt-negate c)))])
(for ([bt (list a b c d)]
[description (list 'a 'b 'c "a×(b−c)")])
(printf "~a = ~a or ~a\n" description (bt->integer bt) (bt->string bt))))
```
Output:
```a = 523 or +-0++0+
b = -436 or -++-0--
c = 65 or +-++-
a×(b−c) = -262023 or ----0+--0++0
```

## Raku

(formerly Perl 6)

Works with: rakudo version 2017.01
```class BT {
has @.coeff;

my %co2bt = '-1' => '-', '0' => '0', '1' => '+';
my %bt2co = %co2bt.invert;

multi method new (Str \$s) {
self.bless(coeff => %bt2co{\$s.flip.comb});
}
multi method new (Int \$i where \$i >= 0) {
self.bless(coeff => carry \$i.base(3).comb.reverse);
}
multi method new (Int \$i where \$i < 0) {
self.new(-\$i).neg;
}

method Str () { %co2bt{@!coeff}.join.flip }
method Int () { [+] @!coeff Z* (1,3,9...*) }

multi method neg () {
self.new: coeff => carry self.coeff X* -1;
}
}

sub carry (*@digits is copy) {
loop (my \$i = 0; \$i < @digits; \$i++) {
while @digits[\$i] < -1 { @digits[\$i] += 3; @digits[\$i+1]--; }
while @digits[\$i] > 1  { @digits[\$i] -= 3; @digits[\$i+1]++; }
}
pop @digits while @digits and not @digits[*-1];
@digits;
}

multi prefix:<-> (BT \$x) { \$x.neg }

multi infix:<+> (BT \$x, BT \$y) {
my (\$b,\$a) = sort +*.coeff, (\$x, \$y);
BT.new: coeff => carry (\$a.coeff Z+ |\$b.coeff, |(0 xx \$a.coeff - \$b.coeff));
}

multi infix:<-> (BT \$x, BT \$y) { \$x + \$y.neg }

multi infix:<*> (BT \$x, BT \$y) {
my @x = \$x.coeff;
my @y = \$y.coeff;
my @z = 0 xx @x+@y-1;
my @safe;
for @x -> \$xd {
@z = @z Z+ |(@y X* \$xd), |(0 xx @z-@y);
@safe.push: @z.shift;
}
BT.new: coeff => carry @safe, @z;
}

my \$a = BT.new: "+-0++0+";
my \$b = BT.new: -436;
my \$c = BT.new: "+-++-";
my \$x = \$a * ( \$b - \$c );

say 'a == ', \$a.Int;
say 'b == ', \$b.Int;
say 'c == ', \$c.Int;
say "a × (b − c) == ", ~\$x, ' == ', \$x.Int;
```
Output:
```a == 523
b == -436
c == 65
a × (b − c) == ----0+--0++0 == -262023```

## REXX

The REXX program could be optimized by using   (procedure) with   expose   and having the   \$.   and   @.   variables set only once.

```/*REXX program converts decimal  ◄───►  balanced ternary;  it also performs arithmetic. */
numeric digits 10000                             /*be able to handle  gihugic  numbers. */
Ao = '+-0++0+' ;    Abt =      Ao                /*   [↓]  2 literals used by subroutine*/
Bo =    '-436' ;    Bbt = d2bt(Bo);                    @ = "(decimal)"
Co =   '+-++-' ;    Cbt =      Co ;                   @@ = "balanced ternary ="
call btShow  '[a]',       Abt
call btShow  '[b]',       Bbt
call btShow  '[c]',       Cbt
say;                      \$bt = btMul(Abt, btSub(Bbt, Cbt) )
call btShow '[a*(b-c)]',  \$bt
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
d2bt: procedure; parse arg x 1;  x= x / 1;    p= 0;  \$.= '-';   \$.1= "+";   \$.0= 0;     #=
do  until x==0;           _= (x // (3** (p+1) ) )  %  3**p
if _== 2  then _= -1
else if _== -2  then _= 1
x= x  -  _ * (3**p);      p= p + 1;                     #= \$._  ||  #
end   /*until*/;          return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
bt2d: procedure; parse arg x;  r= reverse(x);  \$.= -1;  \$.0= 0;  #= 0;    _= '+';   \$._= 1
do j=1  for length(x);  _= substr(r, j, 1);  #= #  +  \$._ * 3 ** (j-1)
end   /*j*/;                         return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
btAdd: procedure; parse arg x,y;    rx= reverse(x);      ry= reverse(y);          carry= 0
@.= 0;   _= '-';   @._= -1;   _= "+";  @._= 1;  \$.= '-';   \$.0= 0;   \$.1= "+";   #=
do j=1  for max( length(x), length(y) )
x_= substr(rx, j, 1);            xn= @.x_
y_= substr(ry, j, 1);            yn= @.y_
s= xn + yn + carry;           carry= 0
if s== 2  then do;   s=-1;    carry= 1;    end
if s== 3  then do;   s= 0;    carry= 1;    end
if s==-2  then do;   s= 1;    carry=-1;    end
#= \$.s || #
end   /*j*/
if carry\==0  then #= \$.carry || #;                      return btNorm(#)
/*──────────────────────────────────────────────────────────────────────────────────────*/
btMul: procedure; parse arg x 1 x1 2, y 1 y1 2; if x==0 | y==0  then return 0;  S= 1;  P=0
x= btNorm(x); y= btNorm(y); Lx= length(x); Ly= length(y)  /*handle: 0-xxx values.*/
if x1=='-'  then do;   x= btNeg(x);   S= -S;   end        /*positate the number. */
if y1=='-'  then do;   y= btNeg(y);   S= -S;   end        /*    "     "    "     */
if Ly>Lx    then parse value  x y  with  y x              /*optimize  "    "     */
do   until  y==0    /*keep adding 'til done*/
P= btAdd(P,  x )    /*multiple the hard way*/
y= btSub(y, '+')    /*subtract  1  from  Y.*/
end   /*until*/
if S==-1  then P= btNeg(P);  return P       /*adjust the product's sign;  return.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
btNeg:  return translate( arg(1), '-+', "+-")                    /*negate bal_ternary #.*/
btNorm: _= strip(arg(1), 'L', 0);  if _==''  then _=0;  return _ /*normalize the number.*/
btSub:  return btAdd( arg(1), btNeg( arg(2) ) )                  /*subtract two BT args.*/
btShow: say center( arg(1), 9)  right( arg(2), 20)  @@  right( bt2d(arg(2)), 9) @;  return
```
output   when using the default input:
```   [a]                 +-0++0+ balanced ternary =       523 (decimal)
[b]                 -++-0-- balanced ternary =      -436 (decimal)
[c]                   +-++- balanced ternary =        65 (decimal)

[a*(b-c)]         ----0+--0++0 balanced ternary =   -262023 (decimal)
```

## RPL

Translation of: Nim
Works with: RPL version HP-48
```« "-0+" SWAP POS 2 -
» 'CH→TR' STO

« "-0+" SWAP 2 + DUP SUB
» 'TR→CH' STO

« WHILE DUP SIZE OVER HEAD "0" == AND REPEAT TAIL END
» 'NOZEROS' STO

« DUP SIZE → bt len
« 0
1 len FOR j
bt j DUP SUB CH→TR
3 len j - ^ * +
NEXT
» » 'BT→I' STO

« DUP "" "0" IFTE
WHILE OVER REPEAT
OVER 3 MOD
1 ≤ LASTARG NEG IFTE     @ convert 2 into -1
DUP TR→CH ROT - 3 / IP SWAP
END
SWAP DROP
» 'I→BT' STO

« IF OVER SIZE OVER SIZE < THEN SWAP END
WHILE OVER SIZE OVER SIZE > REPEAT "0" SWAP + END
→ a b
« "" 0
a SIZE 1 FOR j
a j DUP SUB CH→TR + b j DUP SUB CH→TR +
IF DUP ABS 2 ≥ THEN
DUP 3 MOD 1 ≤ LASTARG NEG IFTE
SWAP SIGN
ELSE 0 END
SWAP TR→CH ROT + SWAP
-1 STEP
IF THEN LASTARG TR→CH SWAP + END
NOZEROS

« ""
1 3 PICK SIZE FOR j
OVER j DUP SUB
CH→TR NEG TR→CH +
NEXT
SWAP DROP
» 'NEGBT' STO

« "" → a b shift
« "0"
a SIZE 1 FOR j
a j DUP SUB
IF DUP "0" ≠ THEN
b
IF SWAP "-" == THEN NEGBT END
END
'shift' "0" STO+
-1 STEP
NOZEROS
» » 'MULBT' STO

« "+-0++0+" -436 I→BT "+-++-" → a b c
« a BT→I b BT→I c BT→I 3 →LIST
a b c NEGBT ADDBT MULBT
```
Output:
```3: { 523 -436 65 }
2: "----0+--0++0"
1: -262023
```

## Ruby

```class BalancedTernary
include Comparable
def initialize(str = "")
if str =~ /[^-+0]+/
raise ArgumentError, "invalid BalancedTernary number: #{str}"
end
@digits = trim0(str)
end

I2BT = {0 => ["0",0], 1 => ["+",0], 2 => ["-",1]}
def self.from_int(value)
n = value.to_i
digits = ""
while n != 0
quo, rem = n.divmod(3)
bt, carry = I2BT[rem]
digits = bt + digits
n = quo + carry
end
new(digits)
end

BT2I = {"-" => -1, "0" => 0, "+" => 1}
def to_int
@digits.chars.inject(0) do |sum, char|
sum = 3 * sum + BT2I[char]
end
end
alias :to_i :to_int

def to_s
@digits.dup                 # String is mutable
end
alias :inspect :to_s

def <=>(other)
to_i <=> other.to_i
end

"---" => ["-","0"], "--0" => ["-","+"], "--+" => ["0","-"],
"-0-" => ["-","+"], "-00" => ["0","-"], "-0+" => ["0","0"],
"-+-" => ["0","-"], "-+0" => ["0","0"], "-++" => ["0","+"],
"0--" => ["-","+"], "0-0" => ["0","-"], "0-+" => ["0","0"],
"00-" => ["0","-"], "000" => ["0","0"], "00+" => ["0","+"],
"0+-" => ["0","0"], "0+0" => ["0","+"], "0++" => ["+","-"],
"+--" => ["0","-"], "+-0" => ["0","0"], "+-+" => ["0","+"],
"+0-" => ["0","0"], "+00" => ["0","+"], "+0+" => ["+","-"],
"++-" => ["0","+"], "++0" => ["+","-"], "+++" => ["+","0"],
}

def +(other)
maxl = [to_s.length, other.to_s.length].max
carry = "0"
sum = a.zip( b ).inject("") do |sum, (c1, c2)|
carry, digit = ADDITION_TABLE[carry + c1 + c2]
sum = digit + sum
end
self.class.new(carry + sum)
end

MULTIPLICATION_TABLE = {
"-" => "+0-",
"0" => "000",
"+" => "-0+",
}

def *(other)
product = self.class.new
other.to_s.each_char do |bdigit|
row = to_s.tr("-0+", MULTIPLICATION_TABLE[bdigit])
product += self.class.new(row)
product << 1
end
product >> 1
end

# negation
def -@()
self.class.new(@digits.tr('-+','+-'))
end

# subtraction
def -(other)
self + (-other)
end

# shift left
def <<(count)
@digits = trim0(@digits + "0"*count)
self
end

# shift right
def >>(count)
@digits[-count..-1] = "" if count > 0
@digits = trim0(@digits)
self
end

private

def trim0(str)
str = str.sub(/^0+/, "")
str = "0" if str.empty?
str
end

str.rjust(len, "0").reverse.chars
end
end

a = BalancedTernary.new("+-0++0+")
b = BalancedTernary.from_int(-436)
c = BalancedTernary.new("+-++-")

%w[a b c a*(b-c)].each do |exp|
val = eval(exp)
puts "%8s :%13s,%8d" % [exp, val, val.to_i]
end
```
Output:
```       a :      +-0++0+,     523
b :      -++-0--,    -436
c :        +-++-,      65
a*(b-c) : ----0+--0++0, -262023
```

## Rust

```use std::{
cmp::min,
convert::{TryFrom, TryInto},
fmt,
str::FromStr,
};

fn main() -> Result<(), &'static str> {
let a = BalancedTernary::from_str("+-0++0+")?;
let b = BalancedTernary::from(-436);
let c = BalancedTernary::from_str("+-++-")?;
println!("a = {} = {}", a, i128::try_from(a.clone())?);
println!("b = {} = {}", b, i128::try_from(b.clone())?);
println!("c = {} = {}", c, i128::try_from(c.clone())?);

let d = a * (b + -c);
println!("a * (b - c) = {} = {}", d, i128::try_from(d.clone())?);

let e = BalancedTernary::from_str(
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
)?;
assert_eq!(i128::try_from(e).is_err(), true);

Ok(())
}

#[derive(Clone, Copy, PartialEq)]
enum Trit {
Zero,
Pos,
Neg,
}

impl TryFrom<char> for Trit {
type Error = &'static str;

fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'0' => Ok(Self::Zero),
'+' => Ok(Self::Pos),
'-' => Ok(Self::Neg),
_ => Err("Invalid character for balanced ternary"),
}
}
}

impl From<Trit> for char {
fn from(x: Trit) -> Self {
match x {
Trit::Zero => '0',
Trit::Pos => '+',
Trit::Neg => '-',
}
}
}

// (Carry, Current)
type Output = (Self, Self);

fn add(self, rhs: Self) -> Self::Output {
use Trit::{Neg, Pos, Zero};
match (self, rhs) {
(Zero, x) | (x, Zero) => (Zero, x),
(Pos, Neg) | (Neg, Pos) => (Zero, Zero),
(Pos, Pos) => (Pos, Neg),
(Neg, Neg) => (Neg, Pos),
}
}
}

impl Mul for Trit {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
use Trit::{Neg, Pos, Zero};
match (self, rhs) {
(Zero, _) | (_, Zero) => Zero,
(Pos, Pos) | (Neg, Neg) => Pos,
(Pos, Neg) | (Neg, Pos) => Neg,
}
}
}

impl Neg for Trit {
type Output = Self;

fn neg(self) -> Self::Output {
match self {
Trit::Zero => Trit::Zero,
Trit::Pos => Trit::Neg,
Trit::Neg => Trit::Pos,
}
}
}

// The vector is stored in reverse from how it would be viewed, as
// operations tend to work backwards
#[derive(Clone)]
struct BalancedTernary(Vec<Trit>);

impl fmt::Display for BalancedTernary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
self.0
.iter()
.rev()
.map(|&d| char::from(d))
.collect::<String>()
)
}
}

type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
use Trit::Zero;

fn trim(v: &mut Vec<Trit>) {
while let Some(last_elem) = v.pop() {
if last_elem != Zero {
v.push(last_elem);
break;
}
}
}

if rhs.0.is_empty() {
// A balanced ternary shouldn't be empty
if self.0.is_empty() {
return BalancedTernary(vec![Zero]);
}
return self;
}

let length = min(self.0.len(), rhs.0.len());
let mut sum = Vec::new();
let mut carry = vec![Zero];

for i in 0..length {
let (carry_dig, digit) = self.0[i] + rhs.0[i];
sum.push(digit);
carry.push(carry_dig);
}
// At least one of these two loops will be ignored
for i in length..self.0.len() {
sum.push(self.0[i]);
}
for i in length..rhs.0.len() {
sum.push(rhs.0[i]);
}

trim(&mut sum);
trim(&mut carry);

BalancedTernary(sum) + BalancedTernary(carry)
}
}

// This version of `Mul` requires an implementation of the `Add` trait
impl Mul for BalancedTernary {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
let mut results = Vec::with_capacity(rhs.0.len());
for i in 0..rhs.0.len() {
let mut digits = vec![Trit::Zero; i];
for j in 0..self.0.len() {
digits.push(self.0[j] * rhs.0[i]);
}
results.push(BalancedTernary(digits));
}
#[allow(clippy::suspicious_arithmetic_impl)]
results
.into_iter()
.fold(BalancedTernary(vec![Trit::Zero]), |acc, x| acc + x)
}
}

impl Neg for BalancedTernary {
type Output = Self;

fn neg(self) -> Self::Output {
BalancedTernary(self.0.iter().map(|&x| -x).collect())
}
}

impl FromStr for BalancedTernary {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
s.chars()
.rev()
.map(|c| c.try_into())
.collect::<Result<_, _>>()
.map(BalancedTernary)
}
}

impl From<i128> for BalancedTernary {
fn from(x: i128) -> Self {
let mut v = Vec::new();
let mut curr = x;

loop {
let rem = curr % 3;

match rem {
0 => v.push(Trit::Zero),
1 | -2 => v.push(Trit::Pos),
2 | -1 => v.push(Trit::Neg),
_ => unreachable!(),
}

let offset = (rem as f64 / 3.0).round() as i128;
curr = curr / 3 + offset;

if curr == 0 {
break;
}
}

BalancedTernary(v)
}
}

impl TryFrom<BalancedTernary> for i128 {
type Error = &'static str;

fn try_from(value: BalancedTernary) -> Result<Self, Self::Error> {
value
.0
.iter()
.enumerate()
.try_fold(0_i128, |acc, (i, character)| {
let size_err = "Balanced ternary string is too large to fit into 16 bytes";
let index: u32 = i.try_into().map_err(|_| size_err)?;

match character {
Trit::Zero => Ok(acc),
Trit::Pos => 3_i128
.checked_pow(index)
.ok_or(size_err),
Trit::Neg => 3_i128
.checked_pow(index)
.and_then(|x| acc.checked_sub(x))
.ok_or(size_err),
}
})
}
}
```

Output

```a = +-0++0+ = 523
b = -++-0-- = -436
c = +-++- = 65
a * (b - c) = ----0+--0++0 = -262023
```

## Scala

This implementation represents ternaries as a reversed list of bits. Also, there are plenty of implicit convertors

```object TernaryBit {
val P = TernaryBit(+1)
val M = TernaryBit(-1)
val Z = TernaryBit( 0)

implicit def asChar(t: TernaryBit): Char = t.charValue
implicit def valueOf(c: Char): TernaryBit = {
c match {
case '0' => 0
case '+' => 1
case '-' => -1
case nc => throw new IllegalArgumentException("Illegal ternary symbol " + nc)
}
}
implicit def asInt(t: TernaryBit): Int = t.intValue
implicit def valueOf(i: Int): TernaryBit = TernaryBit(i)
}

case class TernaryBit(val intValue: Int) {

def inverse: TernaryBit = TernaryBit(-intValue)

def charValue = intValue match {
case  0 => '0'
case  1 => '+'
case -1 => '-'
}
}

class Ternary(val bits: List[TernaryBit]) {

def + (b: Ternary) = {
val sumBits: List[Int] = bits.map(_.intValue).zipAll(b.bits.map(_.intValue), 0, 0).map(p => p._1 + p._2)

// normalize
val iv: Tuple2[List[Int], Int] = (List(), 0)
val (revBits, carry) = sumBits.foldLeft(iv)((accu: Tuple2[List[Int], Int], e: Int) => {
val s = e + accu._2
(((s + 1 + 3 * 100) % 3 - 1) :: accu._1 , (s + 1 + 3 * 100) / 3 - 100)
})

new Ternary(( TernaryBit```