Guide to Unix/Explanations/bc

bc is an arbitrary-precision decimal calculator language. The arbitrary-precision means that numbers can contain an arbitrary number of digits before the decimal point, limited by memory; most other languages limit numbers to eight bytes at most. The number of digits after the decimal point is per default zero, but can be set to a fixed number called "scale".

"bc" is often called using the "-l" option. The option loads the standard library containing mostly trigonometric functions available as single letters, and sets the number of decimal places for division to 20.

Overview

edit

Bc at a glance:

echo '2*17' | bc                  # Feeds the math expression into bc, resulting in 34
echo '2^5' | bc                   # Exponentiation
echo '2+3;4*5' | bc               # Two calculations, output on separate lines
echo '1/3' | bc                   # Zero: the default decimal precision is 0
echo '1/3' | bc -l                # 0.33...: -l raises the decimal precision to 20
echo 'sqrt(2)' | bc -l
echo 'sqrt(2.00)' | bc            # 1.41; sqrt is affected by the argument precision
echo 's(1/3)' | bc -l             # sin(1/3): sin is there via -l loading the library
echo 's(1)+c(1)+a(1)+l(1)+e(1)' | bc -l  # sin(1)+cos(1)+atan(1)+ln(1)+exp(1)
echo 'scale=100;4*a(1)' | bc -l   # Pi, 3.1415..., with 100 decimal digit precision
echo 'scale=5000;4*a(1)' | bc -l  # Pi, 3.1415..., with 5000 decimal digit precision within minutes
echo '4!=5' | bc -l               # 1 for True: 4 differs from 5
echo 'if(1!=0)2' | bc -l          # if
echo 'i=1;r=1;while(i<=10){r*=i;i+=1};r' | bc -l  # Factorial of 10; while loop
echo 'r=1;for(i=1;i<=10;i++){r*=i};r' | bc -l     # Factorial of 10; for loop
echo 'define mul(x,y){return x*y}mul(2,3)' | bc   # Functions there
echo '!((1&&0)||1)' | bc          # GNU bc, not POSIX bc: not, and, or (logical operations)
echo 'e(l(2)*1/3)' | bc -l        # 2 ^ 1/3; exponentiation with non-integers
echo 'a[0]=1;a[0]+1' | bc         # Arrays are supported
echo 'obase=2;12' | bc            # Yields 12 converted to binary by setting output base
echo 'obase=2;1/3' | bc -l        # Yields .01010101...: output base affects fractions
echo 'ibase=16;1F' | bc           # Yields 31; sets the input base
echo 'ibase=8;ibase=10;10' | bc   # Yields 8; due to the 1st ibase, the 2nd ibase with 10 is interpreted as 8
echo 'ibase=8;ibase=A;10' | bc    # Yields 10; A is interpreted as 10
echo 'ibase=8;ibase=G;10' | bc    # Yields 16; G is interpreted as 16
result=$( echo '2^200' | bc )     # Stores the result in a variable
bc <<< '2*17'                     # Works in bash
bc -l                             # Starts interactive use; enter quit to quit
bc -l mylib.bc                    # Loads bc code from mylib.bc and starts interactive use

Example session

edit

This is an example of a user starting bc, doing two calculations, and exiting with "quit". Note that pressing ^D (control-D) also exits.

$ bc -l
3 + 4
7
2 / 5
.40000000000000000000
quit
$


binary numbers

edit

Conversion from decimal ratio to binary[1]

bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
obase=2
3/14
.0011011011011011011011011011011011011011011011011011011011011011010
1/5
.0011001100110011001100110011001100110011001100110011001100110011001

Example script

edit

Some versions of "bc" limit function and variable names to one letter. The following example has long function and variable names and must be changed to work on these copies of "bc".

The following example was tested with OpenBSD bc and has also been verified with Gnu bc version 1.06 patchlevel 2.

This script implements Simpson's rule for integration. The function "integrate" approximates the definite integral from "a" to "b" using "n" parabola sections. The formula for "simpson" is taken from the Wikipedia article. This example integrates the sine function, but different functions can be used by replacing f.

define f(x) {
  return s(x);
}

define simpson(a,b) {
  return ( (b-a)/6 ) * ( f(a) + 4*f((a+b)/2) + f(b) );
}

define integrate(a,b,n) {
  delta = (b - a) / n;
  result = 0;

  for(i = a; (n = n - 1) + 1; i = i + delta) {
    /*print "calling simpson(", i, ", ", i + delta, ") with n = ", n, "\n";*/
    result = result + simpson(i, i + delta);
  }
  return result;
}

Put this in a file, say "simpson", load it, and integrate f from 0 to pi (pi is "4*a(1)", 4 times arctangent of 1) with 100 intervals:

$ bc -l simpson
integrate(0, 4*a(1), 100)
2.00000000067647189101
^D

Limitations

edit
  • Bc does not support floating-point arithmetic. It supports fixed-point arithmetic, and the fixed number of decimal points can be set to be rather large, via scale.
  • bc does not allow numbers to be entered in the scientific notation, like 5.031E10.
  • No operators for bitwise manipulation (| for or, & for and, ^ for xor, <<, >>) in POSIX and GNU bc.
  • No operators for logical and and or (&&, ||) in POSIX bc; present in GNU bc as an extension.
  • Very limited number of functions in the standard library. Many additional functions are provided by Gavin Howard bc.

Standard library

edit

Standard library is loaded when bc is called with the "-l" option. The library contains mostly trigonometric functions available as single letters. The library is usually implemented in bc itself and thus serves as examples of bc use. The functions included are s (sin), c (cos), a (atan), l (log), e (exp) and j (the bessel function).

Links:

  • libmath.b in bc-21, opensource.apple.com – actually GNU bc used in Linux as well
  • bc.library in freebsd-src, github.com
  • bc.library in openbsd/src, github.com
  • lib.bc in gavinhoward/bc, github.com
  • lib2.bc in gavinhoward/bc, github.com – extension functions

Decimal vs. binary

edit

As specified by POSIX, bc shall behave as if performing the calculation using decimal representation in the digits after decimal point rather than the usual binary representation. One consequence is that 0.1 is exactly representable and that 0.1 * 3 is exactly 0.3, which is not the case in languages that use binary representation.

edit
  1. math.stackexchange question: find-a-fraction-given-the-repeating-binary-expansions