# Understand “ibase” and “obase” in case of conversions with bc?

I often use `bc` utility for converting hex to decimal and vice versa. However, it is always bit trial and error how `ibase` and `obase` should be configured. For example here I want to convert hex value C0 to decimal:

``````\$ echo "ibase=F;obase=A;C0" | bc
180
\$ echo "ibase=F;obase=10;C0" | bc
C0
\$ echo "ibase=16;obase=A;C0" | bc
192
``````

What is the logic here? `obase`(`A` in my third example) needs to be in the same base as the value which is converted(`C0` in my examples) and `ibase`(`16` in my third example) has to be in the base where I am converting to?

• for hex calculations (input and output in hex) I have to set obase before ibase! – Paschalis Sep 15 '16 at 2:59

What you actually want to say is:

``````\$ echo "ibase=16; C0" | bc
192
``````

for hex-to-decimal, and:

``````\$ echo "obase=16; 192" | bc
C0
``````

for decimal-to-hex.

You don't need to give both `ibase` and `obase` for any conversion involving decimal numbers, since these settings default to 10.

You do need to give both for conversions such as binary-to-hex. In that case, I find it easiest to make sense of things if you give `obase` first:

``````\$ echo "obase=16; ibase=2; 11000000" | bc
C0
``````

If you give `ibase` first instead, it changes the interpretation of the following `obase` setting, so that the command has to be:

``````\$ echo "ibase=2; obase=10000; 11000000" | bc
C0
``````

This is because in this order, the `obase` value is interpreted as a binary number, so you need to give 10000₂=16 to get output in hex. That's clumsy.

Now let’s work out why your three examples behave as they do.

1. `echo "ibase=F;obase=A;C0" | bc`

`180`

That sets the input base to 15 and the output base to 10, since a single-digit value is interpreted in hex, according to POSIX. This asks `bc` to tell you what C0₁₅ is in base A₁₅=10, and it is correctly answering 180₁₀, though this is certainly not the question you meant to ask.

2. `echo "ibase=F;obase=10;C0" | bc`

`C0`

This is a null conversion in base 15.

Why? First, because the single `F` digit is interpreted in hex, as I pointed out in the previous example. But now that you've set it to base 15, the following output base setting is interpreted that way, and 10₁₅=15, so you have a null conversion from C0₁₅ to C0₁₅.

That's right, the output isn't in hex as you were assuming, it's in base 15!

You can prove this to yourself by trying to convert `F0` instead of `C0`. Since there is no `F` digit in base 15, `bc` clamps it to `E0`, and gives `E0` as the output.

3. `echo "ibase=16; obase=A; C0"`

`192`

This is the only one of your three examples that likely has any practical use.

It is changing the input base to hex first, so that you no longer need to dig into the POSIX spec to understand why `A` is interpreted as hex, 10 in this case. The only problem with it is that it is redundant to set the output base to A₁₆=10, since that's its default value.

• Thanks. The `bc` also must use upper case letters for hex – eigenfield Feb 16 '20 at 6:27

Setting `ibase` means you need to set `obase` in that same base. Explaining your examples will show this:

``````echo "ibase=F;obase=A;C0" | bc
``````

You set `bc` to consider input numbers as represented in base 15 with the "ibase=F". "obase=A" sets output numbers to base 10, which is the default.

`bc` reads C0 as a base 15 number: C = 12. 12*15 = 180.

``````echo "ibase=F;obase=10;C0" | bc
``````

In this one, you set input to base 15, and output to 10 - in base 15, so output base is 15. C0 input in base 15 is C0 output in base 15.

``````echo "ibase=16;obase=A;C0" | bc
``````

Set input to base 16, output to base 10 (A in base 16 is 10 in base 10).

C0 converted to base 10 is: 12*16 = 192

My personal rule is to set obase first, so that I can use base 10. Then set ibase, also using base 10.

Note that `bc` does have an ironic exception: `ibase=A` and `obase=A` always sets input and output to base 10. From the `bc` man page:

``````Single digit numbers always have the value of the digit
regardless of the value of ibase.
``````

This behavior is enshrined in the specification of `bc`: From the 2004 OpenGroup `bc` specification:

``````When either ibase or obase is assigned a single digit value from
the list in 'Lexical Conventions in bc', the value shall be assumed
in hexadecimal. (For example, ibase=A sets to base ten, regardless
of the current ibase value.) Otherwise, the behavior is undefined
when digits greater than or equal to the value of ibase appear in
the input.
``````

That's why the `ibase=F` setting changed your input base to base 15, and why I recommended to always set the base using base 10. Avoid confusing yourself.

• @StéphaneChazelas - I have a recollection of "ibase=A" working on a SysVr3 machine in 1989 or so. I bet it goes back farther that Single Unix Spec. I couldn't quickly google up an earlier ref. – Bruce Ediger Apr 30 '15 at 14:28
• I think that's because there are more links around to the older specs since they have been around for longer. The same kind of things happen for apache/mysql/bugzilla... documentation where google gives you the doc for the older versions first instead of the latest. – Stéphane Chazelas Apr 30 '15 at 16:21

All numbers are interpreted by GNU bc as the current input base that is in effect for the statement the number appears in. When you use a digit outside the current input interpret them as the highest digit available in the base (9 in decimal) when part of a multiple digit number, or as their normal values when used as a single digit number (`A` == 10 in decimal).

From the GNU bc manual:

Single digit numbers always have the value of the digit regardless of the value of ibase. (i.e. A = 10.) For multi-digit numbers, `bc` changes all input digits greater or equal to ibase to the value of ibase-1. This makes the number `FFF` always be the largest 3 digit number of the input base.

However, you should be aware that the POSIX standard only defines this behavior for assignments to `ibase` and `obase`, and not in any other context.

From the SUS specification on bc:

When either ibase or obase is assigned a single digit value from the list in Lexical Conventions in bc , the value shall be assumed in hexadecimal. (For example, ibase=A sets to base ten, regardless of the current ibase value.) Otherwise, the behavior is undefined when digits greater than or equal to the value of ibase appear in the input. Both ibase and obase shall have initial values of 10.

The key factor you are missing is that F is not in fact sixteen, but is actually fifteen, so when you are setting ibase=F you are setting the input base to fifteen.

Therefore, to portably set the ibase to hexadecimal from an unknown state, you therefore need to use two statements: `ibase=A; ibase=16`. However, in the beginning of the program you can rely on it being decimal and simply use `ibase=16`.

It is always recommended to set `ibase` and `obase` using a single-digit number, instead of a number such as `16`, since according to `bc` man page,

Single digit numbers always have the value of the digit regardless of the value of ibase.

This means that `A,B,...,F` always have the values `10,11,...,15` respectively, regardless of what the value of `ibase` is. You can also use `F+1` to specify number `16`. For example, you'd better write

``````echo "ibase=F+1; obase=A; C0" | bc
``````

instead of writing `echo "ibase=16; obase=A; C0" | bc` to specify that input base is `16` and output base is `10`. Or for example, if you want both `ibase` and `obase` to be 16, you'd better use

``````ibase=F+1; obase=F+1
``````

instead of using `ibase=16; obase=10`. Similarly, if you're going to input your numbers in base 14 and output them in base 16, use

``````ibase=E; obase=F+1
``````

Although bath forms have the same results, the former is less error prone, whereas the latter may lead to more confusion and error.

The difference between the two forms especially becomes more apparent, when you are in the execution environment of `bc`, or you are going to write your calculations in a file, and then pass that file to `bc` as an argument. In such situations, you may have to change the values of `ibase` and `obase` several times, and using the latter form, can lead to serious confusion and errors. (experience it)

## Heading ##In short, once you set ibase, all numbers that are entered are in that base. So, if you do:

``````ibase=16
``````

Then any numbers you enter after that are considered hex digits. The possibly unintended consequence of this is that if you then try to set obase (or reset ibase) to say, base 10, you will need to use A, not 10 as the number:

``````obase=A
``````

in bc, you can check the values of ibase and obase, by typing them without setting them:

``````ibase
16
obase
10
``````

in oneliner parlance (convert hex 13 to decimal:

``````echo "ibase=16;13;ibase;obase" | bc -l
19
16
10
``````