NAME
bc - an arbitrary precision calculator language
SYNOPSIS
Run a bc program from FILE
bc [-bdiqswy] FILE...
Start an interactive bc session
bc [-bdiqswy]
DESCRIPTION
This is the PerlPowerTools implementation of the GNU version of bc, a standard 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
-l - use mathlib
-y - turn on parser 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
.
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 is 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.
print
LIST-
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 variablelast
. 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 orfor
statement. quit
-
When the
quit
statement is read, thebc
processor is terminated, regardless of where thequit
statement is found. For example,if (0 == 1) quit
will causebc
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/