1392 lines
43 KiB
Groff
1392 lines
43 KiB
Groff
.\"
|
|
.\" SPDX-License-Identifier: BSD-2-Clause
|
|
.\"
|
|
.\" Copyright (c) 2018-2021 Gavin D. Howard and contributors.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions are met:
|
|
.\"
|
|
.\" * Redistributions of source code must retain the above copyright notice,
|
|
.\" this list of conditions and the following disclaimer.
|
|
.\"
|
|
.\" * Redistributions in binary form must reproduce the above copyright notice,
|
|
.\" this list of conditions and the following disclaimer in the documentation
|
|
.\" and/or other materials provided with the distribution.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
|
.\"
|
|
.TH "BC" "1" "April 2021" "Gavin D. Howard" "General Commands Manual"
|
|
.SH NAME
|
|
.PP
|
|
bc - arbitrary-precision decimal arithmetic language and calculator
|
|
.SH SYNOPSIS
|
|
.PP
|
|
\f[B]bc\f[R] [\f[B]-ghilPqRsvVw\f[R]] [\f[B]--global-stacks\f[R]]
|
|
[\f[B]--help\f[R]] [\f[B]--interactive\f[R]] [\f[B]--mathlib\f[R]]
|
|
[\f[B]--no-prompt\f[R]] [\f[B]--no-read-prompt\f[R]] [\f[B]--quiet\f[R]]
|
|
[\f[B]--standard\f[R]] [\f[B]--warn\f[R]] [\f[B]--version\f[R]]
|
|
[\f[B]-e\f[R] \f[I]expr\f[R]] [\f[B]--expression\f[R]=\f[I]expr\f[R]...]
|
|
[\f[B]-f\f[R] \f[I]file\f[R]...] [\f[B]--file\f[R]=\f[I]file\f[R]...]
|
|
[\f[I]file\f[R]...]
|
|
.SH DESCRIPTION
|
|
.PP
|
|
bc(1) is an interactive processor for a language first standardized in
|
|
1991 by POSIX.
|
|
(The current standard is
|
|
here (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html).)
|
|
The language provides unlimited precision decimal arithmetic and is
|
|
somewhat C-like, but there are differences.
|
|
Such differences will be noted in this document.
|
|
.PP
|
|
After parsing and handling options, this bc(1) reads any files given on
|
|
the command line and executes them before reading from \f[B]stdin\f[R].
|
|
.SH OPTIONS
|
|
.PP
|
|
The following are the options that bc(1) accepts.
|
|
.PP
|
|
\f[B]-g\f[R], \f[B]--global-stacks\f[R]
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
|
|
|
This has the effect that a copy of the current value of all three are pushed
|
|
onto a stack for every function call, as well as popped when every function
|
|
returns. This means that functions can assign to any and all of those
|
|
globals without worrying that the change will affect other functions.
|
|
Thus, a hypothetical function named **output(x,b)** that simply printed
|
|
**x** in base **b** could be written like this:
|
|
|
|
define void output(x, b) {
|
|
obase=b
|
|
x
|
|
}
|
|
|
|
instead of like this:
|
|
|
|
define void output(x, b) {
|
|
auto c
|
|
c=obase
|
|
obase=b
|
|
x
|
|
obase=c
|
|
}
|
|
|
|
This makes writing functions much easier.
|
|
|
|
However, since using this flag means that functions cannot set **ibase**,
|
|
**obase**, or **scale** globally, functions that are made to do so cannot
|
|
work anymore. There are two possible use cases for that, and each has a
|
|
solution.
|
|
|
|
First, if a function is called on startup to turn bc(1) into a number
|
|
converter, it is possible to replace that capability with various shell
|
|
aliases. Examples:
|
|
|
|
alias d2o=\[dq]bc -e ibase=A -e obase=8\[dq]
|
|
alias h2b=\[dq]bc -e ibase=G -e obase=2\[dq]
|
|
|
|
Second, if the purpose of a function is to set **ibase**, **obase**, or
|
|
**scale** globally for any other purpose, it could be split into one to
|
|
three functions (based on how many globals it sets) and each of those
|
|
functions could return the desired value for a global.
|
|
|
|
If the behavior of this option is desired for every run of bc(1), then users
|
|
could make sure to define **BC_ENV_ARGS** and include this option (see the
|
|
**ENVIRONMENT VARIABLES** section for more details).
|
|
|
|
If **-s**, **-w**, or any equivalents are used, this option is ignored.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-h\f[R], \f[B]--help\f[R]
|
|
.PP
|
|
: Prints a usage message and quits.
|
|
.PP
|
|
\f[B]-i\f[R], \f[B]--interactive\f[R]
|
|
.PP
|
|
: Forces interactive mode.
|
|
(See the \f[B]INTERACTIVE MODE\f[R] section.)
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-l\f[R], \f[B]--mathlib\f[R]
|
|
.PP
|
|
: Sets \f[B]scale\f[R] (see the \f[B]SYNTAX\f[R] section) to
|
|
\f[B]20\f[R] and loads the included math library before running any
|
|
code, including any expressions or files specified on the command line.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
To learn what is in the library, see the **LIBRARY** section.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-P\f[R], \f[B]--no-prompt\f[R]
|
|
.PP
|
|
: Disables the prompt in TTY mode.
|
|
(The prompt is only enabled in TTY mode.
|
|
See the \f[B]TTY MODE\f[R] section.) This is mostly for those users that
|
|
do not want a prompt or are not used to having them in bc(1).
|
|
Most of those users would want to put this option in
|
|
\f[B]BC_ENV_ARGS\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R] section).
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-R\f[R], \f[B]--no-read-prompt\f[R]
|
|
.PP
|
|
: Disables the read prompt in TTY mode.
|
|
(The read prompt is only enabled in TTY mode.
|
|
See the \f[B]TTY MODE\f[R] section.) This is mostly for those users that
|
|
do not want a read prompt or are not used to having them in bc(1).
|
|
Most of those users would want to put this option in
|
|
\f[B]BC_ENV_ARGS\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R] section).
|
|
This option is also useful in hash bang lines of bc(1) scripts that
|
|
prompt for user input.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This option does not disable the regular prompt because the read prompt is
|
|
only used when the **read()** built-in function is called.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-q\f[R], \f[B]--quiet\f[R]
|
|
.PP
|
|
: This option is for compatibility with the GNU
|
|
bc(1) (https://www.gnu.org/software/bc/); it is a no-op.
|
|
Without this option, GNU bc(1) prints a copyright header.
|
|
This bc(1) only prints the copyright header if one or more of the
|
|
\f[B]-v\f[R], \f[B]-V\f[R], or \f[B]--version\f[R] options are given.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-s\f[R], \f[B]--standard\f[R]
|
|
.PP
|
|
: Process exactly the language defined by the
|
|
standard (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
|
|
and error if any extensions are used.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-v\f[R], \f[B]-V\f[R], \f[B]--version\f[R]
|
|
.PP
|
|
: Print the version information (copyright header) and exit.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-w\f[R], \f[B]--warn\f[R]
|
|
.PP
|
|
: Like \f[B]-s\f[R] and \f[B]--standard\f[R], except that warnings (and
|
|
not errors) are printed for non-standard extensions and execution
|
|
continues normally.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-e\f[R] \f[I]expr\f[R], \f[B]--expression\f[R]=\f[I]expr\f[R]
|
|
.PP
|
|
: Evaluates \f[I]expr\f[R].
|
|
If multiple expressions are given, they are evaluated in order.
|
|
If files are given as well (see below), the expressions and files are
|
|
evaluated in the order given.
|
|
This means that if a file is given before an expression, the file is
|
|
read in and evaluated first.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
If this option is given on the command-line (i.e., not in **BC_ENV_ARGS**,
|
|
see the **ENVIRONMENT VARIABLES** section), then after processing all
|
|
expressions and files, bc(1) will exit, unless **-** (**stdin**) was given
|
|
as an argument at least once to **-f** or **-\[rs]-file**, whether on the
|
|
command-line or in **BC_ENV_ARGS**. However, if any other **-e**,
|
|
**-\[rs]-expression**, **-f**, or **-\[rs]-file** arguments are given after **-f-**
|
|
or equivalent is given, bc(1) will give a fatal error and exit.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-f\f[R] \f[I]file\f[R], \f[B]--file\f[R]=\f[I]file\f[R]
|
|
.PP
|
|
: Reads in \f[I]file\f[R] and evaluates it, line by line, as though it
|
|
were read through \f[B]stdin\f[R].
|
|
If expressions are also given (see above), the expressions are evaluated
|
|
in the order given.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
If this option is given on the command-line (i.e., not in **BC_ENV_ARGS**,
|
|
see the **ENVIRONMENT VARIABLES** section), then after processing all
|
|
expressions and files, bc(1) will exit, unless **-** (**stdin**) was given
|
|
as an argument at least once to **-f** or **-\[rs]-file**. However, if any other
|
|
**-e**, **-\[rs]-expression**, **-f**, or **-\[rs]-file** arguments are given after
|
|
**-f-** or equivalent is given, bc(1) will give a fatal error and exit.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
All long options are \f[B]non-portable extensions\f[R].
|
|
.SH STDOUT
|
|
.PP
|
|
Any non-error output is written to \f[B]stdout\f[R].
|
|
In addition, if history (see the \f[B]HISTORY\f[R] section) and the
|
|
prompt (see the \f[B]TTY MODE\f[R] section) are enabled, both are output
|
|
to \f[B]stdout\f[R].
|
|
.PP
|
|
\f[B]Note\f[R]: Unlike other bc(1) implementations, this bc(1) will
|
|
issue a fatal error (see the \f[B]EXIT STATUS\f[R] section) if it cannot
|
|
write to \f[B]stdout\f[R], so if \f[B]stdout\f[R] is closed, as in
|
|
\f[B]bc >&-\f[R], it will quit with an error.
|
|
This is done so that bc(1) can report problems when \f[B]stdout\f[R] is
|
|
redirected to a file.
|
|
.PP
|
|
If there are scripts that depend on the behavior of other bc(1)
|
|
implementations, it is recommended that those scripts be changed to
|
|
redirect \f[B]stdout\f[R] to \f[B]/dev/null\f[R].
|
|
.SH STDERR
|
|
.PP
|
|
Any error output is written to \f[B]stderr\f[R].
|
|
.PP
|
|
\f[B]Note\f[R]: Unlike other bc(1) implementations, this bc(1) will
|
|
issue a fatal error (see the \f[B]EXIT STATUS\f[R] section) if it cannot
|
|
write to \f[B]stderr\f[R], so if \f[B]stderr\f[R] is closed, as in
|
|
\f[B]bc 2>&-\f[R], it will quit with an error.
|
|
This is done so that bc(1) can exit with an error code when
|
|
\f[B]stderr\f[R] is redirected to a file.
|
|
.PP
|
|
If there are scripts that depend on the behavior of other bc(1)
|
|
implementations, it is recommended that those scripts be changed to
|
|
redirect \f[B]stderr\f[R] to \f[B]/dev/null\f[R].
|
|
.SH SYNTAX
|
|
.PP
|
|
The syntax for bc(1) programs is mostly C-like, with some differences.
|
|
This bc(1) follows the POSIX
|
|
standard (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html),
|
|
which is a much more thorough resource for the language this bc(1)
|
|
accepts.
|
|
This section is meant to be a summary and a listing of all the
|
|
extensions to the standard.
|
|
.PP
|
|
In the sections below, \f[B]E\f[R] means expression, \f[B]S\f[R] means
|
|
statement, and \f[B]I\f[R] means identifier.
|
|
.PP
|
|
Identifiers (\f[B]I\f[R]) start with a lowercase letter and can be
|
|
followed by any number (up to \f[B]BC_NAME_MAX-1\f[R]) of lowercase
|
|
letters (\f[B]a-z\f[R]), digits (\f[B]0-9\f[R]), and underscores
|
|
(\f[B]_\f[R]).
|
|
The regex is \f[B][a-z][a-z0-9_]*\f[R].
|
|
Identifiers with more than one character (letter) are a
|
|
\f[B]non-portable extension\f[R].
|
|
.PP
|
|
\f[B]ibase\f[R] is a global variable determining how to interpret
|
|
constant numbers.
|
|
It is the \[dq]input\[dq] base, or the number base used for interpreting
|
|
input numbers.
|
|
\f[B]ibase\f[R] is initially \f[B]10\f[R].
|
|
If the \f[B]-s\f[R] (\f[B]--standard\f[R]) and \f[B]-w\f[R]
|
|
(\f[B]--warn\f[R]) flags were not given on the command line, the max
|
|
allowable value for \f[B]ibase\f[R] is \f[B]36\f[R].
|
|
Otherwise, it is \f[B]16\f[R].
|
|
The min allowable value for \f[B]ibase\f[R] is \f[B]2\f[R].
|
|
The max allowable value for \f[B]ibase\f[R] can be queried in bc(1)
|
|
programs with the \f[B]maxibase()\f[R] built-in function.
|
|
.PP
|
|
\f[B]obase\f[R] is a global variable determining how to output results.
|
|
It is the \[dq]output\[dq] base, or the number base used for outputting
|
|
numbers.
|
|
\f[B]obase\f[R] is initially \f[B]10\f[R].
|
|
The max allowable value for \f[B]obase\f[R] is \f[B]BC_BASE_MAX\f[R] and
|
|
can be queried in bc(1) programs with the \f[B]maxobase()\f[R] built-in
|
|
function.
|
|
The min allowable value for \f[B]obase\f[R] is \f[B]2\f[R].
|
|
Values are output in the specified base.
|
|
.PP
|
|
The \f[I]scale\f[R] of an expression is the number of digits in the
|
|
result of the expression right of the decimal point, and \f[B]scale\f[R]
|
|
is a global variable that sets the precision of any operations, with
|
|
exceptions.
|
|
\f[B]scale\f[R] is initially \f[B]0\f[R].
|
|
\f[B]scale\f[R] cannot be negative.
|
|
The max allowable value for \f[B]scale\f[R] is \f[B]BC_SCALE_MAX\f[R]
|
|
and can be queried in bc(1) programs with the \f[B]maxscale()\f[R]
|
|
built-in function.
|
|
.PP
|
|
bc(1) has both \f[I]global\f[R] variables and \f[I]local\f[R] variables.
|
|
All \f[I]local\f[R] variables are local to the function; they are
|
|
parameters or are introduced in the \f[B]auto\f[R] list of a function
|
|
(see the \f[B]FUNCTIONS\f[R] section).
|
|
If a variable is accessed which is not a parameter or in the
|
|
\f[B]auto\f[R] list, it is assumed to be \f[I]global\f[R].
|
|
If a parent function has a \f[I]local\f[R] variable version of a
|
|
variable that a child function considers \f[I]global\f[R], the value of
|
|
that \f[I]global\f[R] variable in the child function is the value of the
|
|
variable in the parent function, not the value of the actual
|
|
\f[I]global\f[R] variable.
|
|
.PP
|
|
All of the above applies to arrays as well.
|
|
.PP
|
|
The value of a statement that is an expression (i.e., any of the named
|
|
expressions or operands) is printed unless the lowest precedence
|
|
operator is an assignment operator \f[I]and\f[R] the expression is
|
|
notsurrounded by parentheses.
|
|
.PP
|
|
The value that is printed is also assigned to the special variable
|
|
\f[B]last\f[R].
|
|
A single dot (\f[B].\f[R]) may also be used as a synonym for
|
|
\f[B]last\f[R].
|
|
These are \f[B]non-portable extensions\f[R].
|
|
.PP
|
|
Either semicolons or newlines may separate statements.
|
|
.SS Comments
|
|
.PP
|
|
There are two kinds of comments:
|
|
.IP "1." 3
|
|
Block comments are enclosed in \f[B]/*\f[R] and \f[B]*/\f[R].
|
|
.IP "2." 3
|
|
Line comments go from \f[B]#\f[R] until, and not including, the next
|
|
newline.
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.SS Named Expressions
|
|
.PP
|
|
The following are named expressions in bc(1):
|
|
.IP "1." 3
|
|
Variables: \f[B]I\f[R]
|
|
.IP "2." 3
|
|
Array Elements: \f[B]I[E]\f[R]
|
|
.IP "3." 3
|
|
\f[B]ibase\f[R]
|
|
.IP "4." 3
|
|
\f[B]obase\f[R]
|
|
.IP "5." 3
|
|
\f[B]scale\f[R]
|
|
.IP "6." 3
|
|
\f[B]last\f[R] or a single dot (\f[B].\f[R])
|
|
.PP
|
|
Number 6 is a \f[B]non-portable extension\f[R].
|
|
.PP
|
|
Variables and arrays do not interfere; users can have arrays named the
|
|
same as variables.
|
|
This also applies to functions (see the \f[B]FUNCTIONS\f[R] section), so
|
|
a user can have a variable, array, and function that all have the same
|
|
name, and they will not shadow each other, whether inside of functions
|
|
or not.
|
|
.PP
|
|
Named expressions are required as the operand of
|
|
\f[B]increment\f[R]/\f[B]decrement\f[R] operators and as the left side
|
|
of \f[B]assignment\f[R] operators (see the \f[I]Operators\f[R]
|
|
subsection).
|
|
.SS Operands
|
|
.PP
|
|
The following are valid operands in bc(1):
|
|
.IP " 1." 4
|
|
Numbers (see the \f[I]Numbers\f[R] subsection below).
|
|
.IP " 2." 4
|
|
Array indices (\f[B]I[E]\f[R]).
|
|
.IP " 3." 4
|
|
\f[B](E)\f[R]: The value of \f[B]E\f[R] (used to change precedence).
|
|
.IP " 4." 4
|
|
\f[B]sqrt(E)\f[R]: The square root of \f[B]E\f[R].
|
|
\f[B]E\f[R] must be non-negative.
|
|
.IP " 5." 4
|
|
\f[B]length(E)\f[R]: The number of significant decimal digits in
|
|
\f[B]E\f[R].
|
|
.IP " 6." 4
|
|
\f[B]length(I[])\f[R]: The number of elements in the array \f[B]I\f[R].
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.IP " 7." 4
|
|
\f[B]scale(E)\f[R]: The \f[I]scale\f[R] of \f[B]E\f[R].
|
|
.IP " 8." 4
|
|
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.IP " 9." 4
|
|
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
|
|
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
|
|
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
|
|
The \f[B]E\f[R] argument(s) may also be arrays of the form
|
|
\f[B]I[]\f[R], which will automatically be turned into array references
|
|
(see the \f[I]Array References\f[R] subsection of the
|
|
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
|
|
function definition is an array reference.
|
|
.IP "10." 4
|
|
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
|
|
expression.
|
|
The result of that expression is the result of the \f[B]read()\f[R]
|
|
operand.
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.IP "11." 4
|
|
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.IP "12." 4
|
|
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.IP "13." 4
|
|
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.SS Numbers
|
|
.PP
|
|
Numbers are strings made up of digits, uppercase letters, and at most
|
|
\f[B]1\f[R] period for a radix.
|
|
Numbers can have up to \f[B]BC_NUM_MAX\f[R] digits.
|
|
Uppercase letters are equal to \f[B]9\f[R] + their position in the
|
|
alphabet (i.e., \f[B]A\f[R] equals \f[B]10\f[R], or \f[B]9+1\f[R]).
|
|
If a digit or letter makes no sense with the current value of
|
|
\f[B]ibase\f[R], they are set to the value of the highest valid digit in
|
|
\f[B]ibase\f[R].
|
|
.PP
|
|
Single-character numbers (i.e., \f[B]A\f[R] alone) take the value that
|
|
they would have if they were valid digits, regardless of the value of
|
|
\f[B]ibase\f[R].
|
|
This means that \f[B]A\f[R] alone always equals decimal \f[B]10\f[R] and
|
|
\f[B]Z\f[R] alone always equals decimal \f[B]35\f[R].
|
|
.SS Operators
|
|
.PP
|
|
The following arithmetic and logical operators can be used.
|
|
They are listed in order of decreasing precedence.
|
|
Operators in the same group have the same precedence.
|
|
.PP
|
|
\f[B]++\f[R] \f[B]--\f[R]
|
|
.PP
|
|
: Type: Prefix and Postfix
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: None
|
|
|
|
Description: **increment**, **decrement**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-\f[R] \f[B]!\f[R]
|
|
.PP
|
|
: Type: Prefix
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: None
|
|
|
|
Description: **negation**, **boolean not**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]\[ha]\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Right
|
|
|
|
Description: **power**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]*\f[R] \f[B]/\f[R] \f[B]%\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Left
|
|
|
|
Description: **multiply**, **divide**, **modulus**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]+\f[R] \f[B]-\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Left
|
|
|
|
Description: **add**, **subtract**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]=\f[R] \f[B]+=\f[R] \f[B]-=\f[R] \f[B]*=\f[R] \f[B]/=\f[R]
|
|
\f[B]%=\f[R] \f[B]\[ha]=\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Right
|
|
|
|
Description: **assignment**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]==\f[R] \f[B]<=\f[R] \f[B]>=\f[R] \f[B]!=\f[R] \f[B]<\f[R]
|
|
\f[B]>\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Left
|
|
|
|
Description: **relational**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]&&\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Left
|
|
|
|
Description: **boolean and**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]||\f[R]
|
|
.PP
|
|
: Type: Binary
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Associativity: Left
|
|
|
|
Description: **boolean or**
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
The operators will be described in more detail below.
|
|
.PP
|
|
\f[B]++\f[R] \f[B]--\f[R]
|
|
.PP
|
|
: The prefix and postfix \f[B]increment\f[R] and \f[B]decrement\f[R]
|
|
operators behave exactly like they would in C.
|
|
They require a named expression (see the \f[I]Named Expressions\f[R]
|
|
subsection) as an operand.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
The prefix versions of these operators are more efficient; use them where
|
|
possible.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]-\f[R]
|
|
.PP
|
|
: The \f[B]negation\f[R] operator returns \f[B]0\f[R] if a user attempts
|
|
to negate any expression with the value \f[B]0\f[R].
|
|
Otherwise, a copy of the expression with its sign flipped is returned.
|
|
.PP
|
|
\f[B]!\f[R]
|
|
.PP
|
|
: The \f[B]boolean not\f[R] operator returns \f[B]1\f[R] if the
|
|
expression is \f[B]0\f[R], or \f[B]0\f[R] otherwise.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]\[ha]\f[R]
|
|
.PP
|
|
: The \f[B]power\f[R] operator (not the \f[B]exclusive or\f[R] operator,
|
|
as it would be in C) takes two expressions and raises the first to the
|
|
power of the value of the second.
|
|
The \f[I]scale\f[R] of the result is equal to \f[B]scale\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
The second expression must be an integer (no *scale*), and if it is
|
|
negative, the first value must be non-zero.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]*\f[R]
|
|
.PP
|
|
: The \f[B]multiply\f[R] operator takes two expressions, multiplies
|
|
them, and returns the product.
|
|
If \f[B]a\f[R] is the \f[I]scale\f[R] of the first expression and
|
|
\f[B]b\f[R] is the \f[I]scale\f[R] of the second expression, the
|
|
\f[I]scale\f[R] of the result is equal to
|
|
\f[B]min(a+b,max(scale,a,b))\f[R] where \f[B]min()\f[R] and
|
|
\f[B]max()\f[R] return the obvious values.
|
|
.PP
|
|
\f[B]/\f[R]
|
|
.PP
|
|
: The \f[B]divide\f[R] operator takes two expressions, divides them, and
|
|
returns the quotient.
|
|
The \f[I]scale\f[R] of the result shall be the value of \f[B]scale\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
The second expression must be non-zero.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]%\f[R]
|
|
.PP
|
|
: The \f[B]modulus\f[R] operator takes two expressions, \f[B]a\f[R] and
|
|
\f[B]b\f[R], and evaluates them by 1) Computing \f[B]a/b\f[R] to current
|
|
\f[B]scale\f[R] and 2) Using the result of step 1 to calculate
|
|
\f[B]a-(a/b)*b\f[R] to \f[I]scale\f[R]
|
|
\f[B]max(scale+scale(b),scale(a))\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
The second expression must be non-zero.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]+\f[R]
|
|
.PP
|
|
: The \f[B]add\f[R] operator takes two expressions, \f[B]a\f[R] and
|
|
\f[B]b\f[R], and returns the sum, with a \f[I]scale\f[R] equal to the
|
|
max of the \f[I]scale\f[R]s of \f[B]a\f[R] and \f[B]b\f[R].
|
|
.PP
|
|
\f[B]-\f[R]
|
|
.PP
|
|
: The \f[B]subtract\f[R] operator takes two expressions, \f[B]a\f[R] and
|
|
\f[B]b\f[R], and returns the difference, with a \f[I]scale\f[R] equal to
|
|
the max of the \f[I]scale\f[R]s of \f[B]a\f[R] and \f[B]b\f[R].
|
|
.PP
|
|
\f[B]=\f[R] \f[B]+=\f[R] \f[B]-=\f[R] \f[B]*=\f[R] \f[B]/=\f[R]
|
|
\f[B]%=\f[R] \f[B]\[ha]=\f[R]
|
|
.PP
|
|
: The \f[B]assignment\f[R] operators take two expressions, \f[B]a\f[R]
|
|
and \f[B]b\f[R] where \f[B]a\f[R] is a named expression (see the
|
|
\f[I]Named Expressions\f[R] subsection).
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
For **=**, **b** is copied and the result is assigned to **a**. For all
|
|
others, **a** and **b** are applied as operands to the corresponding
|
|
arithmetic operator and the result is assigned to **a**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]==\f[R] \f[B]<=\f[R] \f[B]>=\f[R] \f[B]!=\f[R] \f[B]<\f[R]
|
|
\f[B]>\f[R]
|
|
.PP
|
|
: The \f[B]relational\f[R] operators compare two expressions,
|
|
\f[B]a\f[R] and \f[B]b\f[R], and if the relation holds, according to C
|
|
language semantics, the result is \f[B]1\f[R].
|
|
Otherwise, it is \f[B]0\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Note that unlike in C, these operators have a lower precedence than the
|
|
**assignment** operators, which means that **a=b\[rs]>c** is interpreted as
|
|
**(a=b)\[rs]>c**.
|
|
|
|
Also, unlike the [standard][1] requires, these operators can appear anywhere
|
|
any other expressions can be used. This allowance is a
|
|
**non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]&&\f[R]
|
|
.PP
|
|
: The \f[B]boolean and\f[R] operator takes two expressions and returns
|
|
\f[B]1\f[R] if both expressions are non-zero, \f[B]0\f[R] otherwise.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is *not* a short-circuit operator.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]||\f[R]
|
|
.PP
|
|
: The \f[B]boolean or\f[R] operator takes two expressions and returns
|
|
\f[B]1\f[R] if one of the expressions is non-zero, \f[B]0\f[R]
|
|
otherwise.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is *not* a short-circuit operator.
|
|
|
|
This is a **non-portable extension**.
|
|
\f[R]
|
|
.fi
|
|
.SS Statements
|
|
.PP
|
|
The following items are statements:
|
|
.IP " 1." 4
|
|
\f[B]E\f[R]
|
|
.IP " 2." 4
|
|
\f[B]{\f[R] \f[B]S\f[R] \f[B];\f[R] ...
|
|
\f[B];\f[R] \f[B]S\f[R] \f[B]}\f[R]
|
|
.IP " 3." 4
|
|
\f[B]if\f[R] \f[B](\f[R] \f[B]E\f[R] \f[B])\f[R] \f[B]S\f[R]
|
|
.IP " 4." 4
|
|
\f[B]if\f[R] \f[B](\f[R] \f[B]E\f[R] \f[B])\f[R] \f[B]S\f[R]
|
|
\f[B]else\f[R] \f[B]S\f[R]
|
|
.IP " 5." 4
|
|
\f[B]while\f[R] \f[B](\f[R] \f[B]E\f[R] \f[B])\f[R] \f[B]S\f[R]
|
|
.IP " 6." 4
|
|
\f[B]for\f[R] \f[B](\f[R] \f[B]E\f[R] \f[B];\f[R] \f[B]E\f[R]
|
|
\f[B];\f[R] \f[B]E\f[R] \f[B])\f[R] \f[B]S\f[R]
|
|
.IP " 7." 4
|
|
An empty statement
|
|
.IP " 8." 4
|
|
\f[B]break\f[R]
|
|
.IP " 9." 4
|
|
\f[B]continue\f[R]
|
|
.IP "10." 4
|
|
\f[B]quit\f[R]
|
|
.IP "11." 4
|
|
\f[B]halt\f[R]
|
|
.IP "12." 4
|
|
\f[B]limits\f[R]
|
|
.IP "13." 4
|
|
A string of characters, enclosed in double quotes
|
|
.IP "14." 4
|
|
\f[B]print\f[R] \f[B]E\f[R] \f[B],\f[R] ...
|
|
\f[B],\f[R] \f[B]E\f[R]
|
|
.IP "15." 4
|
|
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
|
|
\f[B]I\f[R] is an identifier for a \f[B]void\f[R] function (see the
|
|
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
|
|
The \f[B]E\f[R] argument(s) may also be arrays of the form
|
|
\f[B]I[]\f[R], which will automatically be turned into array references
|
|
(see the \f[I]Array References\f[R] subsection of the
|
|
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
|
|
function definition is an array reference.
|
|
.PP
|
|
Numbers 4, 9, 11, 12, 14, and 15 are \f[B]non-portable extensions\f[R].
|
|
.PP
|
|
Also, as a \f[B]non-portable extension\f[R], any or all of the
|
|
expressions in the header of a for loop may be omitted.
|
|
If the condition (second expression) is omitted, it is assumed to be a
|
|
constant \f[B]1\f[R].
|
|
.PP
|
|
The \f[B]break\f[R] statement causes a loop to stop iterating and resume
|
|
execution immediately following a loop.
|
|
This is only allowed in loops.
|
|
.PP
|
|
The \f[B]continue\f[R] statement causes a loop iteration to stop early
|
|
and returns to the start of the loop, including testing the loop
|
|
condition.
|
|
This is only allowed in loops.
|
|
.PP
|
|
The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
|
|
.PP
|
|
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
|
|
branch that will not be executed (it is a compile-time command).
|
|
.PP
|
|
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
|
|
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
|
|
that is not executed, bc(1) does not quit.)
|
|
.PP
|
|
The \f[B]limits\f[R] statement prints the limits that this bc(1) is
|
|
subject to.
|
|
This is like the \f[B]quit\f[R] statement in that it is a compile-time
|
|
command.
|
|
.PP
|
|
An expression by itself is evaluated and printed, followed by a newline.
|
|
.SS Print Statement
|
|
.PP
|
|
The \[dq]expressions\[dq] in a \f[B]print\f[R] statement may also be
|
|
strings.
|
|
If they are, there are backslash escape sequences that are interpreted
|
|
specially.
|
|
What those sequences are, and what they cause to be printed, are shown
|
|
below:
|
|
.PP
|
|
* * * * *
|
|
.PP
|
|
\f[B]\[rs]a\f[R] \f[B]\[rs]a\f[R] \f[B]\[rs]b\f[R] \f[B]\[rs]b\f[R]
|
|
\f[B]\[rs]\[rs]\f[R] \f[B]\[rs]\f[R] \f[B]\[rs]e\f[R] \f[B]\[rs]\f[R]
|
|
\f[B]\[rs]f\f[R] \f[B]\[rs]f\f[R] \f[B]\[rs]n\f[R] \f[B]\[rs]n\f[R]
|
|
\f[B]\[rs]q\f[R] \f[B]\[dq]\f[R] \f[B]\[rs]r\f[R] \f[B]\[rs]r\f[R]
|
|
\f[B]\[rs]t\f[R] \f[B]\[rs]t\f[R]
|
|
.PP
|
|
* * * * *
|
|
.PP
|
|
Any other character following a backslash causes the backslash and
|
|
character to be printed as-is.
|
|
.PP
|
|
Any non-string expression in a print statement shall be assigned to
|
|
\f[B]last\f[R], like any other expression that is printed.
|
|
.SS Order of Evaluation
|
|
.PP
|
|
All expressions in a statment are evaluated left to right, except as
|
|
necessary to maintain order of operations.
|
|
This means, for example, assuming that \f[B]i\f[R] is equal to
|
|
\f[B]0\f[R], in the expression
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
a[i++] = i++
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
the first (or 0th) element of \f[B]a\f[R] is set to \f[B]1\f[R], and
|
|
\f[B]i\f[R] is equal to \f[B]2\f[R] at the end of the expression.
|
|
.PP
|
|
This includes function arguments.
|
|
Thus, assuming \f[B]i\f[R] is equal to \f[B]0\f[R], this means that in
|
|
the expression
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
x(i++, i++)
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
the first argument passed to \f[B]x()\f[R] is \f[B]0\f[R], and the
|
|
second argument is \f[B]1\f[R], while \f[B]i\f[R] is equal to
|
|
\f[B]2\f[R] before the function starts executing.
|
|
.SH FUNCTIONS
|
|
.PP
|
|
Function definitions are as follows:
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
define I(I,...,I){
|
|
auto I,...,I
|
|
S;...;S
|
|
return(E)
|
|
}
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
Any \f[B]I\f[R] in the parameter list or \f[B]auto\f[R] list may be
|
|
replaced with \f[B]I[]\f[R] to make a parameter or \f[B]auto\f[R] var an
|
|
array, and any \f[B]I\f[R] in the parameter list may be replaced with
|
|
\f[B]*I[]\f[R] to make a parameter an array reference.
|
|
Callers of functions that take array references should not put an
|
|
asterisk in the call; they must be called with just \f[B]I[]\f[R] like
|
|
normal array parameters and will be automatically converted into
|
|
references.
|
|
.PP
|
|
As a \f[B]non-portable extension\f[R], the opening brace of a
|
|
\f[B]define\f[R] statement may appear on the next line.
|
|
.PP
|
|
As a \f[B]non-portable extension\f[R], the return statement may also be
|
|
in one of the following forms:
|
|
.IP "1." 3
|
|
\f[B]return\f[R]
|
|
.IP "2." 3
|
|
\f[B]return\f[R] \f[B](\f[R] \f[B])\f[R]
|
|
.IP "3." 3
|
|
\f[B]return\f[R] \f[B]E\f[R]
|
|
.PP
|
|
The first two, or not specifying a \f[B]return\f[R] statement, is
|
|
equivalent to \f[B]return (0)\f[R], unless the function is a
|
|
\f[B]void\f[R] function (see the \f[I]Void Functions\f[R] subsection
|
|
below).
|
|
.SS Void Functions
|
|
.PP
|
|
Functions can also be \f[B]void\f[R] functions, defined as follows:
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
define void I(I,...,I){
|
|
auto I,...,I
|
|
S;...;S
|
|
return
|
|
}
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
They can only be used as standalone expressions, where such an
|
|
expression would be printed alone, except in a print statement.
|
|
.PP
|
|
Void functions can only use the first two \f[B]return\f[R] statements
|
|
listed above.
|
|
They can also omit the return statement entirely.
|
|
.PP
|
|
The word \[dq]void\[dq] is not treated as a keyword; it is still
|
|
possible to have variables, arrays, and functions named \f[B]void\f[R].
|
|
The word \[dq]void\[dq] is only treated specially right after the
|
|
\f[B]define\f[R] keyword.
|
|
.PP
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.SS Array References
|
|
.PP
|
|
For any array in the parameter list, if the array is declared in the
|
|
form
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
*I[]
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
it is a \f[B]reference\f[R].
|
|
Any changes to the array in the function are reflected, when the
|
|
function returns, to the array that was passed in.
|
|
.PP
|
|
Other than this, all function arguments are passed by value.
|
|
.PP
|
|
This is a \f[B]non-portable extension\f[R].
|
|
.SH LIBRARY
|
|
.PP
|
|
All of the functions below are available when the \f[B]-l\f[R] or
|
|
\f[B]--mathlib\f[R] command-line flags are given.
|
|
.SS Standard Library
|
|
.PP
|
|
The
|
|
standard (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
|
|
defines the following functions for the math library:
|
|
.PP
|
|
\f[B]s(x)\f[R]
|
|
.PP
|
|
: Returns the sine of \f[B]x\f[R], which is assumed to be in radians.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]c(x)\f[R]
|
|
.PP
|
|
: Returns the cosine of \f[B]x\f[R], which is assumed to be in radians.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]a(x)\f[R]
|
|
.PP
|
|
: Returns the arctangent of \f[B]x\f[R], in radians.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]l(x)\f[R]
|
|
.PP
|
|
: Returns the natural logarithm of \f[B]x\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]e(x)\f[R]
|
|
.PP
|
|
: Returns the mathematical constant \f[B]e\f[R] raised to the power of
|
|
\f[B]x\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]j(x, n)\f[R]
|
|
.PP
|
|
: Returns the bessel integer order \f[B]n\f[R] (truncated) of
|
|
\f[B]x\f[R].
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
This is a transcendental function (see the *Transcendental Functions*
|
|
subsection below).
|
|
\f[R]
|
|
.fi
|
|
.SS Transcendental Functions
|
|
.PP
|
|
All transcendental functions can return slightly inaccurate results (up
|
|
to 1 ULP (https://en.wikipedia.org/wiki/Unit_in_the_last_place)).
|
|
This is unavoidable, and this
|
|
article (https://people.eecs.berkeley.edu/~wkahan/LOG10HAF.TXT) explains
|
|
why it is impossible and unnecessary to calculate exact results for the
|
|
transcendental functions.
|
|
.PP
|
|
Because of the possible inaccuracy, I recommend that users call those
|
|
functions with the precision (\f[B]scale\f[R]) set to at least 1 higher
|
|
than is necessary.
|
|
If exact results are \f[I]absolutely\f[R] required, users can double the
|
|
precision (\f[B]scale\f[R]) and then truncate.
|
|
.PP
|
|
The transcendental functions in the standard math library are:
|
|
.IP \[bu] 2
|
|
\f[B]s(x)\f[R]
|
|
.IP \[bu] 2
|
|
\f[B]c(x)\f[R]
|
|
.IP \[bu] 2
|
|
\f[B]a(x)\f[R]
|
|
.IP \[bu] 2
|
|
\f[B]l(x)\f[R]
|
|
.IP \[bu] 2
|
|
\f[B]e(x)\f[R]
|
|
.IP \[bu] 2
|
|
\f[B]j(x, n)\f[R]
|
|
.SH RESET
|
|
.PP
|
|
When bc(1) encounters an error or a signal that it has a non-default
|
|
handler for, it resets.
|
|
This means that several things happen.
|
|
.PP
|
|
First, any functions that are executing are stopped and popped off the
|
|
stack.
|
|
The behavior is not unlike that of exceptions in programming languages.
|
|
Then the execution point is set so that any code waiting to execute
|
|
(after all functions returned) is skipped.
|
|
.PP
|
|
Thus, when bc(1) resets, it skips any remaining code waiting to be
|
|
executed.
|
|
Then, if it is interactive mode, and the error was not a fatal error
|
|
(see the \f[B]EXIT STATUS\f[R] section), it asks for more input;
|
|
otherwise, it exits with the appropriate return code.
|
|
.PP
|
|
Note that this reset behavior is different from the GNU bc(1), which
|
|
attempts to start executing the statement right after the one that
|
|
caused an error.
|
|
.SH PERFORMANCE
|
|
.PP
|
|
Most bc(1) implementations use \f[B]char\f[R] types to calculate the
|
|
value of \f[B]1\f[R] decimal digit at a time, but that can be slow.
|
|
This bc(1) does something different.
|
|
.PP
|
|
It uses large integers to calculate more than \f[B]1\f[R] decimal digit
|
|
at a time.
|
|
If built in a environment where \f[B]BC_LONG_BIT\f[R] (see the
|
|
\f[B]LIMITS\f[R] section) is \f[B]64\f[R], then each integer has
|
|
\f[B]9\f[R] decimal digits.
|
|
If built in an environment where \f[B]BC_LONG_BIT\f[R] is \f[B]32\f[R]
|
|
then each integer has \f[B]4\f[R] decimal digits.
|
|
This value (the number of decimal digits per large integer) is called
|
|
\f[B]BC_BASE_DIGS\f[R].
|
|
.PP
|
|
The actual values of \f[B]BC_LONG_BIT\f[R] and \f[B]BC_BASE_DIGS\f[R]
|
|
can be queried with the \f[B]limits\f[R] statement.
|
|
.PP
|
|
In addition, this bc(1) uses an even larger integer for overflow
|
|
checking.
|
|
This integer type depends on the value of \f[B]BC_LONG_BIT\f[R], but is
|
|
always at least twice as large as the integer type used to store digits.
|
|
.SH LIMITS
|
|
.PP
|
|
The following are the limits on bc(1):
|
|
.PP
|
|
\f[B]BC_LONG_BIT\f[R]
|
|
.PP
|
|
: The number of bits in the \f[B]long\f[R] type in the environment where
|
|
bc(1) was built.
|
|
This determines how many decimal digits can be stored in a single large
|
|
integer (see the \f[B]PERFORMANCE\f[R] section).
|
|
.PP
|
|
\f[B]BC_BASE_DIGS\f[R]
|
|
.PP
|
|
: The number of decimal digits per large integer (see the
|
|
\f[B]PERFORMANCE\f[R] section).
|
|
Depends on \f[B]BC_LONG_BIT\f[R].
|
|
.PP
|
|
\f[B]BC_BASE_POW\f[R]
|
|
.PP
|
|
: The max decimal number that each large integer can store (see
|
|
\f[B]BC_BASE_DIGS\f[R]) plus \f[B]1\f[R].
|
|
Depends on \f[B]BC_BASE_DIGS\f[R].
|
|
.PP
|
|
\f[B]BC_OVERFLOW_MAX\f[R]
|
|
.PP
|
|
: The max number that the overflow type (see the \f[B]PERFORMANCE\f[R]
|
|
section) can hold.
|
|
Depends on \f[B]BC_LONG_BIT\f[R].
|
|
.PP
|
|
\f[B]BC_BASE_MAX\f[R]
|
|
.PP
|
|
: The maximum output base.
|
|
Set at \f[B]BC_BASE_POW\f[R].
|
|
.PP
|
|
\f[B]BC_DIM_MAX\f[R]
|
|
.PP
|
|
: The maximum size of arrays.
|
|
Set at \f[B]SIZE_MAX-1\f[R].
|
|
.PP
|
|
\f[B]BC_SCALE_MAX\f[R]
|
|
.PP
|
|
: The maximum \f[B]scale\f[R].
|
|
Set at \f[B]BC_OVERFLOW_MAX-1\f[R].
|
|
.PP
|
|
\f[B]BC_STRING_MAX\f[R]
|
|
.PP
|
|
: The maximum length of strings.
|
|
Set at \f[B]BC_OVERFLOW_MAX-1\f[R].
|
|
.PP
|
|
\f[B]BC_NAME_MAX\f[R]
|
|
.PP
|
|
: The maximum length of identifiers.
|
|
Set at \f[B]BC_OVERFLOW_MAX-1\f[R].
|
|
.PP
|
|
\f[B]BC_NUM_MAX\f[R]
|
|
.PP
|
|
: The maximum length of a number (in decimal digits), which includes
|
|
digits after the decimal point.
|
|
Set at \f[B]BC_OVERFLOW_MAX-1\f[R].
|
|
.PP
|
|
Exponent
|
|
.PP
|
|
: The maximum allowable exponent (positive or negative).
|
|
Set at \f[B]BC_OVERFLOW_MAX\f[R].
|
|
.PP
|
|
Number of vars
|
|
.PP
|
|
: The maximum number of vars/arrays.
|
|
Set at \f[B]SIZE_MAX-1\f[R].
|
|
.PP
|
|
The actual values can be queried with the \f[B]limits\f[R] statement.
|
|
.PP
|
|
These limits are meant to be effectively non-existent; the limits are so
|
|
large (at least on 64-bit machines) that there should not be any point
|
|
at which they become a problem.
|
|
In fact, memory should be exhausted before these limits should be hit.
|
|
.SH ENVIRONMENT VARIABLES
|
|
.PP
|
|
bc(1) recognizes the following environment variables:
|
|
.PP
|
|
\f[B]POSIXLY_CORRECT\f[R]
|
|
.PP
|
|
: If this variable exists (no matter the contents), bc(1) behaves as if
|
|
the \f[B]-s\f[R] option was given.
|
|
.PP
|
|
\f[B]BC_ENV_ARGS\f[R]
|
|
.PP
|
|
: This is another way to give command-line arguments to bc(1).
|
|
They should be in the same format as all other command-line arguments.
|
|
These are always processed first, so any files given in
|
|
\f[B]BC_ENV_ARGS\f[R] will be processed before arguments and files given
|
|
on the command-line.
|
|
This gives the user the ability to set up \[dq]standard\[dq] options and
|
|
files to be used at every invocation.
|
|
The most useful thing for such files to contain would be useful
|
|
functions that the user might want every time bc(1) runs.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
The code that parses **BC_ENV_ARGS** will correctly handle quoted arguments,
|
|
but it does not understand escape sequences. For example, the string
|
|
**\[dq]/home/gavin/some bc file.bc\[dq]** will be correctly parsed, but the string
|
|
**\[dq]/home/gavin/some \[rs]\[dq]bc\[rs]\[dq] file.bc\[dq]** will include the backslashes.
|
|
|
|
The quote parsing will handle either kind of quotes, **\[aq]** or **\[dq]**. Thus,
|
|
if you have a file with any number of single quotes in the name, you can use
|
|
double quotes as the outside quotes, as in **\[dq]some \[aq]bc\[aq] file.bc\[dq]**, and vice
|
|
versa if you have a file with double quotes. However, handling a file with
|
|
both kinds of quotes in **BC_ENV_ARGS** is not supported due to the
|
|
complexity of the parsing, though such files are still supported on the
|
|
command-line where the parsing is done by the shell.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]BC_LINE_LENGTH\f[R]
|
|
.PP
|
|
: If this environment variable exists and contains an integer that is
|
|
greater than \f[B]1\f[R] and is less than \f[B]UINT16_MAX\f[R]
|
|
(\f[B]2\[ha]16-1\f[R]), bc(1) will output lines to that length,
|
|
including the backslash (\f[B]\[rs]\f[R]).
|
|
The default line length is \f[B]70\f[R].
|
|
.SH EXIT STATUS
|
|
.PP
|
|
bc(1) returns the following exit statuses:
|
|
.PP
|
|
\f[B]0\f[R]
|
|
.PP
|
|
: No error.
|
|
.PP
|
|
\f[B]1\f[R]
|
|
.PP
|
|
: A math error occurred.
|
|
This follows standard practice of using \f[B]1\f[R] for expected errors,
|
|
since math errors will happen in the process of normal execution.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Math errors include divide by **0**, taking the square root of a negative
|
|
number, attempting to convert a negative number to a hardware integer,
|
|
overflow when converting a number to a hardware integer, and attempting to
|
|
use a non-integer where an integer is required.
|
|
|
|
Converting to a hardware integer happens for the second operand of the power
|
|
(**\[rs]\[ha]**) operator and the corresponding assignment operator.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]2\f[R]
|
|
.PP
|
|
: A parse error occurred.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Parse errors include unexpected **EOF**, using an invalid character, failing
|
|
to find the end of a string or comment, using a token where it is invalid,
|
|
giving an invalid expression, giving an invalid print statement, giving an
|
|
invalid function definition, attempting to assign to an expression that is
|
|
not a named expression (see the *Named Expressions* subsection of the
|
|
**SYNTAX** section), giving an invalid **auto** list, having a duplicate
|
|
**auto**/function parameter, failing to find the end of a code block,
|
|
attempting to return a value from a **void** function, attempting to use a
|
|
variable as a reference, and using any extensions when the option **-s** or
|
|
any equivalents were given.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]3\f[R]
|
|
.PP
|
|
: A runtime error occurred.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
|
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
|
inside of a **read()** call, type errors, passing the wrong number of
|
|
arguments to functions, attempting to call an undefined function, and
|
|
attempting to use a **void** function call as a value in an expression.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
\f[B]4\f[R]
|
|
.PP
|
|
: A fatal error occurred.
|
|
.IP
|
|
.nf
|
|
\f[C]
|
|
Fatal errors include memory allocation errors, I/O errors, failing to open
|
|
files, attempting to use files that do not have only ASCII characters (bc(1)
|
|
only accepts ASCII characters), attempting to open a directory as a file,
|
|
and giving invalid command-line options.
|
|
\f[R]
|
|
.fi
|
|
.PP
|
|
The exit status \f[B]4\f[R] is special; when a fatal error occurs, bc(1)
|
|
always exits and returns \f[B]4\f[R], no matter what mode bc(1) is in.
|
|
.PP
|
|
The other statuses will only be returned when bc(1) is not in
|
|
interactive mode (see the \f[B]INTERACTIVE MODE\f[R] section), since
|
|
bc(1) resets its state (see the \f[B]RESET\f[R] section) and accepts
|
|
more input when one of those errors occurs in interactive mode.
|
|
This is also the case when interactive mode is forced by the
|
|
\f[B]-i\f[R] flag or \f[B]--interactive\f[R] option.
|
|
.PP
|
|
These exit statuses allow bc(1) to be used in shell scripting with error
|
|
checking, and its normal behavior can be forced by using the
|
|
\f[B]-i\f[R] flag or \f[B]--interactive\f[R] option.
|
|
.SH INTERACTIVE MODE
|
|
.PP
|
|
Per the
|
|
standard (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html),
|
|
bc(1) has an interactive mode and a non-interactive mode.
|
|
Interactive mode is turned on automatically when both \f[B]stdin\f[R]
|
|
and \f[B]stdout\f[R] are hooked to a terminal, but the \f[B]-i\f[R] flag
|
|
and \f[B]--interactive\f[R] option can turn it on in other cases.
|
|
.PP
|
|
In interactive mode, bc(1) attempts to recover from errors (see the
|
|
\f[B]RESET\f[R] section), and in normal execution, flushes
|
|
\f[B]stdout\f[R] as soon as execution is done for the current input.
|
|
.SH TTY MODE
|
|
.PP
|
|
If \f[B]stdin\f[R], \f[B]stdout\f[R], and \f[B]stderr\f[R] are all
|
|
connected to a TTY, bc(1) turns on \[dq]TTY mode.\[dq]
|
|
.PP
|
|
The prompt is enabled in TTY mode.
|
|
.PP
|
|
TTY mode is different from interactive mode because interactive mode is
|
|
required in the bc(1)
|
|
specification (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html),
|
|
and interactive mode requires only \f[B]stdin\f[R] and \f[B]stdout\f[R]
|
|
to be connected to a terminal.
|
|
.SH SIGNAL HANDLING
|
|
.PP
|
|
Sending a \f[B]SIGINT\f[R] will cause bc(1) to stop execution of the
|
|
current input.
|
|
If bc(1) is in TTY mode (see the \f[B]TTY MODE\f[R] section), it will
|
|
reset (see the \f[B]RESET\f[R] section).
|
|
Otherwise, it will clean up and exit.
|
|
.PP
|
|
Note that \[dq]current input\[dq] can mean one of two things.
|
|
If bc(1) is processing input from \f[B]stdin\f[R] in TTY mode, it will
|
|
ask for more input.
|
|
If bc(1) is processing input from a file in TTY mode, it will stop
|
|
processing the file and start processing the next file, if one exists,
|
|
or ask for input from \f[B]stdin\f[R] if no other file exists.
|
|
.PP
|
|
This means that if a \f[B]SIGINT\f[R] is sent to bc(1) as it is
|
|
executing a file, it can seem as though bc(1) did not respond to the
|
|
signal since it will immediately start executing the next file.
|
|
This is by design; most files that users execute when interacting with
|
|
bc(1) have function definitions, which are quick to parse.
|
|
If a file takes a long time to execute, there may be a bug in that file.
|
|
The rest of the files could still be executed without problem, allowing
|
|
the user to continue.
|
|
.PP
|
|
\f[B]SIGTERM\f[R] and \f[B]SIGQUIT\f[R] cause bc(1) to clean up and
|
|
exit, and it uses the default handler for all other signals.
|
|
.SH SEE ALSO
|
|
.PP
|
|
dc(1)
|
|
.SH STANDARDS
|
|
.PP
|
|
bc(1) is compliant with the IEEE Std 1003.1-2017
|
|
(\[lq]POSIX.1-2017\[rq]) (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
|
|
specification.
|
|
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
|
|
noted above are extensions to that specification.
|
|
.PP
|
|
Note that the specification explicitly says that bc(1) only accepts
|
|
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
|
|
the value of \f[B]LC_NUMERIC\f[R].
|
|
.SH BUGS
|
|
.PP
|
|
None are known.
|
|
Report bugs at https://git.yzena.com/gavin/bc.
|
|
.SH AUTHORS
|
|
.PP
|
|
Gavin D.
|
|
Howard <gavin@yzena.com> and contributors.
|