Shell Script Nuggets: Mathematic Computations


I’ve been asked on numerous occasions whether we can perform mathematic computations in a Unix command line environment? And how about radix conversions and calculations? The answer to both questions is, YES, using a relatively underutilised Unix tool. Like Windows, Unix systems come equiped with a desktop calculator (dc) utility. dc is a reverse polish calculator that supports unlimited precision arithmetic. Relatively few people know about this handy tool and fewer still take advantage of it. Most rely on the stripped down functionality of the expr command which, unfortunately, only handles round number computations.

Reverse polish or postfix notation is simple enough to understand and work with. Basically, it is programmed as a stack. Every numerical value (operand) that is encountered is pushed into the stack. When an operator is encountered, values are popped from the stack in Last In First Out (LIFO) order. The computed result is then pushed back into the stack. The number of elements popped depend on the type of operator being used.

The way we usually write mathematical formulas is in the standard ordered notation (or infix notation), where operators are sandwiched by the operands that they work on. The biggest advantage of postfix over infix notation is that it works solely on operators and operands alone and does not require parentheses [’(’ and ‘)’] to determine precedence. On the downside, users need to adopt a notation method which is not immediately apparent. However, once the rules are understood, converting from one to the other is a simple procedure.

There is little benefit for me to repeat the algorithm here. Refer to the links above on postfix and infix notation for the conversion algorithms. Instead, here are some quick examples of infix formulas written in postfix notation:

Infix: 10 + 11 + 12
Postfix: 10 11 + 12 +

Infix: 10 + 11 * 12
Postfix: 10 11 12 * +

Infix: (10 + 11) * 12
Postfix: 10 11 + 12 *

Once we know how to write a formula in postfix notation, computing the result in a Unix command line environment is a simple matter of invoking the dc command. The following is an example of invoking the desktop calculator and printing the result:

$ dc -e"10 11 + p"
output: 21

The ‘p’ operator simply tells dc to print the value from the top of the operand stack. If you are writing a shell script, it would be useful to store the computation result in a variable for later use. This is achieved using the usual shell notation as follows:

myresult=`dc -e"10 11 + p"`
echo $myresult

or

myresult=$(dc -e"10 11 + p")
echo $myresult

Both achieve the same result of assigning the value of the computation to the variable ‘myresult’ which can then be reused for future operations. Some are probably thinking big deal. We can do the same using the expr command (e.g. expr 10 + 11). The thing is that expr won’t work with decimal values. ‘expr 10.5 + 11.3′ will throw out an ‘non-numeric argument’ error where as ‘dc -e”10.5 11.3 + p”‘ prints the correct result of 21.8.

One other convenient use of ‘dc’ is to convert between radices. We usually write values in a base-10 decimal format. However, we may have occasion to use a different base radix. This is especially true when dealing with computer generated input/output that may include binary, octal, decimal, or hexadecimal values. ‘dc’ provides two operators to define the input and output radix.

i: Pops the value off the top of the stack and sets it as the input radix.
o: Pops the value off the top of the stack and sets it as the output radix.

The default input and output radix is base-10. Examples for converting between the four common radices are as follows:

Conversion Command
Binary to Octal dc -e”2i 8o 11110000 p”
Binary to Decimal dc -e”2i 11110000 p”
Binary to Hex dc -e”2i 16o 11110000 p”
Octal to Binary dc -e”8i 2o 360 p”
Octal to Decimal dc -e”8i 360 p”
Octal to Hex dc -e”8i 16o 360 p”
Decimal to Binary dc -e”2o f0 p”
Decimal to Octal dc -e”8o f0 p”
Decimal to Hex dc -e”16o f0 p”
Hex to Binary dc -e”16i 2o f0 p”
Hex to Octal dc -e”16i 8o f0 p”
Hex to Decimal dc -e”16i f0 p”

While these are the standard conversions, you can just as easily apply the conversion to any other base radix of your choice.

You might also like to take a look at bc which is an arbitrary precision calculator language. With a combination of dc, bc, and other math libraries and utilities, you have pretty much free reign over mathematical computation within a shell environment. As usual, read the manuals for more indepth information on the commands. I’ll leave you to discover other math utilities and their usage. Until next time, good luck and happy scripting.

Related posts:
Shell Script Nuggets: Simulating File Locks
Perl Scripting: Checking CPAN Module Versions
Shell Script Nuggets: File Date Manipulation And Checking
Tech: Rsync rulez!
PHP Script: Spamming A Website - PHP Spambot


4 Comments »

  1. WL Said,

    August 21, 2006 @ 12:54 pm

    Now i understand. Great!

  2. gheorghe Said,

    August 23, 2006 @ 3:58 am

    Thank you very much!
    I was looking for a binary to decimal converter and backwards to use in a shell script. I checked the dc man page but didn’t find any options… I was thinking of writing a shell script with expr to do all the computations but then I found your page :D
    This was really a life saver, couse I’m not that good at math :)

  3. Electromoss Said,

    July 3, 2007 @ 4:19 pm

    I like prefix/Polish notation :)

    G: Well, it’s a little harder to read since it’s not the natural way our eyes and brain processes the information.

  4. aaa Said,

    June 12, 2009 @ 11:39 pm

    Looks like dc’s base conversion is buggy:

    The following command (copied directly from the table above) reports that 360 in octal is equivalent to 132 in hex.

    dc -e”8i 16o 360 p”

    In fact, 360 in octal is equivalent to F0 in hex.

RSS feed for comments on this post · TrackBack URI

Leave a Comment