CS3343/3341  Analysis of Algorithms  Spring 2012Weird Topic Balanced Ternary

Three-state Hardware:

Most of our hardware has been based on binary state storage, and binary numbers were used internally. Hardware involved with commercial transactions often has to handle money exact to the penny, but even here the number of pennies can be represented in binary. However, a subset of hardware was constructed to handle decimal numbers directly -- handheld calculators are one good example. From the beginning they used decimal numbers internally, so that the limit on the size of an exponent might be +99, for example. This web page asks the question: what if, instead of flip-flop hardware, we had flip-flap-flop hardware, where a 3-state storage was natural for the hardware? Most people would assume that we might then use base 3 numbers, ternary it's called. But there is a startling alternative.

Base Three Numbers:

Of course we could deal with numbers using 3 as the base. Then the digits (or "trits") would be 0, 1, or 2. The number in the rightmost place would be multiplied by 30 = 1, the next over by 31 = 3, and then onto 32 = 9, 33 = 27, 34 = 81, 35 = 243, and so on. Thus the base 3 number 210213 would equal:

2*34 + 1*33 + 0*32 +  2*31 + 1*30 =
2*81 + 1*27 + 0*9 + 2*3 + 1*1 =
162 + 27 + 0 + 6 + 1 =
19610.

The page on elementary recursion gives code that will transform a number into base 3.

Balanced Ternary:

There is another number system, similar to base 3, that Knuth (Vol. 2, p. 207) calls "perhaps the prettiest number system of all." Instead of 0, 1, and 2, this new system uses -1, 0, and 1 for the value of "trits." Just as with hexadecimal numbers, where one has to invent new symbols for the "digits" with values from 10 to 15 (using A through F), here one needs at least a new symbol for -1. There is no standard notation, but the table shows two ways to write -1: use 1, or -. It's not crazy to use a "minus" sign to stand for -1 because balanced ternary represents negative numbers without an initial minus sign (see below).

These examples include ones with a "decimal" point, which is not handled by the software here. (Several items in this writeup are taken verbatim from Knuth.)

Balanced Ternary, Examples and Notation
Values -1 0 1 Samples
5- 632 5/9- 32 and 5 / 9 1 / 2
Wikipedia-0++ - - - + 0+ + - 0 . - -- - + 0 . + + 0 . + + + + + ...
Knuth
1
01 1 1 1 1 1 0 1 1 1 0 . 1 1 1 1 1 0 . 1 1 0 . 1 1 1 1 1 ...
My own-0|| - - - | 0| | - 0 . - -- - | 0 . | | 0 . | | | | | ...

In the example of -6 above, -6 = -1*32 + 1*31 + 0*30 = -9 + 3 + 0 = -6

Balenced ternary has significant advantages over other number systems:

• The negative numbers are represented directly, without a special "minus sign."
• To negate a number, you interchange -1 and 1, leaving 0 alone.
• The sign of a number is given by its most significant nonzero trit.
• One can compare any two numbers reading left-to-right and using lexicographic order.
• The operation of rounding is the same as truncation (or chopping).
The programs below carry out conversions from an int in a program to base 3 and then to balanced ternary, building a table of values. This program uses Knuth's method for transforming ternary to balanced ternary:

(208.3)10 = (21201.02200220022...)3

Then add the "infinite" number ...111111.111111...3, carrying digits where necessary (2+1 = 0 carry 1) to get:

(...111111210012.21012101210...)3

Finally, subtract ...111111.111111...3 by decrementing each digit, to get, in Knuth's notation.

(208.3)10 =
(21201.02200220022...)3
(base three notation) =
101101.101010101010...    (Knuth's notation) =
|0--0|.|0-0|0-0|0-0 ...    (my notation)

This example illustrates digits to the right of a decimal, which we don't cover in the program below.

Balanced Ternary Values
Java C
```// BalancedTernary.java: convert to balanced ternary
//   with weights ("trits" -1, 0, and 1
//   least sig trit in 0th postion
public class BalancedTernary {
private int len; // length of arrays to use
public int[] zeros; // zero value
public BalancedTernary(int leng) {
len = leng;
zeros = new int[len];
for (int i = 0; i < len; i++) zeros[i] = 0;
}
// convert to base 3
public int[] toBase3(int n) {
int[] r = new int[len];
for (int i = 0; i < r.length; i++) r[i] = 0;
int loc = 0;
while (n > 0) {
r[loc++] = n%3;
if (loc == r.length) {
System.out.println("Overflow in toBase");
System.exit(1);
}
n = n/3;
}
return r;
}

// find negative of bal ternary #
public int[] negate(int[] b) {
int[] c = new int[b.length];
for (int i = 0; i < b.length; i++) c[i] = b[i];
for (int i = 0; i < c.length; i++) {
if (c[i] == 1) c[i] = -1;
else if (c[i] == -1) c[i] = 1;
}
return c;
}

// convert from base 3 to bal ternary
public int[] toBalTern(int[] r) {
int[] b = new int[r.length];

for (int i = 0; i < r.length; i++) b[i] = r[i];
for (int i = 0; i < r.length -1; i++) {
// add 1's to all but most sig digit
b[i] = b[i] + 1;
// process carry
int j = i;
while (b[j] == 3) {
b[j] = 0;
j++;
b[j] = b[j] + 1;
}
}
// subtract 1 from all but most sig digit
for (int i = 0; i < r.length -1; i++)
b[i] = b[i] - 1;
return b;
}

// print in reverse without leading zeros
public void printReverseNoZero(int[] r) {
int j = r.length-1;

while (r[j] == 0) j--;
for (int i = j; i >= 0; i--)
System.out.print(r[i]);
}

// print bal ternary with | - and 0
public void printBalTern(int[] b) {

for (int i = b.length-1; i >= 0; i--) {
if (b[i] == 1) System.out.print("|");
else if (b[i] == -1) System.out.print("-");
else System.out.print("0");
}
}

// print bal ternary without leading zeros
public void printBalTernNoZero(int[] b) {
int j = b.length-1;
while (b[j] == 0) j--;

for (int i = j; i >= 0; i--) {
if (b[i] == 1) System.out.print("|");
else if (b[i] == -1) System.out.print("-");
else System.out.print("0");
}
}

System.out.println("             \tbalanced");
System.out.println("    n   base 3\tternary");
System.out.println("-----------------------");
}

public static void main(String[] args) {
BalancedTernary balT = new BalancedTernary(10);

// print table of values
System.out.println("    0:   0   \t0");
for (int i = -1; i >= -40; i--) {
if (i >= -9) System.out.print("   ");
else System.out.print("  ");
System.out.print(i + ":  -");
int[] x = balT.toBase3(-i);
balT.printReverseNoZero(x);
System.out.print(" \t");
int[] y = balT.toBalTern(x);
balT.printBalTernNoZero(balT.negate(y));
System.out.println();
}
System.out.println();

System.out.println("    0:   0   \t0");
for (int i = 1; i <= 40; i++) {
if (i < 10) System.out.print("    ");
else if (i < 100) System.out.print("   ");
System.out.print(i + ":   ");
int[] x = balT.toBase3(i);
balT.printReverseNoZero(x);
System.out.print(" \t");
int[] y = balT.toBalTern(x);
balT.printBalTernNoZero(y);
System.out.println();
}
}
}
```
```// BalancedTernary.c: convert to bal tern
//   with weights ("trits" -1, 0, and 1
//   least sig trit in 0th postion
#include <stdio.h>
#include <stdlib.h>
#define LEN 10 // length of arrays to use

int zeros[LEN]; // zero value

// convert to base 3
int* tobase3(int n) {
int* r = (int *)malloc(4*LEN);
int i;
for (i = 0; i < LEN; i++) r[i] = 0;
int loc = 0;
while (n > 0) {
r[loc++] = n%3;
if (loc == LEN) {
printf("Overflow in toBase\n");
exit(1);
}
n = n/3;
}
return r;
}

// find negative of bal ternary #
int* negate(int* b) {
int* c = (int *)malloc(4*LEN);
int i;
for (i = 0; i < LEN; i++) c[i] = b[i];
for (i = 0; i < LEN; i++) {
if (c[i] == 1) c[i] = -1;
else if (c[i] == -1) c[i] = 1;
}
return c;
}

// convert from base 3 to bal ternary
int* tobaltern(int* r) {
int* b = (int *)malloc(4*LEN);
int i;
for (i = 0; i < LEN; i++) b[i] = r[i];
for (i = 0; i < LEN -1; i++) {
// add 1's to all but most sig dig
b[i] = b[i] + 1;
// process carry
int j = i;
while (b[j] == 3) {
b[j] = 0;
j++;
b[j] = b[j] + 1;
}
}
// subtract 1 from all but most sig dig
for (i = 0; i < LEN -1; i++)
b[i] = b[i] - 1;
return b;
}

// print in reverse without leading zeros
void printreversenozero(int* r) {
int j = LEN-1;
int i;
while (r[j] == 0) j--;
for (i = j; i >= 0; i--)
printf("%i", r[i]);
}

// print bal ternary with | - and 0
void printbaltern(int* b) {
int i;
for (i = LEN-1; i >= 0; i--) {
if (b[i] == 1) printf("|");
else if (b[i] == -1) printf("-");
else printf("0");
}
}

// print bal ternary without leading zeros
void printbalternnozero(int* b) {
int j = LEN-1;
while (b[j] == 0) j--;
int i;
for (i = j; i >= 0; i--) {
if (b[i] == 1) printf("|");
else if (b[i] == -1) printf("-");
else printf("0");
}
}

printf("             \tbalanced\n");
printf("    n   base 3\tternary\n");
printf("--------------------------\n");
}

int main() {
int i;
for (i = 0; i < LEN; i++) zeros[i] = 0;
// print table of values
printf("    0:   0   \t0\n");
for (i = -1; i >= -40; i--) {
if (i >= -9) printf("   ");
else printf("  ");
printf("%i:  -", i);
int* x = tobase3(-i);
printreversenozero(x);
printf(" \t");
int* y = tobaltern(x);
printbalternnozero(negate(y));
printf("\n");
}
printf("\n");

printf("    0:   0   \t0\n");
for (i = 1; i <= 40; i++) {
if (i < 10) printf("    ");
else if (i < 100) printf("   ");
printf("%i:   ", i);
int* x = tobase3(i);
printreversenozero(x);
printf(" \t");
int* y = tobaltern(x);
printbalternnozero(y);
printf("\n");
}
}
```
```               balanced
n   base 3  ternary
0:   0      0
-1:  -1      -
-2:  -2      -|
-3:  -10     -0
-4:  -11     --
-5:  -12     -||
-6:  -20     -|0
-7:  -21     -|-
-8:  -22     -0|
-9:  -100    -00
-10:  -101    -0-
-11:  -102    --|
-12:  -110    --0
-13:  -111    ---
-14:  -112    -|||
-15:  -120    -||0
-16:  -121    -||-
-17:  -122    -|0|
-18:  -200    -|00
-19:  -201    -|0-
-20:  -202    -|-|
-21:  -210    -|-0
-22:  -211    -|--
-23:  -212    -0||
-24:  -220    -0|0
-25:  -221    -0|-
-26:  -222    -00|
-27:  -1000   -000
-28:  -1001   -00-
-29:  -1002   -0-|
-30:  -1010   -0-0
-31:  -1011   -0--
-32:  -1012   --||
-33:  -1020   --|0
-34:  -1021   --|-
-35:  -1022   --0|
-36:  -1100   --00
-37:  -1101   --0-
-38:  -1102   ---|
-39:  -1110   ---0
-40:  -1111   ----
```
```               balanced
n   base 3  ternary
0:   0      0
1:   1      |
2:   2      |-
3:   10     |0
4:   11     ||
5:   12     |--
6:   20     |-0
7:   21     |-|
8:   22     |0-
9:   100    |00
10:   101    |0|
11:   102    ||-
12:   110    ||0
13:   111    |||
14:   112    |---
15:   120    |--0
16:   121    |--|
17:   122    |-0-
18:   200    |-00
19:   201    |-0|
20:   202    |-|-
21:   210    |-|0
22:   211    |-||
23:   212    |0--
24:   220    |0-0
25:   221    |0-|
26:   222    |00-
27:   1000   |000
28:   1001   |00|
29:   1002   |0|-
30:   1010   |0|0
31:   1011   |0||
32:   1012   ||--
33:   1020   ||-0
34:   1021   ||-|
35:   1022   ||0-
36:   1100   ||00
37:   1101   ||0|
38:   1102   |||-
39:   1110   |||0
40:   1111   ||||
```
```               balanced
n   base 3  ternary
-41:  -1112   -||||
-42:  -1120   -|||0
-43:  -1121   -|||-
-44:  -1122   -||0|
-45:  -1200   -||00
-46:  -1201   -||0-
-47:  -1202   -||-|
-48:  -1210   -||-0
-49:  -1211   -||--
-50:  -1212   -|0||
-51:  -1220   -|0|0
-52:  -1221   -|0|-
-53:  -1222   -|00|
-54:  -2000   -|000
-55:  -2001   -|00-
-56:  -2002   -|0-|
-57:  -2010   -|0-0
-58:  -2011   -|0--
-59:  -2012   -|-||
-60:  -2020   -|-|0
-61:  -2021   -|-|-
-62:  -2022   -|-0|
-63:  -2100   -|-00
-64:  -2101   -|-0-
-65:  -2102   -|--|
-66:  -2110   -|--0
-67:  -2111   -|---
-68:  -2112   -0|||
-69:  -2120   -0||0
-70:  -2121   -0||-
-71:  -2122   -0|0|
-72:  -2200   -0|00
-73:  -2201   -0|0-
-74:  -2202   -0|-|
-75:  -2210   -0|-0
-76:  -2211   -0|--
-77:  -2212   -00||
-78:  -2220   -00|0
-79:  -2221   -00|-
-80:  -2222   -000|
-81:  -10000  -0000
```
```               balanced
n   base 3  ternary
41:   1112   |----
42:   1120   |---0
43:   1121   |---|
44:   1122   |--0-
45:   1200   |--00
46:   1201   |--0|
47:   1202   |--|-
48:   1210   |--|0
49:   1211   |--||
50:   1212   |-0--
51:   1220   |-0-0
52:   1221   |-0-|
53:   1222   |-00-
54:   2000   |-000
55:   2001   |-00|
56:   2002   |-0|-
57:   2010   |-0|0
58:   2011   |-0||
59:   2012   |-|--
60:   2020   |-|-0
61:   2021   |-|-|
62:   2022   |-|0-
63:   2100   |-|00
64:   2101   |-|0|
65:   2102   |-||-
66:   2110   |-||0
67:   2111   |-|||
68:   2112   |0---
69:   2120   |0--0
70:   2121   |0--|
71:   2122   |0-0-
72:   2200   |0-00
73:   2201   |0-0|
74:   2202   |0-|-
75:   2210   |0-|0
76:   2211   |0-||
77:   2212   |00--
78:   2220   |00-0
79:   2221   |00-|
80:   2222   |000-
81:   10000  |0000
```

See table (values from 1 to 364).

Revision date: 2011-12-09. (Please use ISO 8601, the International Standard Date and Time Notation.)