bc revisited again: change of base

Here we explore bc again, but now to use different bases. Base 10 makes sense to count with our fingers, but beyond that, it is not a good choice (not considering social effects here). A big base has the downside of having bizarrely big multiplication tables. Compare the tables we learn at school with the equivalent for binary: 0·0 = 1·0 = 0·1 = 0 and 1·1 = 10. However, a big base has the benefit of allowing big numbers to be written in compact form.

Fortunately, we can get the best of both worlds if we choose a big base that is a power of base 2, like the hexadecimal base (base 16). In this case, 16 = 2^4, so this base can provide compact expressions without needing difficult multiplication tables. Its 16 symbols are 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F.

A small downside is that we need to be able to associate every binary 4-digit number to its equivalent in hexadecimal, but this is less painful than base-10 multiplication tables. Here I explain my approach to memorise them: First of all, 0, 1, 2, 4, 8 and F are trivially easy. 0 must be 0000 since it is all empty, and F must be 1111 since it is all full. The numbers 1, 2, 4 and 8 are the powers of 2, so they correspond to single 1's at different locations. I associate 9 to 1001 thinking of the symmetry of the latter with the approximate phonetic symmetry of the first (nain). 1010 is a double ace, so I associate it to an A (in Spain, a score of 10 is equivalent to an A grade), and 0101 (the reverse) is what you score when barely passing an exam, a 5. Next, I learn the string C63 (mnemonics: Commodore C64 minus 1) in order to learn pairs of consecutive 1's. Following this, 1100 is C, 0110 is 6 and 0011 is 3. It's absurd but easy and fast. Finally, I learn 7RDE (7 Rabbits Dancing Everywhere) for single 0's, so that 7 is 0111, R is 1011, D is 1101 and E is 1110. Summary:


bin:  dec:  comment:
0000   0    easy
0001   1    easy
0010   2    easy
0011   3    C6[3]
0100   4    easy
0101   5    reverse double ace, barely pass
0110   6    C[6]3
0111   7    [7]BDE
1000   8    easy
1001   9    symmetry
1010   A    double ace
1011   B    7[B]DE
1100   C    [C]63
1101   D    7B[D]E
1110   E    7BD[E]
1111   F    easy

Now let's multiply 82 times AE. We can see how 82 has a lot of 0's, so we write it at the bottom:


  10101110
x 10000010
----------

Every time we get a 0 at the bottom, we don't write anything, but simply shift one place to the left. Every time we get a 1, we simply copy the top row:


         10101110
       x 10000010
       ----------
                0
        10101110
+ 10101110
-----------------
  101100001011100

We get 101100001011100, which can be written as [0101][1000][0101][1100], easily rewritten as 585C.

These operations can be carried out in bc. First of all, we execute an interactive prompt with bc -ql. Then we use the commands ibase for input base and obase for output base. Allowed values are from 2 to 36 (this can depend on the version). Their default value is 10. Interestingly, when we run bc, capital letters from A to Z have assigned values from 10 to 35 (and cannot be changed). The rest of variables are initialised as 0 and cannot begin by a capital letter. We begin by changing the input base to binary:


$ bc -ql
ibase=2
10
2
100
4
111
7

Now we change the output base to binary:


$ bc -ql
obase=2
2
10
4
100
7
111

What is the problem in the following example? We want to go back to input base 10, so why is the base not changed?


$ bc -ql
ibase=2
10
2
ibase=10
10
2

There is no problem at all. Once we set the input base as 2,bc reads all numbers in binary, even when setting the value of a variable. If we want to go back to decimal base, we just tell it in binary:


$ bc -ql
ibase=2
10
2
ibase=10
10
2
ibase=1010
10
10

Now let's multiply 82 times AE in hexadecimal. We want the input and the output base in base 16:


$ bc -ql
ibase=16;obase=10;
82*AE
585C

We could think that, since the default value of obase is already 10, it could suffice defining ibase=16, but that won't work:


$ bc -ql
ibase=16;
82*AE
22620

What is easier is to set obase first and ibase after that, so that the input is kept in decimal until the latter step:


$ bc -ql
obase=16;ibase=16;
82*AE
585C

In summary, bc is great to do operations in other bases and conversions between them. No need for crappy websites for that.