#21: The command line calculator bc

Posted by | Comments (2) | Trackbacks (2)

Performing calculations on the command line is very handy and bc is the tool which does it for you. Also bash can do some calculation stuff, but that's not very intuitive. For instance

echo $[4*4]

calculates 4*4. That stills looks easy, but as soon as you want to perform more complex calculations, this becomes a hassle. Bash is built for different things than calculation and so bc is the better choice. It can do much more for you and its syntax is ways easier.

There are three ways to use bc. The first is to use files. Write your bc script into a file an then call

bc file

Use -q to suppress the header of bc. The second way is to use STDIN:

echo '1+2*3/4' | bc

and last but not least the third way is the interactive mode. Just run bc and you get a shell-like prompt where you can insert your operations. Quit bc by typing quit and hitting enter.

It's up to your needs, which way you choose, there is no difference in functionality.

As you've already seen: basic arithmetic operations can be done with the operators +, -, * and /. But there's much more. You can, e.g., calculate the square root:

sqrt(x)

where x is any number. The syntax of bc is very C-like. Therefore you can also assign values to variables:

var=123
print var

You can also print strings to the screen:

print "Hello World\n"

There are also some special variables. For instance scale:

scale=10

That sets the decimals form default 0 to 10. Examine the difference with

10/3
scale=10
10/3

The first line only generates 3, the third one 3.3333333333. Two other important special variables are ibase and obase, which define the number system; the default is 10 (decimal system). ibase specifies the input number system and obase the output number system. With these variables you can, e.g., convert hex digits to binary:

ibase=16
obase=2
F

Output is: 1111 (binary for hex F).

bc also let's you define functions like in any normal programming language. The language construct for this is define:

define by2(x) { return x*2 }

You can now call this function:

by2(6)

The output is 12.

Also conditions and loops are possible:

while (var < 5) {
   ++var
}
print var
if (by2(4) < 10) {
    print "Foobar\n"
}

bc also has some pre-defined functions for basic math operations. These are s(x) for the sine, c(x) for the cosine, a(x) for the arctangent, l(x) for the natural logarithm, e(x) for raising the Euler constant to the power of x and j(n, x) for the Bessel function. These functions are all available when executing bc with the -l parameter, which loads the particular math library.

This is all very useful, but one thing has always bothered me is the precision of irrational numbers. bc obviously does a pretty bad job on approximating these numbers. If I execute the following

l(e(3))

I always get 2.99999999999999999999 instead of 3. That's the same if I, e.g., want to calculate the cube root of, let's say, 8:

e(l(8)/3)

There I get 1.99999999999999999998 instead of 2. I know, this behavior should be platform specific, but it should be possible to get nicer results here by automatically rounding periods. As yet I haven't found a way to make bc handle this smarter. If you know one, please leave me a comment.

Learn more about bc:

Trackbacks

Manko10 sent a Trackback on : (permalink)

RT @reflinux: #Advent series “24 Short #Linux #Hints”, day 21: The #command line #calculator #bc http://bit.ly/fwRlDO

robo47 sent a Trackback on : (permalink)

RT @reflinux: #Advent series “24 Short #Linux #Hints”, day 21: The #command line #calculator #bc http://bit.ly/fwRlDO

Comments

There have been 2 comments submitted yet. Add one as well!
phodd
phodd wrote on : (permalink)

You’ve linked my FAQ, which (now) mentions the trunc() function I’ve written which attempts to remedy the largely aesthetic repeating nines problem (as well as repeating zeroes).

Bear in mind that your examples differ from the correct value by a very small amount. In fact e(3) on its own, sqrt(2) and even 2/3 necessarily differ from the correct value by a very small amount – bc stores all results as a decimal fraction – yet most people take those errors for granted, deliberately ignore them or are even unaware there’s a difference.

To demonstrate this behaviour in the worst case, try

scale=20;(2/3)*3

at the bc console. The error here is tiny; one part in fifty quintillion, but it’s unsightly when we’re used to seeing nice round numbers and instead we see nines.

As to the trunc(x) function I mentioned, here it is:

define trunc(x) {
  auto os,s;
  os=scale-5
  if(scale&gt;=A){
    scale-=4
    s=1;if(x&lt;0)s=-1
    x+=s*A^-scale
    scale-=1;x/=1
  }
  for(scale=0;scale&lt;=os;scale++)if(x==x/1){x/=1;break}
  scale=os+5;return(x)
}

The comments field turns the less thans and greater thans into &lt; and &gt; respectively, which I can’t seem to work around.

Then try:

scale=20;f=(2/3)*3;f;trunc(f)

which will set f to a sub-optimal but close value to 2, display that value, and display the value after trunc() has successfully attempted to ‘fix’ it.

Janek Bevendorff
Janek Bevendorff wrote on : (permalink)

Hi, thank you very much!
Such a truncation function is of course a workaround but I think in this case a decent solution.

I know the problem with the HTML entities; it just occurs within code fields and seems to be a plugin conflict. I’ll try to fix that.

Write a comment:

HTML-Tags will be converted to Entities.
Textile-formatting allowed
Standard emoticons like :-) and ;-) are converted to images.
Design and Code Copyright © 2010-2017 Janek Bevendorff Content on this site is published under the terms of the GNU Free Documentation License (GFDL). You may redistribute content only in compliance with these terms. tweetbackcheck