Balanced ternary: Difference between revisions

m
 
(45 intermediate revisions by 23 users not shown)
Line 1:
{{task}}
[[wp:Balanced ternary|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. For example, decimal 11 = 3<sup>2</sup> + 3<sup>1</sup> − 3<sup>0</sup>, thus can be written as "++−", while 6 = 3<sup>2</sup> − 3<sup>1</sup> + 0 × 3<sup>0</sup>, i.e., "+−0".
 
For this task, implement balanced ternary representation of integers with the following
 
;Examples:
'''Requirements'''
Decimal 11 = 3<sup>2</sup> + 3<sup>1</sup> − 3<sup>0</sup>, thus it can be written as "++−"
 
Decimal 6 = 3<sup>2</sup> − 3<sup>1</sup> + 0 × 3<sup>0</sup>, thus it can be written as "+−0"
 
 
;Task:
Implement balanced ternary representation of integers with the following:
# Support arbitrarily large integers, both positive and negative;
# 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).
Line 10 ⟶ 16:
# Provide ways to perform addition, negation and multiplication directly on balanced ternary integers; do ''not'' convert to native integers first.
# 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'' × (''b'' − ''c''), 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 [[wp:arbitrary precision|arbitrary precision]] [[wp:floating point|floating point]] balanced ternary.
<br><br>
 
=={{header|ALGOL 6811l}}==
{{trans|Python}}
See also:
 
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]]
<syntaxhighlight lang="11l">T BalancedTernary
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]]
. -: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)
R BalancedTernary(.:add(.digits, b.digits))
 
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 .:add(x, y)
 
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)</syntaxhighlight>
 
{{out}}
<pre>
a: 523 +-0++0+
b: -436 -++-0--
c: 65 +-++-
a * (b - c): -262023 ----0+--0++0
</pre>
 
=={{header|Ada}}==
Specifications (bt.ads):
<langsyntaxhighlight Adalang="ada">with Ada.Finalization;
 
package BT is
Line 70 ⟶ 175:
procedure Finalize (Object : in out Balanced_Ternary);
end BT;</langsyntaxhighlight>
 
Implementation (bt.adb):
<langsyntaxhighlight Adalang="ada">with Ada.Unchecked_Deallocation;
 
package body BT is
Line 253 ⟶ 358:
end Initialize;
 
end BT;</langsyntaxhighlight>
 
Test task requirements (testbt.adb):
<langsyntaxhighlight Adalang="ada">with Ada.Text_Io; use Ada.Text_Io;
with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
with BT; use BT;
Line 274 ⟶ 379:
Put("a * (b - c) = "); Put(To_integer(Result), 4);
Put_Line (" " & To_String(Result));
end TestBT;</langsyntaxhighlight>
Output:
<pre>
Line 282 ⟶ 387:
a * (b - c) = -262023 ----0+--0++0
</pre>
 
=={{header|ALGOL 68}}==
See also:
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]]
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]]
 
=={{header|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.
 
<syntaxhighlight lang="applescript">-- 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.
on addBTs(bt1, bt2)
checkInput({bt1, bt2}, "addBTs")
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, "")
end addBTs
 
-- 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.
set multiplicationResult to addBTs(multiplicationResult, subresult)
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</syntaxhighlight>
 
{{output}}
<syntaxhighlight lang="applescript">"a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 or -262023"</syntaxhighlight>
 
=={{header|ATS}}==
<syntaxhighlight lang="ats">
<lang ATS>
(*
** This one is
Line 498 ⟶ 787:
//
} (* end of [main0] *)
</syntaxhighlight>
</lang>
Output:
<pre>
Line 508 ⟶ 797:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">BalancedTernary(n){
k = 0
if abs(n)<2
Line 529 ⟶ 818:
}
return r
}</langsyntaxhighlight>
Examples:<langsyntaxhighlight AutoHotkeylang="autohotkey">data =
(
523
Line 540 ⟶ 829:
result .= A_LoopField " : " BalancedTernary(A_LoopField) "`n"
MsgBox % result
return</langsyntaxhighlight>
Outputs:<pre>
523 : +-0++0+
Line 547 ⟶ 836:
-262023 : ----0+--0++0</pre>
 
=={{header|C++Bruijn}}==
The default syntax sugar for numbers in bruijn is balanced ternary. The implementation of respective arithmetic operators is in <code>std/Number/Ternary</code> and <code>std/Math</code>. Converting between bases can be accomplished using <code>std/Number/Conversion</code>. 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").
<lang cpp>
#include <iostream>
#include <string>
#include <climits>
using namespace std;
 
<syntaxhighlight lang="bruijn">
class BalancedTernary {
:import std/Combinator .
protected:
:import std/Logic .
// Store the value as a reversed string of +, 0 and - characters
:import std/Pair .
string value;
 
# negative trit indicating coefficient of (-1)
// Helper function to change a balanced ternary character to an integer
t⁻ [[[2]]]
int charToInt(char c) const {
if (c == '0')
return 0;
return 44 - c;
}
 
# positive trit indicating coefficient of (+1)
// Helper function to negate a string of ternary characters
t⁺ [[[1]]]
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;
}
 
# zero trit indicating coefficient of 0
public:
t⁰ [[[0]]]
// Default constructor
BalancedTernary() {
value = "0";
}
 
# shifts a negative trit into a balanced ternary number
// Construct from a string
↑⁻‣ [[[[[2 (4 3 2 1 0)]]]]]
BalancedTernary(string s) {
value = string(s.rbegin(), s.rend());
}
 
# shifts a positive trit into a balanced ternary number
// Construct from an integer
↑⁺‣ [[[[[1 (4 3 2 1 0)]]]]]
BalancedTernary(long long n) {
if (n == 0) {
value = "0";
return;
}
 
# shifts a zero trit into a balanced ternary number
bool neg = n < 0;
↑⁰‣ [[[[[0 (4 3 2 1 0)]]]]]
if (neg)
n = -n;
 
# shifts a specified trit into a balanced ternary number
value = "";
…↑… [[[[[[5 2 1 0 (4 3 2 1 0)]]]]]]
while (n != 0) {
int r = n % 3;
if (r == 0)
value += "0";
else if (r == 1)
value += "+";
else {
value += "-";
++n;
}
 
# negates a balanced ternary number
n /= 3;
-‣ [[[[[4 3 1 2 0]]]]]
}
 
# increments a balanced ternary number (can introduce leading 0s)
if (neg)
++‣ [~(0 z a⁻ a⁺ a⁰)]
value = negate(value);
z (+0) : (+1)
}
a⁻ &[[↑⁻1 : ↑⁰1]]
a⁺ &[[↑⁺1 : ↑⁻0]]
a⁰ &[[↑⁰1 : ↑⁺1]]
 
# decrements a balanced ternary number (can introduce leading 0s)
// Copy constructor
--‣ [~(0 z a⁻ a⁺ a⁰)]
BalancedTernary(const BalancedTernary &n) {
z (+0) : (-1)
value = n.value;
a⁻ &[[↑⁻1 : ↑⁺0]]
}
a⁺ &[[↑⁺1 : ↑⁰1]]
a⁰ &[[↑⁰1 : ↑⁻1]]
 
# converts the normal balanced ternary representation into abstract form
// Addition operators
→^‣ [0 z a⁻ a⁺ a⁰]
BalancedTernary operator+(BalancedTernary n) const {
z (+0)
n += *this;
a⁻ [[[[[2 4]]]]]
return n;
a⁺ [[[[[1 4]]]]]
}
a⁰ [[[[[0 4]]]]]
 
# converts the abstracted balanced ternary representation back to normal
BalancedTernary& operator+=(const BalancedTernary &n) {
→_‣ y [[0 z a⁻ a⁺ a⁰]]
static char *add = "0+-0+-0";
z (+0)
static char *carry = "--000++";
a⁻ [↑⁻(2 0)]
a⁺ [↑⁺(2 0)]
a⁰ [↑⁰(2 0)]
 
# adds two balanced ternary numbers (can introduce leading 0s)
int lastNonZero = 0;
…+… [[[c (0 z a⁻ a⁺ a⁰)] 1 →^0]]
char c = '0';
b⁻ [1 ↑⁺(3 0 t⁻) ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁰)]
for (int i = 0; i < value.length() || i < n.value.length(); ++i) {
b⁰ [1 ↑ (3 0 t⁰)]
char a = i < value.length() ? value[i] : '0';
b⁺ [1 ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁺) ↑⁺(3 0 t⁰)]
char b = i < n.value.length() ? n.value[i] : '0';
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)
int sum = charToInt(a) + charToInt(b) + charToInt(c) + 3;
…-… [[1 + -0]]
c = carry[sum];
 
# multiplicates two balanced ternary numbers (can introduce leading 0s)
if (i < value.length())
…⋅… [[1 z a⁻ a⁺ a⁰]]
value[i] = add[sum];
z (+0)
else
a⁻ [↑⁰0 - 1]
value += add[sum];
a⁺ [↑⁰0 + 1]
a⁰ [↑⁰0]
 
# true if balanced ternary number is zero
if (add[sum] != '0')
=?‣ [0 true [false] [false] i]
lastNonZero = i;
}
 
# true if two balanced ternary numbers are equal
if (c != '0')
# → ignores leading 0s!
value += c;
…=?… [[[0 z a⁻ a⁺ a⁰] 1 →^0]]
else
z [=?(→_0)]
value = value.substr(0, lastNonZero + 1); // Chop off leading zeroes
a⁻ [[0 false [2 0] [false] [false]]]
a⁺ [[0 false [false] [2 0] [false]]]
a⁰ [[0 (1 0) [false] [false] [2 0]]]
 
main [[0]]
return *this;
}
 
# --- tests/examples ---
// Negation operator
BalancedTernary operator-() const {
BalancedTernary result;
result.value = negate(value);
return result;
}
 
:test ((-42) + (-1) =? (-43)) (true)
// Subtraction operators
:test ((+1) + (+2) =? (+3)) (true)
BalancedTernary operator-(const BalancedTernary &n) const {
:test ((-42) - (-1) =? (-41)) (true)
return operator+(-n);
:test ((+1) - (+2) =? (-1)) (true)
}
:test ((-1) ⋅ (+42) =? (-42)) (true)
:test ((+3) ⋅ (+11) =? (+33)) (true)
</syntaxhighlight>
 
=={{header|C}}==
BalancedTernary& operator-=(const BalancedTernary &n) {
{{trans|Perl}}
return operator+=(-n);
<syntaxhighlight lang="c">#include <stdio.h>
}
#include <string.h>
 
void reverse(char *p) {
// Multiplication operators
size_t len = strlen(p);
BalancedTernary operator*(BalancedTernary n) const {
char *r = p + len - 1;
n *= *this;
while (p < r) {
return n;
*p ^= *r;
}
*r ^= *p;
*p++ ^= *r--;
}
}
 
void to_bt(int n, char *b) {
BalancedTernary& operator*=(const BalancedTernary &n) {
static char d[] = { '0', '+', '-' };
BalancedTernary pos = *this;
static int v[] = { 0, 1, -1 };
BalancedTernary neg = -pos; // Storing an extra copy to avoid negating repeatedly
value = "0";
 
char *ptr = b;
for (int i = 0; i < n.value.length(); ++i) {
*ptr = 0;
if (n.value[i] == '+')
operator+=(pos);
else if (n.value[i] == '-')
operator+=(neg);
pos.value = '0' + pos.value;
neg.value = '0' + neg.value;
}
 
while (n) {
return *this;
int r = n % 3;
}
if (r < 0) {
r += 3;
}
 
*ptr = d[r];
// Stream output operator
*(++ptr) = 0;
friend ostream& operator<<(ostream &out, const BalancedTernary &n) {
out << n.toString();
return out;
}
 
n -= v[r];
// Convert to string
n /= 3;
string toString() const {
}
return string(value.rbegin(), value.rend());
}
 
reverse(b);
// 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;
}
 
int from_bt(const char *a) {
// Convert to integer if possible
int n = 0;
bool tryInt(long long &out) const {
long long result = 0;
bool ok = true;
 
while (*a != '\0') {
for (long long i = 0, pow = 1; i < value.length() && ok; ++i, pow *= 3) {
n *= 3;
if (value[i] == '+') {
if (*a == '+') {
ok &= LLONG_MAX - pow >= result; // Clear ok if the result overflows
n++;
result += pow;
} else if (value[i]*a == '-') {
n--;
ok &= LLONG_MIN + pow <= result; // Clear ok if the result overflows
}
result -= pow;
a++;
}
}
}
 
return n;
if (ok)
}
out = result;
return ok;
}
};
 
char last_char(char *ptr) {
int main() {
char c;
BalancedTernary a("+-0++0+");
BalancedTernary b(-436);
BalancedTernary c("+-++-");
 
cout << "a = "if <<(ptr a== <<NULL "|| *ptr == " << a.toInt('\0') << endl;{
return '\0';
cout << "b = " << b << " = " << b.toInt() << endl;
}
cout << "c = " << c << " = " << c.toInt() << endl;
 
while (*ptr != '\0') {
BalancedTernary d = a * (b - c);
ptr++;
}
ptr--;
 
c = *ptr;
cout << "a * (b - c) = " << d << " = " << d.toInt() << endl;
*ptr = 0;
return c;
}
 
void add(const char *b1, const char *b2, char *out) {
BalancedTernary e("+++++++++++++++++++++++++++++++++++++++++");
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);
long long n;
strcpy(c2, b2);
if (e.tryInt(n))
cout << "e = " << e << "L1 = " << n << endllast_char(c1);
L2 = last_char(c2);
else
if (L2 < L1) {
cout << "e = " << e << " is too big to fit in a long long" << endl;
L2 ^= L1;
L1 ^= L2;
L2 ^= L1;
}
 
if (L1 == '-') {
return 0;
if (L2 == '0') {
d[0] = '-';
}
if (L2 == '-') {
d[0] = '+';
d[1] = '-';
}
}
if (L1 == '+') {
if (L2 == '0') {
d[0] = '+';
}
if (L2 == '-') {
d[0] = '0';
}
if (L2 == '+') {
d[0] = '-';
d[1] = '+';
}
}
if (L1 == '0') {
if (L2 == '0') {
d[0] = '0';
}
}
 
add(c1, &d[1], ob1);
add(ob1, c2, ob2);
strcpy(out, ob2);
 
d[1] = 0;
strcat(out, d);
} else if (*b1 != '\0') {
strcpy(out, b1);
} else if (*b2 != '\0') {
strcpy(out, b2);
} else {
*out = '\0';
}
}
</lang>
 
void unary_minus(const char *b, char *out) {
Output
while (*b != '\0') {
<pre>
if (*b == '-') {
a = +-0++0+ = 523
b = - *out++-0-- = -436'+';
b++;
c = +-++- = 65
} else if (*b == '+') {
a * (b - c) = ----0+--0++0 = -262023
*out++ = '-';
e = +++++++++++++++++++++++++++++++++++++++++ is too big to fit in a long long
b++;
</pre>
} else {
*out++ = *b++;
}
}
*out = '\0';
}
 
void subtract(const char *b1, const char *b2, char *out) {
char buf[16];
unary_minus(b2, buf);
add(b1, buf, out);
}
 
void mult(const char *b1, const char *b2, char *out) {
char r[16] = "0";
char t[16];
char c1[16];
char c2[16];
char *ptr = c2;
 
strcpy(c1, b1);
strcpy(c2, b2);
 
reverse(c2);
 
while (*ptr != '\0') {
if (*ptr == '+') {
add(r, c1, t);
strcpy(r, t);
}
if (*ptr == '-') {
subtract(r, c1, t);
strcpy(r, t);
}
strcat(c1, "0");
 
ptr++;
}
 
ptr = r;
while (*ptr == '0') {
ptr++;
}
strcpy(out, ptr);
}
 
int main() {
const char *a = "+-0++0+";
char b[16];
const char *c = "+-++-";
char t[16];
char d[16];
 
to_bt(-436, b);
subtract(b, c, t);
mult(a, t, d);
 
printf(" a: %14s %10d\n", a, from_bt(a));
printf(" b: %14s %10d\n", b, from_bt(b));
printf(" c: %14s %10d\n", c, from_bt(c));
printf("a*(b-c): %14s %10d\n", d, from_bt(d));
 
return 0;
}</syntaxhighlight>
{{out}}
<pre> a: +-0++0+ 523
b: -++-0-- -436
c: +-++- 65
a*(b-c): ----0+--0++0 -262023</pre>
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Text;
using System.Collections.Generic;
Line 1,003 ⟶ 1,383:
return result;
}
}</langsyntaxhighlight>
output:
<pre>a: +-0++0+ = 523
Line 1,009 ⟶ 1,389:
c: +-++- = 65
a * (b - c): ----0+--0++0 = -262023</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#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;
}
 
// Addition operators
BalancedTernary operator+(BalancedTernary n) const {
n += *this;
return n;
}
 
BalancedTernary& operator+=(const BalancedTernary &n) {
static char *add = "0+-0+-0";
static char *carry = "--000++";
 
int lastNonZero = 0;
char c = '0';
for (int i = 0; i < value.length() || i < n.value.length(); ++i) {
char a = i < value.length() ? value[i] : '0';
char b = i < n.value.length() ? n.value[i] : '0';
 
int sum = charToInt(a) + charToInt(b) + charToInt(c) + 3;
c = carry[sum];
 
if (i < value.length())
value[i] = add[sum];
else
value += add[sum];
 
if (add[sum] != '0')
lastNonZero = i;
}
 
if (c != '0')
value += c;
else
value = value.substr(0, lastNonZero + 1); // 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;
}
</syntaxhighlight>
 
Output
<pre>
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
</pre>
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">;;; balanced ternary
;;; represented as a list of 0, 1 or -1s, with least significant digit first
Line 1,103 ⟶ 1,707:
(bt-integer b) (bt-string b)
(bt-integer c) (bt-string c)
(bt-integer d) (bt-string d)))</langsyntaxhighlight>output<syntaxhighlight lang="text">a 523 +-0++0+
b -436 -++-0--
c 65 +-++-
a × (b − c) = -262023 ----0+--0++0</langsyntaxhighlight>
 
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.bigint, std.range, std.algorithm;
 
struct BalancedTernary {
Line 1,253 ⟶ 1,857:
const /*immutable*/ r = a * (b - c);
writeln("a * (b - c): ", r.toBint, ' ', r);
}</langsyntaxhighlight>
{{out}}
<pre>a: 523 +-0++0+
Line 1,262 ⟶ 1,866:
=={{header|Elixir}}==
{{trans|Erlang}}
<langsyntaxhighlight lang="elixir">defmodule Ternary do
def to_string(t), do: ( for x <- t, do: to_char(x) ) |> List.to_string
Line 1,335 ⟶ 1,939:
IO.puts "b = #{bs} -> #{b}"
IO.puts "c = #{cs} -> #{c}"
IO.puts "a x (b - c) = #{rs} -> #{r}"</langsyntaxhighlight>
 
{{out}}
Line 1,346 ⟶ 1,950:
 
=={{header|Erlang}}==
<langsyntaxhighlight lang="erlang">
-module(ternary).
-compile(export_all).
Line 1,436 ⟶ 2,040:
add_util(1) -> [0,1];
add_util(0) -> [0,0].
</syntaxhighlight>
</lang>
'''Output'''
<langsyntaxhighlight lang="erlang">
234> ternary:test().
A = +-0++0+ -> 523
Line 1,445 ⟶ 2,049:
A x (B - C) = 0----0+--0++0 -> -262023
ok
</syntaxhighlight>
</lang>
 
 
 
=={{header|Factor}}==
{{trans|Ruby}}
{{trans|Common Lisp}}
{{works with|Factor|0.98}}
<syntaxhighlight lang="factor">USING: kernel combinators locals formatting lint literals
sequences assocs strings arrays
math math.functions math.order ;
IN: rosetta-code.bt
CONSTANT: addlookup {
{ 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 ] }
} case bt-add 0 suffix
] reduce
1 head*
;
 
[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
]</syntaxhighlight>
<syntaxhighlight lang="text">a: 523, +-0++0+
b: -436, -++-0--
c: 65, +-++-
a*(b-c): -262023, ----0+--0++0</syntaxhighlight>
 
=={{header|FreeBASIC}}==
{{trans|Liberty BASIC}}
<syntaxhighlight lang="freebasic">
#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
c1S = Mid(cadena,i,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
 
Function pad(cadenaA As String, n As Integer) As String
Dim As String relleno = cadenaA
While Len(relleno) < n
relleno = "0" + relleno
Wend
Return relleno
End Function
 
Function addTernary(cadenaA As String, cadenaB As String) As String
Dim As Integer l = max(Len(cadenaA), Len(cadenaB))
Dim As Integer i, x, y, z
cadenaA = pad(cadenaA, l)
cadenaB = pad(cadenaB, l)
Dim As String resultado = ""
Dim As Byte llevar = 0
For i = l To 1 Step -1
x = Instr(t, Mid(cadenaA,i,1))-2
y = Instr(t, Mid(cadenaB,i,1))-2
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
resultado = Mid(t,z+2,1) + resultado
Next i
If llevar <> 0 Then resultado = Mid(t,llevar+2,1) + resultado
 
i = 0
While Mid(resultado,i+1,1) = "0"
i += 1
Wend
resultado = Mid(resultado,i+1)
If resultado = "" Then resultado = "0"
Return resultado
End Function
 
Function subTernary(cadenaA As String, cadenaB As String) As String
Return addTernary(cadenaA, negate(cadenaB))
End Function
 
Function multTernary(cadenaA As String, cadenaB As String) As String
Dim As String resultado = ""
Dim As String tS = "", cambio = ""
For i As Integer = Len(cadenaA) To 1 Step -1
Select Case Mid(cadenaA,i,1)
Case "+": tS = cadenaB
Case "0": tS = "0"
Case "-": tS = negate(cadenaB)
End Select
resultado = addTernary(resultado, tS + cambio)
cambio += "0"
Next i
Return resultado
End Function
 
 
Dim As String cadenaA = "+-0++0+"
Dim As Integer a = deci(cadenaA)
Print " a:", a, cadenaA
 
Dim As Integer b = -436
Dim As String cadenaB = ternary(b)
Print " b:", b, cadenaB
 
Dim As String cadenaC = "+-++-"
Dim As Integer c = deci(cadenaC)
Print " c:", c, cadenaC
 
'calcular en ternario
Dim As String resS = multTernary(cadenaA, subTernary(cadenaB, cadenaC))
Print "a*(b-c):", deci(resS), resS
 
Print !"\nComprobamos:"
Print "a*(b-c): ", a * (b - c)
Sleep
</syntaxhighlight>
{{out}}
<pre>
a: 523 +-0++0+
b: -436 -++-0--
c: 65 +-++-
a*(b-c): -262023 ----0+--0++0
Comprobamos:
a*(b-c): -262023
</pre>
 
=={{header|Glagol}}==
Line 1,565 ⟶ 2,384:
</pre>
'''A crude English/Pidgin Algol translation of the above [[:Category:Glagol]] code.'''
<langsyntaxhighlight lang="algol68">PROGRAM Setun+;
USES
Parameter IS "...\Departments\Exchange\"
Line 1,677 ⟶ 2,496:
Output.ChTarget(" = %d.", InNumber(), 0, 0, 0);
Remove.Memory
END Setun.</langsyntaxhighlight>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,903 ⟶ 2,722:
fmt.Println("int overflow")
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,914 ⟶ 2,733:
=={{header|Groovy}}==
Solution:
<langsyntaxhighlight lang="groovy">enum T {
m('-', -1), z('0', 0), p('+', 1)
 
Line 2,073 ⟶ 2,892:
 
String toString() { value }
}</langsyntaxhighlight>
 
Test:
<langsyntaxhighlight lang="groovy">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)
Line 2,091 ⟶ 2,910:
 
println "\nDemonstrate failure:"
assert (a * (b-c)) == a</langsyntaxhighlight>
 
Output:
Line 2,116 ⟶ 2,935:
=={{header|Haskell}}==
BTs are represented internally as lists of digits in integers from -1 to 1, but displayed as "+-0" strings.
<langsyntaxhighlight lang="haskell">data BalancedTernary = Bt [Int]
 
zeroTrim a = if null s then [0] else s where
Line 2,173 ⟶ 2,992:
print $ map btInt [a,b,c]
print $ r
print $ btInt r</langsyntaxhighlight>
 
=={{header|Icon}} and {{header|Unicon}}==
Line 2,180 ⟶ 2,999:
 
Works in both languages:
<langsyntaxhighlight lang="unicon">procedure main()
a := "+-0++0+"
write("a = +-0++0+"," = ",cvtFromBT("+-0++0+"))
Line 2,269 ⟶ 3,088:
}
return (\negate,map(mul,"+-","-+")) | mul
end</langsyntaxhighlight>
 
Output:
Line 2,285 ⟶ 3,104:
Implementation:
 
<langsyntaxhighlight lang="j">trigits=: 1+3 <.@^. 2 * 1&>.@|
trinOfN=: |.@((_1 + ] #: #.&1@] + [) #&3@trigits) :. nOfTrin
nOfTrin=: p.&3 :. trinOfN
Line 2,296 ⟶ 3,115:
add=: carry@(+/@,:)
neg=: -
mul=: trimLead0@carry@(+//.@(*/))</langsyntaxhighlight>
 
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).
Line 2,308 ⟶ 3,127:
<code>trimLead0</code> removes leading zeros from a sequence of polynomial coefficients.
 
<code>add</code> adds these polynomials.<br />
<code>neg</code> negates these polynomials. Note that it's just a name for J's <code>-</code>.<br />
<code>mul</code> multiplies these polynomials.<br />
 
Definitions for example:
 
<langsyntaxhighlight lang="j">a=: trinOfStr '+-0++0+'
b=: trinOfN -436
c=: trinOfStr '+-++-'</langsyntaxhighlight>
 
Required example:
 
<langsyntaxhighlight lang="j"> nOfTrin&> a;b;c
523 _436 65
 
Line 2,326 ⟶ 3,145:
----0+--0++0
nOfTrin a mul b (add -) c
_262023</langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">
/*
* Test case
Line 2,541 ⟶ 3,360:
}
}
</syntaxhighlight>
</lang>
 
Output:
Line 2,550 ⟶ 3,369:
 
result= ----0+--0++0 -262023
</pre>
 
=={{header|jq}}==
{{Works with|jq}}
 
'''Works with gojq, the Go implementation of jq'''
 
'''Adapted from [[#Wren|Wren]]'''
<syntaxhighlight lang="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 "-"
def addDigits2($a; $b):
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;
def addDigits3($a; $b; $carry):
addDigits2($a; $b) as $sum1
| addDigits2($sum1[-1:]; $carry) as $sum2
| 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)"
</syntaxhighlight>
{{output}}
<pre>
a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 ~ -262023 => ----0+--0++0
</pre>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{trans|Python}}
 
<syntaxhighlight lang="julia">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)]
function _add(a::Vector{Int8}, b::Vector{Int8}, c::Int8=Int8(0))
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]
r = _add(a[2:end], b[2:end], c)
if !isempty(r) || d != 0
return unshift!(r, d)
else
return r
end
end
end
function Base.:+(a::BalancedTernary, b::BalancedTernary)
v = _add(a.digits, b.digits)
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))
return _add(x, y)
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))</syntaxhighlight>
 
{{out}}
<pre>a: 523, +-0++0+
b: -436, -++-0--
c: 65, +-++-
a * (b - c): -262023, ----0+--0++0</pre>
 
=={{header|Koka}}==
Based on the OCaml version
<syntaxhighlight lang="koka">
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 )
</syntaxhighlight>
 
{{out}}
<pre>
a = 523
b = -++-0--
c = 65
a * (b - c) = ----0+--0++0 = -262023
</pre>
=={{header|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:
<syntaxhighlight lang="scala">// 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 {
val sum1 = addDigits(a, b)
val sum2 = addDigits(sum1.last(), carry)
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")
}</syntaxhighlight>
 
{{out}}
<pre>
a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 = -262023
</pre>
 
=={{header|Liberty BASIC}}==
<syntaxhighlight lang="lb">
<lang lb>
global tt$
tt$="-0+" '-1 0 1; +2 -> 1 2 3, instr
Line 2,691 ⟶ 4,012:
wend
end function
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,703 ⟶ 4,024:
a * (b - c) -262023
</pre>
 
=={{header|Lua}}==
{{trans|C}}
<syntaxhighlight lang="lua">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
 
function add(b1,b2)
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
 
local ob1 = add(c1,d:sub(2,2))
local ob2 = add(ob1,c2)
 
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)
return add(b1, unary_minus(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
r = add(r, c1)
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()</syntaxhighlight>
{{out}}
<pre> a: +-0++0+ 523
b: -++-0-- -436
c: +-++- 65
a*(b-c): ----0+--0++0 -262023</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<langsyntaxhighlight lang="mathematica">frombt = FromDigits[StringCases[#, {"+" -> 1, "-" -> -1, "0" -> 0}],
3] &;
tobt = If[Quotient[#, 3, -1] == 0,
Line 2,726 ⟶ 4,201:
btnegate@#1],
If[StringLength@#2 == 1,
"0", #0[#1, StringDrop[#2, -1]] <> "0"]] &;</langsyntaxhighlight>
Examples:
<langsyntaxhighlight lang="mathematica">frombt[a = "+-0++0+"]
b = tobt@-436
frombt[c = "+-++-"]
btmultiply[a, btsubtract[b, c]]</langsyntaxhighlight>
Outputs:
<pre>523
Line 2,743 ⟶ 4,218:
=={{header|МК-61/52}}==
{{trans|Glagol}}
<syntaxhighlight lang="mk-61">П0 ЗН П2 Вx |x| П0 0 П3 П4 1 П5
ИП0 /-/ x<0 7880
ИП0 ^ ^ 3 / [x] П0 3 * - П1
ИП3 x#0 5254
ИП1 x=0 3638 1ИП2 ПП 8688 0 П3 БП 0810
ИП1 1 - x=0 4749 1ИП2 /-/ ПП 8688 БП 0810
0 ПП 8688 БП 0810
ИП1 x=0 6062 0 ПП 8688 БП 0810
ИП1 1 - x=0 7072 1ИП2 ПП 8688 БП 0810
1 ИП2 /-/ ПП 8688 1 П3 БП 0810
ИП3 x#0 8586 1ИП2 ПП 8688 ИП4 С/П
8 + ИП5 * ИП4 + П4 ИП5 1 0 * П5 В/О</syntaxhighlight>
ИП2 x<0 91 <-> /-/ <-> 8 +
ИП5 * ИП4 + П4 ИП5 1 0 * П5 В/О</lang>
 
''Note: the "-", "0", "+" denotes by digits, respectively, the "7", "8", "9".''
 
=={{header|Nim}}==
<syntaxhighlight lang="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 =
## Add two BTernary numbers.
 
# 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
result.add(s[0])
 
# Append the carry to the result if it is not null.
if carry != TZ:
result.add(carry)
 
#---------------------------------------------------------------------------------------------------
 
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 TZ: discard
of TN: result += start & na
start.add(TZ) # Shift next row.
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]
result.add(trit)
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}"</syntaxhighlight>
 
{{out}}
<pre>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</pre>
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="ocaml">type btdigit = Pos | Zero | Neg
type btern = btdigit list
 
Line 2,811 ⟶ 4,479:
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);</langsyntaxhighlight>
Output:
<pre>a = 523
Line 2,819 ⟶ 4,487:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
use warnings;
 
Line 2,893 ⟶ 4,561:
printf " c: %14s %10d\n", $c, from_bt( $c );
printf "a*(b-c): %14s %10d\n", $d, from_bt( $d );
</syntaxhighlight>
</lang>
{{out}}
<pre> a: +-0++0+ 523
Line 2,900 ⟶ 4,568:
a*(b-c): ----0+--0++0 -262023
</pre>
=={{header|Perl 6}}==
{{Works with|rakudo|2016-11}}
<lang perl6>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;</lang>
{{out}}
<pre>a == 523
b == -436
c == 65
a × (b − c) == ----0+--0++0 == -262023</pre>
 
=={{header|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.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function bt2dec(string bt)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
integer res = 0
<span style="color: #008080;">function</span> <span style="color: #000000;">bt2dec</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">bt</span><span style="color: #0000FF;">)</span>
for i=1 to length(bt) do
<span style="color: #004080;">integer</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
res = 3*res+(bt[i]='+')-(bt[i]='-')
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bt</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">*</span><span style="color: #000000;">res</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">bt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'+'</span><span style="color: #0000FF;">)-(</span><span style="color: #000000;">bt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">)</span>
return res
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function negate(string bt)
for i=1 to length(bt) do
<span style="color: #008080;">function</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">bt</span><span style="color: #0000FF;">)</span>
if bt[i]!='0' then
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bt</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
bt[i] = '+'+'-'-bt[i]
<span style="color: #008080;">if</span> <span style="color: #000000;">bt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">bt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'+'</span><span style="color: #0000FF;">+</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">-</span><span style="color: #000000;">bt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return bt
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">bt</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function dec2bt(integer n)
string res = "0"
<span style="color: #008080;">function</span> <span style="color: #000000;">dec2bt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
integer neg, r
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0"</span>
if n!=0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
neg = n<0
<span style="color: #004080;">integer</span> <span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span>
if neg then n = -n end if
<span style="color: #008080;">if</span> <span style="color: #000000;">neg</span> <span style="color: #008080;">then</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">n</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
res = ""
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
while n!=0 do
<span style="color: #008080;">while</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span>
r = mod(n,3)
<span style="color: #004080;">integer</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
res = "0+-"[r+1]&res
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0+-"</span><span style="color: #0000FF;">[</span><span style="color: #000000;">r</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">res</span>
n = floor((n+(r=2))/3)
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
if neg then res = negate(res) end if
<span style="color: #008080;">if</span> <span style="color: #000000;">neg</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return res
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
-- res,carry for a+b+carry lookup tables (not the fastest way to do it, I'm sure):
<span style="color: #000080;font-style:italic;">-- res,carry for a+b+carry lookup tables (not the fastest way to do it, I'm sure):</span>
constant {tadd,addres} = columnize({{"---","0-"},{"--0","+-"},{"--+","-0"},
<span style="color: #008080;">constant</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">tadd</span><span style="color: #0000FF;">,</span><span style="color: #000000;">addres</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">({{</span><span style="color: #008000;">"---"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"0-"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"--0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+-"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"--+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},</span>
{"-0-","+-"},{"-00","-0"},{"-0+","00"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"-0-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+-"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"-00"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"-0+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},</span>
{"-+-","-0"},{"-+0","00"},{"-++","+0"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"-+-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"-+0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"-++"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},</span>
{"0--","+-"},{"0-0","-0"},{"0-+","00"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0--"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+-"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"0-0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"0-+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},</span>
{"00-","-0"},{"000","00"},{"00+","+0"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"00-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"000"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"00+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},</span>
{"0+-","00"},{"0+0","+0"},{"0++","-+"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0+-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"0+0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"0++"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-+"</span><span style="color: #0000FF;">},</span>
{"+--","-0"},{"+-0","00"},{"+-+","+0"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"+--"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"+-0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"+-+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},</span>
{"+0-","00"},{"+00","+0"},{"+0+","-+"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"+0-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"00"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"+00"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"+0+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-+"</span><span style="color: #0000FF;">},</span>
{"++-","+0"},{"++0","-+"},{"+++","0+"}})
<span style="color: #0000FF;">{</span><span style="color: #008000;">"++-"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+0"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"++0"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-+"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"+++"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"0+"</span><span style="color: #0000FF;">}})</span>
 
 
function bt_add(string a, string b)
<span style="color: #008080;">function</span> <span style="color: #000000;">bt_add</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
integer pad = length(a)-length(b)
<span style="color: #004080;">integer</span> <span style="color: #000000;">padding</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">),</span>
integer carry = '0'
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ch</span>
if pad!=0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">padding</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
if pad<0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">padding</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
a = repeat('0',-pad)&a
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">padding</span><span style="color: #0000FF;">)&</span><span style="color: #000000;">a</span>
else
<span b style="color: repeat('0',pad)&b#008080;">else</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">padding</span><span style="color: #0000FF;">)&</span><span style="color: #000000;">b</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
for i=length(a) to 1 by -1 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
{a[i],carry} = addres[find(a[i]&b[i]&carry,tadd)]
<span style="color: #004080;">string</span> <span style="color: #000000;">cc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">addres</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tadd</span><span style="color: #0000FF;">)]</span>
end for
<span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
if carry!='0' then
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
a = carry&a
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
else
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">then</span>
while length(a)>1 and a[1]='0' do
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">carry</span><span style="color: #0000FF;">&</span><span style="color: #000000;">a</span>
a = a[2..$]
<span style="color: #008080;">else</span>
end while
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">do</span>
end if
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
return a
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
 
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span>
function bt_mul(string a, string b)
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
string pos = a, neg = negate(a), res = "0"
integer ch
<span style="color: #008080;">function</span> <span style="color: #000000;">bt_mul</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
for i=length(b) to 1 by -1 do
<span style="color: #004080;">string</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0"</span>
ch = b[i]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
if ch='+' then
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
res = bt_add(res,pos)
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'+'</span> <span style="color: #008080;">then</span>
elsif ch='-' then
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">)</span>
res = bt_add(res,neg)
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">neg</span><span style="color: #0000FF;">)</span>
pos = pos&'0'
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
neg = neg&'0'
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos</span><span style="color: #0000FF;">&</span><span style="color: #008000;">'0'</span>
end for
<span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">neg</span><span style="color: #0000FF;">&</span><span style="color: #008000;">'0'</span>
return res
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
string a = "+-0++0+", b = dec2bt(-436), c = "+-++-"
 
<span style="color: #004080;">string</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"+-0++0+"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec2bt</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">436</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"+-++-"</span><span style="color: #0000FF;">,</span>
?{bt2dec(a),bt2dec(b),bt2dec(c)}
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bt_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)))</span>
 
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%7s: %12s %9d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"a"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bt2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)})</span>
string res = bt_mul(a,bt_add(b,negate(c)))
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%7s: %12s %9d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"b"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bt2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)})</span>
?{res,bt2dec(res)}</lang>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%7s: %12s %9d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"c"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bt2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%7s: %12s %9d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"a*(b-c)"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bt2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
a: +-0++0+ 523
{523,-436,65}
b: -++-0-- -436
{"----0+--0++0",-262023}
c: +-++- 65
a*(b-c): ----0+--0++0 -262023
</pre>
Proof of arbitrary large value support is provided by calculating 1000! and 999! and using a naive subtraction loop to effect division.
Line 3,074 ⟶ 4,677:
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!
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>atom t0 = time()
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
string f999 = dec2bt(1)
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
for i=2 to 999 do
<span style="color: #004080;">string</span> <span style="color: #000000;">f999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec2bt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
f999 = bt_mul(f999,dec2bt(i))
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">999</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">f999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f999</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dec2bt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">))</span>
string f1000 = bt_mul(f999,dec2bt(1000))
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
 
<span style="color: #004080;">string</span> <span style="color: #000000;">f1000</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f999</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dec2bt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">))</span>
printf(1,"In balanced ternary, f999 has %d digits and f1000 has %d digits\n",{length(f999),length(f1000)})
 
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"In balanced ternary, f999 has %d digits and f1000 has %d digits\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f999</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f1000</span><span style="color: #0000FF;">)})</span>
integer count = 0
f999 = negate(f999)
<span style="color: #004080;">integer</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
while f1000!="0" do
<span style="color: #000000;">f999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f999</span><span style="color: #0000FF;">)</span>
f1000 = bt_add(f1000,f999)
<span style="color: #008080;">while</span> <span style="color: #000000;">f1000</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">"0"</span> <span style="color: #008080;">do</span>
count += 1
<span style="color: #000000;">f1000</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bt_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f999</span><span style="color: #0000FF;">)</span>
end while
<span style="color: #000000;">count</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
printf(1,"It took %d subtractions to reach 0. (%3.2fs)\n",{count,time()-t0})</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"It took %d subtractions to reach 0. (%3.2fs)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">count</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 3,097 ⟶ 4,703:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(seed (in "/dev/urandom" (rd 8)))
 
(setq *G '((0 -1) (1 -1) (-1 0) (0 0) (1 0) (-1 1) (0 1)))
Line 3,218 ⟶ 4,824:
(println 'R (trih R) R) )
 
(bye)</langsyntaxhighlight>
 
=={{header|Prolog}}==
Line 3,225 ⟶ 4,831:
'''The conversion.'''<br>
Library '''clpfd''' is used so that '''bt_convert''' works in both ways Decimal => Ternary and Ternary ==> Decimal.
<langsyntaxhighlight Prologlang="prolog">:- module('bt_convert.pl', [bt_convert/2,
op(950, xfx, btconv),
btconv/2]).
Line 3,292 ⟶ 4,898:
R1 #= R - 3 * C1, % C1 #= 1,
convert(N1, C1, [R1 | LC], LF).
</langsyntaxhighlight><br>
'''The addition.''' <br>
The same predicate is used for addition and substraction.
<langsyntaxhighlight Prologlang="prolog">:- module('bt_add.pl', [bt_add/3,
bt_add1/3,
op(900, xfx, btplus),
Line 3,418 ⟶ 5,024:
strip_nombre(L) -->
L.
</syntaxhighlight>
</lang>
'''The multiplication.''' <br>
We give a predicate '''euclide(?A, +B, ?Q, ?R)''' which computes both the multiplication and the division, but it is very inefficient.<br>
The predicates '''multiplication(+B, +Q, -A)''' and '''division(+A, +B, -Q, -R)''' are much more efficient.
<langsyntaxhighlight Prologlang="prolog">:- module('bt_mult.pl', [op(850, xfx, btmult),
btmult/2,
multiplication/3
Line 3,593 ⟶ 5,199:
; mult_(B, Q1, A1, R, Resultat, Ajout)) .
 
</syntaxhighlight>
</lang>
Example of output :
<pre> ?- A btconv "+-0++0+".
Line 3,609 ⟶ 5,215:
Z = -262023 .
</pre>
 
=={{header|Python}}==
{{trans|CommonLispCommon Lisp}}
<langsyntaxhighlight lang="python">class BalancedTernary:
# Represented as a list of 0, 1 or -1s, with least significant digit first.
 
Line 3,705 ⟶ 5,312:
print "a * (b - c):", r.to_int(), r
 
main()</langsyntaxhighlight>
{{out}}
<pre>a: 523 +-0++0+
Line 3,713 ⟶ 5,320:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
 
;; Represent a balanced-ternary number as a list of 0's, 1's and -1's.
Line 3,788 ⟶ 5,395:
[description (list 'a 'b 'c "a×(b−c)")])
(printf "~a = ~a or ~a\n" description (bt->integer bt) (bt->string bt))))
</syntaxhighlight>
</lang>
 
{{output}}
Line 3,797 ⟶ 5,404:
a×(b−c) = -262023 or ----0+--0++0
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2017.01}}
<syntaxhighlight lang="raku" line>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;</syntaxhighlight>
{{out}}
<pre>a == 523
b == -436
c == 65
a × (b − c) == ----0+--0++0 == -262023</pre>
 
=={{header|REXX}}==
The REXX program could be optimized by using &nbsp; (procedure) with &nbsp; '''expose''' &nbsp; and having the &nbsp; <big>'''$.'''</big> &nbsp; and &nbsp; <big>'''@.'''</big> &nbsp; variables set only once.
<langsyntaxhighlight lang="rexx">/*REXX pgmprogram 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
x=x/1
do if until x_==0; 2 then _=(x//(3**(p+ -1)))%3**p
else if _== -2 then _= -1
if _=x= -2x then- _ * (3**p); p= p + 1; #= $._ || #
end x=x-_/*(3until**p)/; p=p+1; #=$._ || return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
end /*until ···*/
bt2d: procedure; parse arg x; r= reverse(x); $.= -1; $.0= 0; #= 0; _= '+'; $._= 1
return #
do j=1 for length(x); _= substr(r, j, 1); #= # + $._ * 3 ** (j-1)
/*────────────────────────────────────────────────────────────────────────────*/
end /*j*/; return #
bt2d: procedure; parse arg x; r=reverse(x); #=0; $.=-1; $.0=0; _='+'; $._=1
/*──────────────────────────────────────────────────────────────────────────────────────*/
do j=1 for length(x); _=substr(r,j,1); #=#+$._*3**(j-1); end
btAdd: procedure; parse arg x,y; rx= reverse(x); ry= reverse(y); carry= 0
return #
@.= 0; _= '-'; @._= -1; _= "+"; @._= 1; $.= '-'; $.0= 0; $.1= "+"; #=
/*────────────────────────────────────────────────────────────────────────────*/
do j=1 for max( length(x), length(y) )
btAdd: procedure; parse arg x,y; rx=reverse(x); ry=reverse(y); carry=0
@.=0 ; _='-'; @._ x_=- substr(rx, j, 1); _="+"; xn= @._=1x_
y_= substr(ry, j, 1); yn= @.y_
$.='-'; $.0=0; $.1='+'
#=; do j s=1 xn for+ yn + carry; carry= max(length(x),length(y))0
x_ if s=substr(rx,j,1)= 2 then do; s=-1; carry= 1; xn=@.x_end
y_ if s==substr(ry,j,1); 3 then do; s= 0; yncarry=@.y_ 1; end
if s=xn+yn+carry =-2 then do; s= 1; carry=-1; 0end
if s== 2 then do; s#=-1; carry= 1; $.s || end#
if s== 3 then do; s=end 0; carry= 1; end/*j*/
if carry\==0 then #= $.carry || #; if s==-2 then do; s= 1; carry=-1; return endbtNorm(#)
/*──────────────────────────────────────────────────────────────────────────────────────*/
#=$.s || #
btMul: procedure; parse arg x 1 x1 2, y 1 y1 2; if x==0 | y==0 then return 0; S= 1; end /*j*/P=0
x= btNorm(x); y= btNorm(y); Lx= length(x); Ly= length(y) /*handle: 0-xxx values.*/
if carry\==0 then #=$.carry||#; return btNorm(#)
if x1=='-' then do; x= btNeg(x); S= -S; end /*positate the number. */
/*────────────────────────────────────────────────────────────────────────────*/
if y1=='-' then do; y= btNeg(y); S= -S; end /* " " " */
btMul: procedure; parse arg x 1 x1 2, y 1 y1 2; if x==0 | y==0 then return 0
S=1; if Ly>Lx then parse value x=btNorm(x); y with y=btNorm(y) x /*handle:optimize " " 0-xxx values.*/
if x1=='-' then do; x=btNeg(x); S=-S; end do until y==0 /*positate.keep adding 'til done*/
if y1=='-' then do; y=btNeg(y); S=-S; end /* " P= btAdd(P, x ) /*multiple the hard way*/
if length(y)>length(x) then parse value x y with y x y= btSub(y, '+') /*optimizesubtract 1 from Y.*/
end /*until*/
P=0
if S==-1 then P= btNeg(P); return P do until y==0 /*keepadjust addingthe product'tils sign; donereturn.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
P=btAdd(P,x) /*multiple the hard way*/
btNeg: return translate( arg(1), '-+', "+-") y=btSub(y,'+') /*subtract 1 fromnegate bal_ternary Y#.*/
btNorm: _= strip(arg(1), 'L', 0); if _=='' then _=0; return _ /*normalize the number.*/
end /*until*/
ifbtSub: S==-1 return thenbtAdd( P=btNegarg(P1), btNeg( arg(2) ) ) /*adjustsubtract producttwo sign.BT args.*/
btShow: say center( arg(1), 9) right( arg(2), 20) @@ right( bt2d(arg(2)), 9) @; return</syntaxhighlight>
return P /*return the product P.*/
{{out|output|text=&nbsp; when using the default input:}}
/*────────────────────────────────────────────────────────────────────────────*/
btNeg: return translate(arg(1), '-+', "+-") /*negate the bal_tern #*/
btNorm: _=strip(arg(1),'L',0); if _=='' then _=0; return _ /*normalize a #*/
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</lang>
'''output''' &nbsp; when using the default inputs:
<pre>
[a] +-0++0+ balanced ternary = 523 (decimal)
Line 3,863 ⟶ 5,537:
 
[a*(b-c)] ----0+--0++0 balanced ternary = -262023 (decimal)
</pre>
 
=={{header|RPL}}==
{{trans|Nim}}
{{works with|RPL|HP-48}}
« "-0+" SWAP POS 2 -
» '<span style="color:blue">CH→TR</span>' STO
« "-0+" SWAP 2 + DUP SUB
» '<span style="color:blue">TR→CH</span>' STO
« '''WHILE''' DUP SIZE OVER HEAD "0" == AND '''REPEAT''' TAIL '''END'''
» '<span style="color:blue">NOZEROS</span>' STO
« DUP SIZE → bt len
« 0
1 len '''FOR''' j
bt j DUP SUB <span style="color:blue">CH→TR</span>
3 len j - ^ * +
'''NEXT'''
» » '<span style="color:blue">BT→I</span>' STO
« DUP "" "0" IFTE
'''WHILE''' OVER '''REPEAT'''
OVER 3 MOD
1 ≤ LASTARG NEG IFTE <span style="color:grey>''@ convert 2 into -1''</span>
DUP <span style="color:blue">TR→CH</span> ROT - 3 / IP SWAP
'''END'''
SWAP DROP
» '<span style="color:blue">I→BT</span>' 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 <span style="color:blue">CH→TR</span> + b j DUP SUB <span style="color:blue">CH→TR</span> +
'''IF''' DUP ABS 2 ≥ '''THEN'''
DUP 3 MOD 1 ≤ LASTARG NEG IFTE
SWAP SIGN
'''ELSE''' 0 '''END'''
SWAP <span style="color:blue">TR→CH</span> ROT + SWAP
-1 '''STEP'''
'''IF THEN''' LASTARG <span style="color:blue">TR→CH</span> SWAP + '''END'''
<span style="color:blue">NOZEROS</span>
» » '<span style="color:blue">ADDBT</span>' STO
« ""
1 3 PICK SIZE '''FOR''' j
OVER j DUP SUB
<span style="color:blue">CH→TR</span> NEG <span style="color:blue">TR→CH</span> +
'''NEXT'''
SWAP DROP
» '<span style="color:blue">NEGBT</span>' STO
« "" → a b shift
« "0"
a SIZE 1 '''FOR''' j
a j DUP SUB
'''IF''' DUP "0" ≠ '''THEN'''
b
'''IF''' SWAP "-" == '''THEN''' <span style="color:blue">NEGBT</span> '''END'''
'''END'''
shift + <span style="color:blue">ADDBT</span>
'shift' "0" STO+
-1 '''STEP'''
<span style="color:blue">NOZEROS</span>
» » '<span style="color:blue">MULBT</span>' STO
« "+-0++0+" -436 <span style="color:blue">I→BT</span> "+-++-" → a b c
« a <span style="color:blue">BT→I</span> b <span style="color:blue">BT→I</span> c <span style="color:blue">BT→I</span> 3 →LIST
a b c <span style="color:blue">NEGBT ADDBT MULBT</span>
» » '<span style="color:blue">TASK</span>' STO
{{out}}
<pre>
3: { 523 -436 65 }
2: "----0+--0++0"
1: -262023
</pre>
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">class BalancedTernary
include Comparable
def initialize(str = "")
Line 3,988 ⟶ 5,740:
val = eval(exp)
puts "%8s :%13s,%8d" % [exp, val, val.to_i]
end</langsyntaxhighlight>
 
{{out}}
Line 3,996 ⟶ 5,748:
c : +-++-, 65
a*(b-c) : ----0+--0++0, -262023
</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">use std::{
cmp::min,
convert::{TryFrom, TryInto},
fmt,
ops::{Add, Mul, Neg},
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 => '-',
}
}
}
 
impl Add for Trit {
// (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>()
)
}
}
 
impl Add for BalancedTernary {
type Output = Self;
 
fn add(self, rhs: Self) -> Self::Output {
use Trit::Zero;
 
// Trim leading zeroes
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)
.and_then(|x| acc.checked_add(x))
.ok_or(size_err),
Trit::Neg => 3_i128
.checked_pow(index)
.and_then(|x| acc.checked_sub(x))
.ok_or(size_err),
}
})
}
}
</syntaxhighlight>
 
Output
<pre>
a = +-0++0+ = 523
b = -++-0-- = -436
c = +-++- = 65
a * (b - c) = ----0+--0++0 = -262023
</pre>
 
=={{header|Scala}}==
This implementation represents ternaries as a reversed list of bits. Also, there are plenty of implicit convertors
<langsyntaxhighlight lang="scala">
object TernaryBit {
val P = TernaryBit(+1)
Line 4,087 ⟶ 6,107:
implicit def intToTernary(i: Int): Ternary = valueOf(i)
}
</syntaxhighlight>
</scala>
 
Then these classes can be used in the following way:
<langsyntaxhighlight lang="scala">
object Main {
 
Line 4,105 ⟶ 6,125:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 4,115 ⟶ 6,135:
 
Besides, we can easily check, that the code works for any input. This can be achieved with ScalaCheck:
<langsyntaxhighlight lang="scala">
object TernarySpecification extends Properties("Ternary") {
 
Line 4,131 ⟶ 6,151:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 4,138 ⟶ 6,158:
+ Ternary.multiply: OK, passed 100 tests.
</pre>
 
=={{header|Tcl}}==
This directly uses the printable representation of the balanced ternary numbers, as Tcl's string operations are reasonably efficient.
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
proc bt-int b {
Line 4,196 ⟶ 6,217:
- { return [bt-sub $sub $b] }
}
}</langsyntaxhighlight>
Demonstration code:
<langsyntaxhighlight lang="tcl">for {set i 0} {$i<=10} {incr i} {puts "$i = [int-bt $i]"}
puts "'+-+'+'+--' = [bt-add +-+ +--] = [bt-int [bt-add +-+ +--]]"
puts "'++'*'++' = [bt-mul ++ ++] = [bt-int [bt-mul ++ ++]]"
Line 4,207 ⟶ 6,228:
puts "a = [bt-int $a], b = [bt-int $b], c = [bt-int $c]"
set abc [bt-mul $a [bt-sub $b $c]]
puts "a*(b-c) = $abc (== [bt-int $abc])"</langsyntaxhighlight>
Output:
<pre>
Line 4,225 ⟶ 6,246:
a = 523, b = -436, c = 65
a*(b-c) = ----0+--0++0 (== -262023)
</pre>
 
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Imports System.Text
 
Module Module1
Sub Main()
Dim a As New BalancedTernary("+-0++0+")
Console.WriteLine("a: {0} = {1}", a, a.ToLong)
Dim b As New BalancedTernary(-436)
Console.WriteLine("b: {0} = {1}", b, b.ToLong)
Dim c As New BalancedTernary("+-++-")
Console.WriteLine("c: {0} = {1}", c, c.ToLong)
Dim d = a * (b - c)
Console.WriteLine("a * (b - c): {0} = {1}", d, d.ToLong)
End Sub
 
Class BalancedTernary
Private Enum BalancedTernaryDigit
MINUS = -1
ZERO = 0
PLUS = 1
End Enum
 
Private ReadOnly value() As BalancedTernaryDigit
 
' empty = 0
Public Sub New()
ReDim value(-1)
End Sub
 
' create from string
Public Sub New(str As String)
ReDim value(str.Length - 1)
For i = 1 To str.Length
If str(i - 1) = "-" Then
value(i - 1) = BalancedTernaryDigit.MINUS
ElseIf str(i - 1) = "0" Then
value(i - 1) = BalancedTernaryDigit.ZERO
ElseIf str(i - 1) = "+" Then
value(i - 1) = BalancedTernaryDigit.PLUS
Else
Throw New ArgumentException("Unknown Digit: " + str(i - 1))
End If
Next
Array.Reverse(value)
End Sub
 
' convert integer
Public Sub New(l As Long)
Dim value As New List(Of BalancedTernaryDigit)
Dim sign = Math.Sign(l)
l = Math.Abs(l)
 
While l <> 0
Dim remainder = CType(l Mod 3, Byte)
If remainder = 0 OrElse remainder = 1 Then
value.Add(remainder)
l /= 3
ElseIf remainder = 2 Then
value.Add(BalancedTernaryDigit.MINUS)
l = (l + 1) / 3
End If
End While
 
Me.value = value.ToArray
If sign < 0 Then
Invert()
End If
End Sub
 
' copy constructor
Public Sub New(origin As BalancedTernary)
ReDim value(origin.value.Length - 1)
Array.Copy(origin.value, value, origin.value.Length)
End Sub
 
' only for internal use
Private Sub New(value() As BalancedTernaryDigit)
Dim endi = value.Length - 1
While endi > 0 AndAlso value(endi) = BalancedTernaryDigit.ZERO
endi -= 1
End While
ReDim Me.value(endi)
Array.Copy(value, Me.value, endi + 1)
End Sub
 
' invert the values
Private Sub Invert()
For i = 1 To value.Length
value(i - 1) = CType(-CType(value(i - 1), Integer), BalancedTernaryDigit)
Next
End Sub
 
' convert to string
Public Overrides Function ToString() As String
Dim result As New StringBuilder
Dim i = value.Length - 1
While i >= 0
If value(i) = BalancedTernaryDigit.MINUS Then
result.Append("-")
ElseIf value(i) = BalancedTernaryDigit.ZERO Then
result.Append("0")
ElseIf value(i) = BalancedTernaryDigit.PLUS Then
result.Append("+")
End If
 
i -= 1
End While
Return result.ToString
End Function
 
' convert to long
Public Function ToLong() As Long
Dim result = 0L
For i = 1 To value.Length
result += value(i - 1) * Math.Pow(3.0, i - 1)
Next
Return result
End Function
 
' unary minus
Public Shared Operator -(origin As BalancedTernary) As BalancedTernary
Dim result As New BalancedTernary(origin)
result.Invert()
Return result
End Operator
 
' addition of digits
Private Shared carry = BalancedTernaryDigit.ZERO
Private Shared Function Add(a As BalancedTernaryDigit, b As BalancedTernaryDigit) As BalancedTernaryDigit
If a <> b Then
carry = BalancedTernaryDigit.ZERO
Return a + b
Else
carry = a
Return -CType(b, Integer)
End If
End Function
 
' addition of balanced ternary numbers
Public Shared Operator +(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
Dim maxLength = Math.Max(a.value.Length, b.value.Length)
Dim resultValue(maxLength) As BalancedTernaryDigit
For i = 1 To maxLength
If i - 1 < a.value.Length Then
resultValue(i - 1) = Add(resultValue(i - 1), a.value(i - 1))
resultValue(i) = carry
Else
carry = BalancedTernaryDigit.ZERO
End If
 
If i - 1 < b.value.Length Then
resultValue(i - 1) = Add(resultValue(i - 1), b.value(i - 1))
resultValue(i) = Add(resultValue(i), carry)
End If
Next
Return New BalancedTernary(resultValue)
End Operator
 
' subtraction of balanced ternary numbers
Public Shared Operator -(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
Return a + (-b)
End Operator
 
' multiplication of balanced ternary numbers
Public Shared Operator *(a As BalancedTernary, b As BalancedTernary) As BalancedTernary
Dim longValue = a.value
Dim shortValue = b.value
Dim result As New BalancedTernary
 
If a.value.Length < b.value.Length Then
longValue = b.value
shortValue = a.value
End If
 
For i = 1 To shortValue.Length
If shortValue(i - 1) <> BalancedTernaryDigit.ZERO Then
Dim temp(i + longValue.Length - 2) As BalancedTernaryDigit
For j = 1 To longValue.Length
temp(i + j - 2) = CType(shortValue(i - 1) * longValue(j - 1), BalancedTernaryDigit)
Next
result += New BalancedTernary(temp)
End If
Next
 
Return result
End Operator
End Class
 
End Module</syntaxhighlight>
{{out}}
<pre>a: +-0++0+ = 523
b: -++-0-- = -436
c: +-++- = 65
a * (b - c): ----0+--0++0 = -262023</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-big}}
{{libheader|Wren-trait}}
<syntaxhighlight lang="wren">import "./big" for BigInt
import "./trait" for Comparable
 
class BTernary is Comparable {
toBT_(v) {
if (v < BigInt.zero) return flip_(toBT_(-v))
if (v == BigInt.zero) return ""
var rem = mod3_(v)
return (rem == BigInt.zero) ? toBT_(v/BigInt.three) + "0" :
(rem == BigInt.one) ? toBT_(v/BigInt.three) + "+" :
toBT_((v + BigInt.one)/BigInt.three) + "-"
}
 
flip_(s) {
var sb = ""
for (c in s) {
sb = sb + ((c == "+") ? "-" : (c == "-") ? "+" : "0")
}
return sb
}
 
mod3_(v) {
if (v > BigInt.zero) return v % BigInt.three
return ((v % BigInt.three) + BigInt.three) % BigInt.three
}
 
addDigits2_(a, b) {
return (a == "0") ? b :
(b == "0") ? a :
(a == "+") ? ((b == "+") ? "+-" : "0") :
(b == "+") ? "0" : "-+"
}
 
addDigits3_(a, b, carry) {
var sum1 = addDigits2_(a, b)
var sum2 = addDigits2_(sum1[-1], carry)
return (sum1.count == 1) ? sum2 : (sum2.count == 1) ? sum1[0] + sum2 : sum1[0]
}
 
construct new(value) {
if (value is String && value.all { |c| "0+-".contains(c) }) {
_value = value.trimStart("0")
} else if (value is BigInt) {
_value = toBT_(value)
} else if (value is Num && value.isInteger) {
_value = toBT_(BigInt.new(value))
} else {
Fiber.abort("Invalid argument.")
}
}
 
value { _value }
 
+(other) {
var a = _value
var b = other.value
var longer = (a.count > b.count) ? a : b
var shorter = (a.count > b.count) ? b : a
while (shorter.count < longer.count) shorter = "0" + shorter
a = longer
b = shorter
var carry = "0"
var sum = ""
for (i in 0...a.count) {
var place = a.count - i - 1
var digisum = addDigits3_(a[place], b[place], carry)
carry = (digisum.count != 1) ? digisum[0] : "0"
sum = digisum[-1] + sum
}
sum = carry + sum
return BTernary.new(sum)
}
 
- { BTernary.new(flip_(_value)) }
 
-(other) { this + (-other) }
 
*(other) {
var that = other.clone()
var one = BTernary.new(1)
var zero = BTernary.new(0)
var mul = zero
var flipFlag = false
if (that < zero) {
that = -that
flipFlag = true
}
var i = one
while (i <= that) {
mul = mul + this
i = i + one
}
if (flipFlag) mul = -mul
return mul
}
 
toBigInt {
var len = _value.count
var sum = BigInt.zero
var pow = BigInt.one
for (i in 0...len) {
var c = _value[len-i-1]
var dig = (c == "+") ? BigInt.one : (c == "-") ? BigInt.minusOne : BigInt.zero
if (dig != BigInt.zero) sum = sum + dig*pow
pow = pow * BigInt.three
}
return sum
}
 
compare(other) { this.toBigInt.compare(other.toBigInt) }
 
clone() { BTernary.new(_value) }
 
toString { _value }
}
 
var a = BTernary.new("+-0++0+")
var b = BTernary.new(-436)
var c = BTernary.new("+-++-")
System.print("a = %(a.toBigInt)")
System.print("b = %(b.toBigInt)")
System.print("c = %(c.toBigInt)")
var bResult = a * (b - c)
var iResult = bResult.toBigInt
System.print("a * (b - c) = %(bResult) = %(iResult)")</syntaxhighlight>
 
{{out}}
<pre>
a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 = -262023
</pre>
 
1,453

edits