Balanced ternary logic
Ternary is normally another name for base 3, that is to say, each digit is 0
, 1
, or 2
, and each place is worth 3 times as much as the next place.
Balanced ternary is a modification of ternary which uses digits of -1
, 0
and 1
. This has the advantage of not needing a sign. Each place is still worth 3 times as much as the next place. The first few positive integers are therefore [1]
, [1, -1]
, [1, 0]
, [1, 1]
, [1, -1, -1]
while the first few negative integers are [-1]
, [-1, 1]
, [-1, 0]
, [-1, -1]
, [-1, 1, 1]
.
You have three inputs x, y, z
. z
is either -1
, 0
, or 1
, while x
and y
can be from -3812798742493
to 3812798742493
inclusive.
The first step is to convert x
and y
from decimal to balanced ternary. This should give you 27 trits (TeRnary digITS). You then have to combine the trits from x
and y
in pairs using a ternary operation and then convert the result back to decimal.
You can choose which values of z
map to one of these three ternary operations each:
A
: Given two trits, if either is zero, then the result is zero, otherwise the result is -1 if they are different or 1 if they are the same.B
: Given two trits, if either is zero, then the result is the other trit, otherwise the result is zero if they are different or the negation if they are the same.C
: Given two trits, the result is zero if they are different or their value if they are the same.
Example. Suppose x
is 29
and y
is 15
. In balanced ternary, these become [1, 0, 1, -1]
and [1, -1, -1, 0]
. (The remaining 23 zero trits have been omitted for brevity.) After each of the respective operations they become A
: [1, 0, -1, 0]
, B
: [-1, -1, 0, -1]
, C
: [1, 0, 0, 0]
. Converted back to decimal the results are 24
, -37
and 27
respectively. Try the following reference implementation for more examples:
function reference(xd, yd, zd) {
var rd = 0;
var p3 = 1;
for (var i = 0; i < 27; i++) {
var x3 = 0;
if (xd % 3 == 1) {
x3 = 1;
xd--;
} else if (xd % 3) {
x3 = -1;
xd++;
}
var y3 = 0;
if (yd % 3 == 1) {
y3 = 1;
yd--;
} else if (yd % 3) {
y3 = -1;
yd++;
}
var r3 = 0;
if (zd < 0) { // option A
if (x3 && y3) r3 = x3 == y3 ? 1 : -1;
} else if (zd > 0) { // option B
if (!x3) r3 = y3;
else if (!y3) r3 = x3;
else r3 = x3 == y3 ? -x3 : 0;
} else { // option C
r3 = x3 == y3 ? x3 : 0;
}
rd += r3 * p3;
p3 *= 3;
xd /= 3;
yd /= 3;
}
return rd;
}
<div onchange=r.textContent=reference(+x.value,+y.value,+z.selectedOptions[0].value)><input type=number id=x><input type=number id=y><select id=z><option value=-1>A</option><option value=1>B</option><option value=0>C</option><select><pre id=r>
The reference implementation follows the steps given above but you are of course free to use any algorithm that produces the same results.
This is code-golf, so the shortest program or function that violates no standard loopholes wins!
z
have to be one of-1,0,1
or can we pick any three consistent and distinct values? I've selected1,2,3
in my answer, and there's some confusion about it. \$\endgroup\$