The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

bc - an arbitrary precision calculator language

SYNOPSIS

Show a help message

        % bc -h

Run a bc program from FILE

        bc [-bdiqswy] FILE

Run a bc program from standard input

        bc [-bdiqswy] -

DESCRIPTION

This is the PerlPowerTools implementations of GNU version of bc, a souped-up calculator language. This is documented at:

https://www.gnu.org/software/bc/manual/html_mono/bc.html

Options

  • -b - use Math::BigFloat

  • -d - turn on debugging output

  • -h - show a help message and exit

  • -i - force interactive mode (a no-op for compatibility)

  • -l - use mathlib

  • -q - suppress the welcome message

  • -s - process the POSIX bc language (a no-op for compatibility)

  • -w - give warnings for POSIX bc extensions (a no-op for compatibility)

  • -y - turn on parsing debugging output

Environment

There are no environment variables that affect this program.

The bc language

NOTE: Some of this documentation is lifted straight from the GNU documentation for its version of bc.

bc is a language that supports arbitrary precision numbers with interactive execution of statements. There are some similarities in the syntax to the C programming language.

bc starts by processing code from all the files listed on the command line in the order listed. If no files are listed, then stdin is read. If a file contains a command to halt the processor, bc will never read from the standard input.

Dash ('-') is a pseudo-filename which represents stdin. This makes it possible to do something like bc fileA - fileB and have bc run commands from fileA before prompting for input, and then run commands from fileB after interactive input is finished.

bc will terminate interactive input via stdin if you enter quit or press CTRL-C.

Pressing CTRL-Z will end stdin input and move on the the next filename on the command line (if there is one). Otherwise, execution ends.

OPTIONS

bc takes the following options from the command line:

-b

Use Math::BigFloat for arbitrarily large number support.

-d

Print debugging data (using Data::Dumper).

-y

Turn on parser debugging.

BASIC ELEMENTS

Numbers

The most basic element in bc is the number. Numbers are arbitrary precision numbers. This precision is both in the integer part and the fractional part. All numbers are represented internally in decimal and all computation is done in decimal.

There are two attributes of numbers, the length and the scale. The length is the total number of significant decimal digits in a number and the scale is the total number of decimal digits after the decimal point. For example, .000001 has a length of 6 and scale of 6, while 1935.000 has a length of 7 and a scale of 3.

Variables

Numbers are stored in two types of variables, simple variables and arrays. Both simple variables and array variables are named. Names begin with a letter followed by any number of letters, digits and underscores. All letters must be lower case.

The type of variable is clear by the context because all array variable names will be followed by brackets ( [ ] ).

Special Variables

scale

Defines how some operations use digits after the decimal point. The default value is 0.

ibase

Defines the conversion base for input numbers. Defaults to 10.

obase

Defines the conversion base for output numbers. Defaults to 10.

Comments

Comments in bc start with the characters '/*' and end with the characters '*/'. Comments may start anywhere and appear as a single space in the input. Note that this causes comments to delimit other input items, therefore a comment cannot be included the middle of a variable name. Comments include any newlines (end of line) between the start and the end of the comment.

To support the use of scripts for bc, a single line comment has been added as an extension. A single line comment starts at a '#' character and continues to the next end of the line. The end of line character is not part of the comment and is processed normally.

EXPRESSIONS

Numbers are manipulated by expressions and statements. Since the language was designed to be interactive, statements and expressions are executed as soon as possible. There is no main program. Instead, code is executed as it is encountered.

A simple expression is just a constant. bc converts constants into internal decimal numbers using the current input base, specified by the variable ibase.

Full expressions are similar to many other high level languages. Since there is only one kind of number, there are no rules for mixing types. Instead, there are rules on the scale of expressions. Every expression has a scale. This is derived from the scale of original numbers, the operation performed and in many cases, the value of the variable scale.

Basic Expressions

In the following descriptions of legal expressions, "expr" refers to a complete expression and "VAR" refers to a simple or an array variable. A simple variable is just a NAME and an array variable is specified as NAME[EXPR].

Unless specifically mentioned the scale of the result is the maximum scale of the expressions involved.

- expr

The result is the negation of the expression.

++ VAR

The variable is incremented by one and the new value is the result of the expression.

-- VAR

The variable is decremented by one and the new value is the result of the expression.

VAR ++

The result of the expression is the value of the variable and then the variable is incremented by one.

VAR --

The result of the expression is the value of the variable and then the variable is decremented by one.

expr + expr

The result of the expression is the sum of the two expressions.

expr - expr

The result of the expression is the difference of the two expressions.

expr * expr

The result of the expression is the product of the two expressions.

expr / expr

The result of the expression is the quotient of the two expressions. The scale of the result is the value of the variable scale

expr % expr

The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to SCALE digits. That result is used to compute a-(a/b)*b to the scale of the maximum of SCALE+scale(b) and scale(a). If SCALE is set to zero and both expressions are integers this expression is the integer remainder function.

expr ^ expr

The result of the expression is the value of the first raised to the second.

The scale of the result is SCALE if the exponent is negative. If the exponent is positive the scale of the result is the minimum of the scale of the first expression times the value of the exponent and the maximum of SCALE and the scale of the first expression. (e.g. scale(a^b) = min(scale(a)*b, max(SCALE, scale(a))).) It should be noted that expr^0 will always return the value of 1.

( expr )

This alters the standard precedence to force the evaluation of the expression.

VAR = expr

The variable is assigned the value of the expression.

VAR op= expr

This is equivalent to "VAR = VAR op expr" with the exception that the "VAR" part is evaluated only once. This can make a difference if "VAR" is an array.

Relational Expressions

Relational expressions are a special kind of expression that always evaluate to 0 or 1, 0 if the relation is false and 1 if the relation is true. These may appear in any legal expression. (POSIX bc requires that relational expressions are used only in if, while, and for statements and that only one relational test may be done in them.) The relational operators are

expr1 < expr2

The result is 1 if expr1 is strictly less than expr2.

expr1 <= expr2

The result is 1 if expr1 is less than or equal to expr2.

expr1 > expr2

The result is 1 if expr1 is strictly greater than expr2.

expr1 >= expr2

The result is 1 if expr1 is greater than or equal to expr2.

expr1 == expr2

The result is 1 if expr1 is equal to expr2.

expr1 != expr2

The result is 1 if expr1 is not equal to expr2.

Boolean Expressions

Boolean operations are also legal. (POSIX bc does NOT have boolean operations). The result of all boolean operations are 0 and 1 (for false and true) as in relational expressions. The boolean operators are:

!expr

The result is 1 if expr is 0.

expr && expr

The result is 1 if both expressions are non-zero.

expr || expr

The result is 1 if either expression is non-zero.

Precedence

The expression precedence is as follows: (lowest to highest)

        = += etc     operators (assigment)   right associative
        ||           OR operator             left associative
        &&           AND operator            left associative
        !            NOT operator            nonassociative
        < > etc      relational operators    left associative
        + and -      operators               left associative
        *, / and %   operators               left associative
        ^            operator (power)        right associative
        unary -      operator                nonassociative
        ++ and --    operators               nonassociative

This differs from POSIX-compliant bc, which puts assignment between relational operators and addition/subtraction. As a result, expressions behave more like they do in most languages (including perl and C).

Special Expressions

There are a few more special expressions that are provided in bc. These have to do with user-defined functions and standard functions. These are:

length ( expression )

The value of the length function is the number of significant digits in the expression.

scale ( expression )

The value of the scale function is the number of digits after the decimal point in the expression.

sqrt ( expression )

The value of the sqrt function is the square root of the expression. If the expression is negative, a run time error is generated.

Statements

Statements (as in most algebraic languages) provide the sequencing of expression evaluation. In bc statements are executed "as soon as possible." Execution happens when a newline in encountered and there is one or more complete statements. Due to this immediate execution, newlines are very important in bc. In fact, both a semicolon and a newline are used as statement separators. An improperly placed newline will cause a syntax error.

Because newlines are statement separators, it is possible to hide a newline by using the backslash character. The sequence "\<nl>" (where <nl> represents a newline your typed) appears to bc as whitespace instead of an actual newline.

A statement list is a series of statements separated by semicolons and newlines.

The following is a list of bc statements and what they do. Things enclosed in brackets ( [ ] ) are optional parts of the statement.

EXPRESSION

This statement does one of two things. If the expression starts with "<variable> <assignment> ...", it is considered to be an assignment statement. If the expression is not an assignment statement, the expression is evaluated and printed to the output. After the number is printed, a newline is printed.

For example, "a=1" is an assignment statement and "(a=1)" is an expression that has an embedded assignment.

STRING

The string is printed to the output. Strings start with a double quote character and contain all characters until the next double quote character. All characters are taken literally, including any newline. No newline character is printed after the string.

The print statement (an extension) provides another method of output. The LIST is a list of strings and expressions separated by commas. Each string or expression is printed in the order of the list. No terminating newline is printed. Expressions are evaluated and their value is printed and assigned to the variable last. Strings in the print statement are printed to the output and may contain special characters. Special characters start with the backslash character. The special characters include:

        \a  alert or bell
        \b  backspace
        \f  form feed
        \n  newline
        \r  carriage return
        \q  double quote
        \t  tab
        \e  backslash.

Any other character following a backslash will be ignored.

{ STATEMENT_LIST }

This is the compound statement. It allows multiple statements to be grouped together for execution.

if ( EXPRESSION ) STATEMENT

The if statement evaluates the expression and executes STATEMENT depending on the value of the expression. If the expression is non-zero, STATEMENT is executed. Otherwise it isn't. (The statement can be a block enclosed in { }.)

while ( EXPRESSION ) STATEMENT

The while statement will execute the statement while the expression is non-zero. It evaluates the expression before each execution of the statement. Termination of the loop is caused by a zero expression value or the execution of a break statement.

for ( [EXPRESSION1] ; [EXPRESSION2] ; [EXPRESSION3] ) STATEMENT

The for statement controls repeated execution of the statement. EXPRESSION1 is evaluated before the loop. EXPRESSION2 is evaluated before each execution of the statement. If it is non-zero, the statement is evaluated. If it is zero, the loop is terminated.

After each execution of the statement, EXPRESSION3 is evaluated before the reevaluation of expression2. If EXPRESSION1 or EXPRESSION3 are missing, nothing is evaluated at the point they would be evaluated. If EXPRESSION2 is missing, it is the same as substituting the value 1 for EXPRESSION2.

(The optional expressions are an extension. POSIX bc requires all three expressions.)

The following is equivalent code for the for statement:

        expression1;
        while (expression2) {
                statement;
                expression3;
        }
break

This statement causes a forced exit of the most recent enclosing while statement or for statement.

quit

When the quit statement is read, the bc processor is terminated, regardless of where the quit statement is found. For example, if (0 == 1) quit will cause bc to terminate.

EXAMPLE

The following illustrates how bc expressions can be written in script form and fed to bc via stdin.

        print "\nCompute balances after withdrawals\n"

        bal = 100.00
        withdrawal = 20.00;

        while (1) {
                print "Balance: ", "\t", bal, "\n"
                print "Withdrawal: ", "\t", withdrawal, "\n"
                if ( (bal - withdrawal) < 0 ) break;
                bal -= withdrawal
        }

        print "Balance:", bal

        quit

BUGS AND LIMITATIONS

This implementation of bc is mostly POSIX compliant and has similar extensions to GNU bc. However, some features and extensions are either not supported or are not working.

Perhaps the biggest non-working feature would be Function definitions via the define syntax, which if used generats syntax errors. As a consequence, the -l option (to load math library definitions) doesn't work either.

Setting the following variables don't seem to have the intended effects:

        scale
        ibase
        obase

Hexadecimal values, for use when ibase is > 10, are not supported.

Old style assignment operators (=+, =-, =*, =/, =%, =^) are not required to be supported by the POSIX standard, and they are not supported by this implementation. However, they will not generate any errors. Instead you will get a result you don't expect. For example:

        v=3; v += 2  # v is 5 as you would expect
        v=3; v =+ 2  # v is 2 because the 2nd expression is seen as v = +2

COMPARISON TO GNU bc AND OTHERS

The following bc features are not supported in this implementation. (Some are syntactically accepted, but simply return zero).

        * -w, --warn option
        * -s, --standard option
        * -q, --quiet option
        * -v, --version option
        * long options (e.g. --help)
        * LC_ language and NLSPATH environment variables
        * "last" special variable
        * "if" statement: "else" clause
        * "read" function
        * "continue" statement
        * "halt" statement
        * "limits" pseudo statement
        * "warranty" pseudo statement
        * function definitions

In addition, the GNU implementation set the precedence of assignent below + and - and above relational operators (< > etc). This implementation seems to make it the lowest precedence (i.e. below ||), as most perl (and C) users would expect.

REFERENCES

POSIX bc https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html

GNU bc https://www.gnu.org/software/bc/manual/html_mono/bc.html

GNU's mathlib

Load the GNU math extensions with the -l switch:

        % bc -l FILE

The library provides these functions:

  • a(x) - the arctangent of X, where X is expressed in radians

  • c(x) - the cosine of X, where X is expressed in radians

  • e(X) - the natural base, e, raised to the X power

  • j(X) - the Bessel function of order X, where X is an integer

  • l(X) - the natural logarithm of X

  • s(x) - the sine of X, where X is expressed in radians

AUTHOR

Philip A. Nelson originally translated GNU bc to Perl for the PerlPowerTools project.

https://github.com/briandfoy/PerlPowerTools

LICENSE

You can use and modify this program under the terms of the GNU Public License version 2. A copy of this license is in the PerlPowerTools repository:

        https://github.com/briandfoy/PerlPowerTools/