Balanced ternary logic 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 &lt; 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 &lt; 0) { // option A
            if (x3 &amp;&amp; y3) r3 = x3 == y3 ? 1 : -1;
        } else if (zd &gt; 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;
}
&lt;div onchange=r.textContent=reference(+x.value,+y.value,+z.selectedOptions[0].value)&gt;&lt;input type=number id=x&gt;&lt;input type=number id=y&gt;&lt;select id=z&gt;&lt;option value=-1&gt;A&lt;/option&gt;&lt;option value=1&gt;B&lt;/option&gt;&lt;option value=0&gt;C&lt;/option&gt;&lt;select&gt;&lt;pre id=r&gt;




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!
Clean, 231 ... 162 bytes

import StdEnv
$n=tl(foldr(\p[t:s]#d=sign(2*t/3^p)
=[t-d*3^p,d:s])[n][0..26])
@x y z=sum[3^p*[(a+b)/2,[1,-1,0,1,-1]!!(a+b+2),a*b]!!(z+1)\\a&lt;- $x&amp;b&lt;- $y&amp;p&lt;-[0..26]]


Defines the function @, taking three Ints and giving an Int.
Operators map as 1 -&gt; A, 0 -&gt; B, -1 -&gt; C.

Try it online!

The function $ folds a lambda over the digit places [0..26], into a list of ternary digits. It uses the head of the list it yields to keep a current total difference from the requisite number (which is why it is tailed prior to returning), and sign(2*t/3^p) to determine the current digit to yield. The sign trick is equivalent to if(abs(2*t)&lt;3^p)0(sign t).