> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man1/bc.1.md).

# bc.1

`bc` — 任意精度十进制算术语言和计算器

## 名称

`bc` — 任意精度十进制算术语言和计算器

## 概要

`bc [-cCghilPqRsvVw] [--digit-clamp] [--no-digit-clamp] [--global-stacks] [--help] [--interactive] [--mathlib] [--no-prompt] [--no-read-prompt] [--quiet] [--standard] [--warn] [--version] [-e expr] [--expression=expr...] [-f file...] [--file=file...] [file...] [-I ibase] [--ibase=ibase] [-O obase] [--obase=obase] [-S scale] [--scale=scale] [-E seed] [--seed=seed]`

## 描述

`bc(1)` 是一种语言的交互式处理器，该语言于 1991 年由 POSIX 首次标准化。（参见 STANDARDS 章节。）该语言提供无限精度的十进制算术，并且有些类似 C 语言，但存在差异。这些差异将在本文档中注明。

解析并处理选项后，此 `bc(1)` 会读取命令行上给定的任何文件，并在从 stdin 读取之前执行它们。

此 `bc(1)` 是*任何* `bc(1)`（包括且尤其是 GNU `bc(1)`）的直接替换品。它还具有许多超越其他实现的扩展和额外功能。

**注意**：如果在用于其他 `bc(1)` 的任何脚本上运行此 `bc(1)` 时出现解析错误，可能是因为此 `bc(1)` 保留为关键字的某个字被用作函数、变量或数组的名称。要解决此问题，请使用命令行选项 `-r` `keyword`，其中 `keyword` 是脚本中用作名称的关键字。更多信息参见 OPTIONS 章节。

如果解析用于其他 `bc(1)` 实现的脚本仍然无效，那是 bug，应当报告。参见 BUGS 章节。

## 选项

以下是 `bc(1)` 接受的选项。

**`-C`**、**`--no-digit-clamp`** 禁用在解析数字时对大于或等于当前 `ibase` 的数字进行钳制。

这意味着从某数字添加到数字的值始终是该数字的值乘以 `ibase` 的相应次幂（从最低有效数字的位置 0 开始）。

如果此选项和/或 `-c` 或 `--digit-clamp` 选项被多次给定，使用最后给定的一个。

此选项覆盖 `BC_DIGIT_CLAMP` 环境变量（参见 ENVIRONMENT VARIABLES 章节）和默认值，默认值可通过 `-h` 或 `--help` 选项查询。

这是一个**非可移植扩展**。

**`-c`**、**`--digit-clamp`** 启用在解析数字时对大于或等于当前 `ibase` 的数字进行钳制。

这意味着从大于或等于 `ibase` 的数字添加到数字的值是 `ibase` 减 1 的值乘以 `ibase` 的相应次幂（从最低有效数字的位置 0 开始）。

如果此选项和/或 `-C` 或 `--no-digit-clamp` 选项被多次给定，使用最后给定的一个。

此选项覆盖 `BC_DIGIT_CLAMP` 环境变量（参见 ENVIRONMENT VARIABLES 章节）和默认值，默认值可通过 `-h` 或 `--help` 选项查询。

这是一个**非可移植扩展**。

**`-E`** `seed`、**`--seed=seed`** 将内建变量 `seed` 设置为值 `seed`，假定 `seed` 为十进制。如果 `seed` 不是有效数字，则为致命错误。

如果此选项被多次给定，使用最后一个。

这是一个**非可移植扩展**。

**`-e`** `expr`、**`--expression=expr`** 求值 `expr`。如果给定多个表达式，按顺序求值。如果同时给定文件（参见 `-f` 和 `--file` 选项），表达式和文件按给定顺序求值。这意味着如果在表达式之前给定文件，则先读入并求值该文件。

如果此选项在命令行上给定（即不在 `BC_ENV_ARGS` 中，参见 ENVIRONMENT VARIABLES 章节），则在处理所有表达式和文件后，`bc(1)` 会退出，除非 `-`（stdin）至少一次被作为 `-f` 或 `--file` 的参数（无论是在命令行还是 `BC_ENV_ARGS` 中）。但是，如果在给定 `-f-` 或等效项之后还给定了任何其他 `-e`、`--expression`、`-f` 或 `--file` 参数，`bc(1)` 将发出致命错误并退出。

这是一个**非可移植扩展**。

**`-f`** `file`、**`--file=file`** 读入 `file` 并逐行求值，如同通过 stdin 读入。如果同时给定表达式（参见 `-e` 和 `--expression` 选项），表达式按给定顺序求值。

如果此选项在命令行上给定（即不在 `BC_ENV_ARGS` 中，参见 ENVIRONMENT VARIABLES 章节），则在处理所有表达式和文件后，`bc(1)` 会退出，除非 `-`（stdin）至少一次被作为 `-f` 或 `--file` 的参数。但是，如果在给定 `-f-` 或等效项之后还给定了任何其他 `-e`、`--expression`、`-f` 或 `--file` 参数，`bc(1)` 将发出致命错误并退出。

这是一个**非可移植扩展**。

**`-g`**、**`--global-stacks`** 将全局变量 `ibase`、`obase`、`scale` 和 `seed` 转换为栈。

这导致每次函数调用时所有四个全局变量的当前值的副本被压入栈，每次函数返回时弹出。这意味着函数可以赋值给这些全局变量中的任何一个或全部，而无需担心更改会影响其他函数。因此，一个名为 `output(x,b)` 的假设函数（仅以 `b` 进制打印 `x`）可以这样编写：

```sh
define void output(x, b) {
    obase=b
    x
}
```

而不是这样：

```sh
define void output(x, b) {
    auto c
    c=obase
    obase=b
    x
    obase=c
}
```

这使得编写函数更加容易。

（**注意**：函数 `output(x,b)` 存在于扩展数学库中。参见 LIBRARY 章节。）

但是，由于使用此标志意味着函数不能全局设置 `ibase`、`obase`、`scale` 或 `seed`，为此目的创建的函数将不再工作。有两种可能的用例，每种都有解决方案。

首先，如果在启动时调用函数以将 `bc(1)` 转换为数字转换器，可以使用各种 shell 别名替换该功能。示例：

```sh
alias d2o="bc -e ibase=A -e obase=8"
alias h2b="bc -e ibase=G -e obase=2"
```

其次，如果函数的目的是为任何其他目的全局设置 `ibase`、`obase`、`scale` 或 `seed`，可以将其拆分为一到四个函数（基于它设置多少个全局变量），每个函数可以返回相应全局变量的所需值。

对于设置 `seed` 的函数，分配给 `seed` 的值不会传播到父函数。这意味着它们看到的伪随机数序列不会与任何父函数看到的伪随机数序列相同。这仅在 `seed` 已被设置后才成立。

如果函数希望不影响其父函数的伪随机数序列，但想使用相同的 `seed`，可以使用以下行：

```sh
seed = seed
```

如果希望每次运行 `bc(1)` 时都使用此选项的行为，用户可以确保定义 `BC_ENV_ARGS` 并包含此选项（参见 ENVIRONMENT VARIABLES 章节了解更多详情）。

如果使用 `-s`、`-w` 或任何等效项，此选项将被忽略。

这是一个**非可移植扩展**。

**`-h`**、**`--help`** 打印用法消息并退出。

**`-I`** `ibase`、**`--ibase=ibase`** 将内建变量 `ibase` 设置为值 `ibase`，假定 `ibase` 为十进制。如果 `ibase` 不是有效数字，则为致命错误。

如果此选项被多次给定，使用最后一个。

这是一个**非可移植扩展**。

**`-i`**、**`--interactive`** 强制交互模式。（参见 INTERACTIVE MODE 章节。）

这是一个**非可移植扩展**。

**`-L`**、**`--no-line-length`** 禁用行长度检查，并打印数字时不带反斜杠和换行符。换句话说，此选项将 `BC_LINE_LENGTH` 设置为 0（参见 ENVIRONMENT VARIABLES 章节）。

这是一个**非可移植扩展**。

**`-l`**、**`--mathlib`** 将 `scale`（参见 SYNTAX 章节）设置为 20，并在运行任何代码（包括命令行上指定的任何表达式或文件）之前加载包含的数学库和扩展数学库。

要了解库中的内容，参见 LIBRARY 章节。

**`-O`** `obase`、**`--obase=obase`** 将内建变量 `obase` 设置为值 `obase`，假定 `obase` 为十进制。如果 `obase` 不是有效数字，则为致命错误。

如果此选项被多次给定，使用最后一个。

这是一个**非可移植扩展**。

**`-P`**、**`--no-prompt`** 在 TTY 模式下禁用提示符。（提示符仅在 TTY 模式下启用。参见 TTY MODE 章节。）这主要用于那些不希望有提示符或不习惯在 `bc(1)` 中有提示符的用户。大多数此类用户希望将此选项放入 `BC_ENV_ARGS`（参见 ENVIRONMENT VARIABLES 章节）。

这些选项覆盖 `BC_PROMPT` 和 `BC_TTY_MODE` 环境变量（参见 ENVIRONMENT VARIABLES 章节）。

这是一个**非可移植扩展**。

**`-q`**、**`--quiet`** 此选项用于与 GNU `bc(1)` (<https://www.gnu.org/software/bc/>) 兼容；它是一个空操作。如果没有此选项，GNU `bc(1)` 会打印版权标题。此 `bc(1)` 仅在给定 `-v`、`-V` 或 `--version` 选项中的一个或多个时打印版权标题，除非设置了 `BC_BANNER` 环境变量并包含非零整数，或者此 `bc(1)` 构建时默认显示标题。如果是上述任何情况，则此选项确实会阻止 `bc(1)` 打印标题。

这是一个**非可移植扩展**。

**`-R`**、**`--no-read-prompt`** 在 TTY 模式下禁用读取提示符。（读取提示符仅在 TTY 模式下启用。参见 TTY MODE 章节。）这主要用于那些不希望有读取提示符或不习惯在 `bc(1)` 中有读取提示符的用户。大多数此类用户希望将此选项放入 `BC_ENV_ARGS`（参见 ENVIRONMENT VARIABLES 章节）。此选项在提示用户输入的 `bc(1)` 脚本的 hash bang 行中也很有用。

此选项不会禁用常规提示符，因为读取提示符仅在调用 `read()` 内建函数时使用。

这些选项*确实*覆盖 `BC_PROMPT` 和 `BC_TTY_MODE` 环境变量（参见 ENVIRONMENT VARIABLES 章节），但仅针对读取提示符。

这是一个**非可移植扩展**。

**`-r`** `keyword`、**`--redefine=keyword`** 重新定义 `keyword`，使其可用作函数、变量或数组名称。当此 `bc(1)` 在解析用于其他 `bc(1)` 实现的脚本时出现解析错误，这很有用。

此 `bc(1)` 允许重新定义的关键字有：

* `abs`
* `asciify`
* `continue`
* `divmod`
* `else`
* `halt`
* `irand`
* `last`
* `limits`
* `maxibase`
* `maxobase`
* `maxrand`
* `maxscale`
* `modexp`
* `print`
* `rand`
* `read`
* `seed`
* `stream`

如果脚本中将上述任何关键字用作函数、变量或数组名称，请使用此选项并将关键字作为参数。如果使用了多个，请对所有关键字使用此选项；它可以多次使用。

解析内建数学库时不会重新定义关键字（参见 LIBRARY 章节）。

重新定义 POSIX 标准要求的关键字（参见 STANDARDS 章节）是致命错误。尝试重新定义此 `bc(1)` 不保留为关键字的字也是致命错误。

**`-S`** `scale`、**`--scale=scale`** 将内建变量 `scale` 设置为值 `scale`，假定 `scale` 为十进制。如果 `scale` 不是有效数字，则为致命错误。

如果此选项被多次给定，使用最后一个。

这是一个**非可移植扩展**。

**`-s`**、**`--standard`** 仅处理标准定义的语言（参见 STANDARDS 章节），如果使用任何扩展则出错。

这是一个**非可移植扩展**。

**`-v`**、**`-V`**、**`--version`** 打印版本信息（版权标题）并退出。

这是一个**非可移植扩展**。

**`-w`**、**`--warn`** 类似于 `-s` 和 `--standard`，但对非标准扩展打印警告（而非错误），并正常继续执行。

这是一个**非可移植扩展**。

**`-z`**、**`--leading-zeroes`** 使 `bc(1)` 打印所有大于 -1 且小于 1 且不等于 0 的数字时带前导零。

这可以通过扩展数学库中的 `plz(x)`、`plznl(x)`、`pnlz(x)` 和 `pnlznl(x)` 函数为单个数字设置（参见 LIBRARY 章节）。

这是一个**非可移植扩展**。

所有长选项都是**非可移植扩展**。

## STDIN

如果未通过 `-f`、`--file`、`-e` 或 `--expression` 选项给定文件或表达式，则 `bc(1)` 从 stdin 读取。

但是，这有一些注意事项。

首先，stdin 每次求值一行。唯一的例外是解析无法完成。这意味着开始一个字符串但未结束它，或开始一个函数、`if` 语句或循环但未结束它，也会导致 `bc(1)` 不执行。

其次，在 `if` 语句之后，`bc(1)` 不知道是否会有 `else` 语句跟随，因此在知道不会有 `else` 语句之前不会执行。

## STDOUT

任何非错误输出都写入 stdout。此外，如果启用历史（参见 HISTORY 章节）和提示符（参见 TTY MODE 章节），两者都输出到 stdout。

**注意**：与其他 `bc(1)` 实现不同，此 `bc(1)` 在无法写入 stdout 时会发出致命错误（参见 EXIT STATUS 章节），因此如果 stdout 被关闭（如 `bc >&-`），它会以错误退出。这样做是为了让 `bc(1)` 在 stdout 重定向到文件时能报告问题。

如果有脚本依赖于其他 `bc(1)` 实现的行为，建议将这些脚本更改为将 stdout 重定向到 **/dev/null**。

## STDERR

任何错误输出都写入 stderr。

**注意**：与其他 `bc(1)` 实现不同，此 `bc(1)` 在无法写入 stderr 时会发出致命错误（参见 EXIT STATUS 章节），因此如果 stderr 被关闭（如 `bc 2>&-`），它会以错误退出。这样做是为了让 `bc(1)` 在 stderr 重定向到文件时能以错误代码退出。

如果有脚本依赖于其他 `bc(1)` 实现的行为，建议将这些脚本更改为将 stderr 重定向到 **/dev/null**。

## SYNTAX

`bc(1)` 程序的语法大部分类似 C 语言，但有一些差异。此 `bc(1)` 遵循 POSIX 标准（参见 STANDARDS 章节），该标准是此 `bc(1)` 接受的语言的更全面资源。本节旨在作为摘要和所有标准扩展的列表。

在下文中，**E** 表示表达式，**S** 表示语句，**I** 表示标识符。

标识符（**I**）以小写字母开头，后跟任意数量（最多 `BC_NAME_MAX-1` 个）的小写字母（`a-z`）、数字（`0-9`）和下划线（`_`）。正则表达式为 `[a-z][a-z0-9_]*`。具有多个字符（字母）的标识符是**非可移植扩展**。

`ibase` 是确定如何解释常量数字的全局变量。它是“输入”基，即用于解释输入数字的数制基。`ibase` 初始为 10。如果命令行上未给定 `-s`（`--standard`）和 `-w`（`--warn`）标志，`ibase` 的最大允许值为 36。否则为 16。`ibase` 的最小允许值为 2。`ibase` 的最大允许值可在 `bc(1)` 程序中通过 `maxibase()` 内建函数查询。

`obase` 是确定如何输出结果的全局变量。它是“输出”基，即用于输出数字的数制基。`obase` 初始为 10。`obase` 的最大允许值为 `BC_BASE_MAX`，可在 `bc(1)` 程序中通过 `maxobase()` 内建函数查询。`obase` 的最小允许值为 0。如果 `obase` 为 0，值以科学计数法输出；如果 `obase` 为 1，值以工程计数法输出。否则，值以指定基数输出。

以科学计数法和工程计数法输出是**非可移植扩展**。

表达式的 *scale* 是表达式结果中小数点右侧的数字位数，`scale` 是设置任何操作精度的全局变量（有例外）。`scale` 初始为 0。`scale` 不能为负。`scale` 的最大允许值为 `BC_SCALE_MAX`，可在 `bc(1)` 程序中通过 `maxscale()` 内建函数查询。

`bc(1)` 既有*全局*变量也有*局部*变量。所有*局部*变量对函数是局部的；它们是参数或在函数的 `auto` 列表中引入（参见 FUNCTIONS 章节）。如果访问的变量不是参数或不在 `auto` 列表中，则假定为*全局*。如果父函数有一个子函数视为*全局*的变量的*局部*版本，则子函数中该*全局*变量的值是父函数中该变量的值，而非实际*全局*变量的值。

以上所有内容也适用于数组。

作为表达式的语句（即任何命名表达式或操作数）的值会被打印，除非最低优先级的运算符是赋值运算符且表达式未被括号包围。

打印的值也会分配给特殊变量 `last`。单个点（`.`）也可用作 `last` 的同义词。这些是**非可移植扩展**。

分号或换行符都可以分隔语句。

### 注释

有两种注释：

1. 块注释由 `/*` 和 `*/` 包围。
2. 行注释从 `#` 开始到下一个换行符（不包括）。这是**非可移植扩展**。

### 命名表达式

以下是 `bc(1)` 中的命名表达式：

1. 变量：`I`
2. 数组元素：`I[E]`
3. `ibase`
4. `obase`
5. `scale`
6. `seed`
7. `last` 或单个点（`.`）

第 6 和第 7 项是**非可移植扩展**。

`seed` 的含义取决于当前的伪随机数生成器，但保证不会更改，除非有新的主要版本。

值的 *scale* 和符号可能很重要。

如果将先前使用的 `seed` 值分配给 `seed` 并再次使用，伪随机数生成器保证产生与先前使用 `seed` 值时相同的伪随机数序列。

如果立即再次查询 `seed`，不保证返回分配给 `seed` 的确切值。但是，如果 `seed` *确实*返回不同的值，两个值在分配给 `seed` 时都保证产生相同的伪随机数序列。这意味着分配给 `seed` 的某些值*不会*产生唯一的伪随机数序列。在任何使用 `rand()` 和 `irand(E)` 操作数（参见下文 Operands 小节）后，`seed` 的值都会更改，除非传递给 `irand(E)` 的参数为 0、1 或负数。

分配给 `seed` 的值的长度（有效十进制数字位数）或 *scale* 没有限制。

变量和数组互不干扰；用户可以拥有与变量同名的数组。这也适用于函数（参见 FUNCTIONS 章节），因此用户可以拥有同名的变量、数组和函数，它们不会相互遮蔽，无论是在函数内部还是外部。

命名表达式作为自增/自减运算符的操作数和赋值运算符的左侧所必需（参见 Operators 小节）。

### 操作数

以下是 `bc(1)` 中的有效操作数：

1. 数字（参见下文 Numbers 小节）。
2. 数组索引（`I[E]`）。
3. `(E)`：`E` 的值（用于更改优先级）。
4. `sqrt(E)`：`E` 的平方根。`E` 必须非负。
5. `length(E)`：`E` 中有效十进制数字的位数。对于无小数位的 0 返回 1。如果给定字符串，则返回字符串的长度。将字符串传递给 `length(E)` 是**非可移植扩展**。
6. `length(I[])`：数组 `I` 中的元素数量。这是**非可移植扩展**。
7. `scale(E)`：`E` 的 *scale*。
8. `abs(E)`：`E` 的绝对值。这是**非可移植扩展**。
9. `is_number(E)`：如果给定参数是数字则为 1，如果是字符串则为 0。这是**非可移植扩展**。
10. `is_string(E)`：如果给定参数是字符串则为 1，如果是数字则为 0。这是**非可移植扩展**。
11. `modexp(E, E, E)`：模幂运算，其中第一个表达式是底数，第二个是指数，第三个是模数。三个值都必须是整数。第二个参数必须非负。第三个参数必须非零。这是**非可移植扩展**。
12. `divmod(E, E, I[])`：一次操作中的除法和取模。这用于优化。第一个表达式是被除数，第二个是除数（必须非零）。返回值是商，模数存储在所提供数组（最后一个参数）的索引 0 处。这是**非可移植扩展**。
13. `asciify(E)`：如果 `E` 是字符串，返回一个由其参数第一个字母组成的字符串。如果是数字，计算该数字 mod 256 并将该数字作为单字符字符串返回。这是**非可移植扩展**。
14. `asciify(I[])`：一个由对参数所标识数组的每个元素运行 `asciify(E)` 所得到的字符组成的字符串。这允许创建并存储多字符字符串。这是**非可移植扩展**。
15. `I()`、`I(E)`、`I(E, E)` 等，其中 `I` 是非 `void` 函数的标识符（参见 FUNCTIONS 章节的 Void Functions 小节）。`E` 参数也可以是 `I[]` 形式的数组，如果函数定义中相应的参数是数组引用，则会自动转换为数组引用（参见 FUNCTIONS 章节的 Array References 小节）。
16. `read()`：从 stdin 读取一行并将其用作表达式。该表达式的结果是 `read()` 操作数的结果。这是**非可移植扩展**。
17. `maxibase()`：最大允许的 `ibase`。这是**非可移植扩展**。
18. `maxobase()`：最大允许的 `obase`。这是**非可移植扩展**。
19. `maxscale()`：最大允许的 `scale`。这是**非可移植扩展**。
20. `line_length()`：通过 `BC_LINE_LENGTH` 设置的行长度（参见 ENVIRONMENT VARIABLES 章节）。这是**非可移植扩展**。
21. `global_stacks()`：如果未通过 `-g` 或 `--global-stacks` 选项启用全局栈则为 0，否则非零。参见 OPTIONS 章节。这是**非可移植扩展**。
22. `leading_zero()`：如果未通过 `-z` 或 `--leading-zeroes` 选项启用前导零则为 0，否则非零。参见 OPTIONS 章节。这是**非可移植扩展**。
23. `rand()`：0（含）到 `BC_RAND_MAX`（含）之间的伪随机整数。使用此操作数会更改 `seed` 的值。这是**非可移植扩展**。
24. `irand(E)`：0（含）到 `E` 的值（不含）之间的伪随机整数。如果 `E` 为负或非整数（`E` 的 *scale* 不为 0），则引发错误，`bc(1)` 重置（参见 RESET 章节），而 `seed` 保持不变。如果 `E` 大于 `BC_RAND_MAX`，通过生成多个伪随机整数、将它们乘以适当次幂的 `BC_RAND_MAX+1` 并相加来兑现较高上界。因此，此操作数可生成的整数大小无界。使用此操作数会更改 `seed` 的值，除非 `E` 的值为 0 或 1。在这种情况下，返回 0，`seed` *不*更改。这是**非可移植扩展**。
25. `maxrand()`：`rand()` 返回的最大整数。这是**非可移植扩展**。

`rand()` 和 `irand(E)` 生成的整数保证尽可能无偏，受伪随机数生成器的限制。

**注意**：伪随机数生成器通过 `rand()` 和 `irand(E)` 返回的值保证*不*是密码学安全的。这是使用种子伪随机数生成器的后果。但是，它们*保证*在相同 `seed` 值下可重现。这意味着 `bc(1)` 的伪随机值应仅用于可重现的伪随机数流*必不可少*的情况。在其他任何情况下，使用非种子伪随机数生成器。

### 数字

数字是由数字、大写字母和最多一个表示小数点的句点组成的字符串。数字最多可有 `BC_NUM_MAX` 位数字。大写字母等于 9 加其在字母表中的位置，从 1 开始（即 `A` 等于 10，或 `9+1`）。

如果某数字或字母在当前 `ibase` 下无意义（即大于或等于当前 `ibase` 的值），则行为取决于是否存在 `-c`/`--digit-clamp` 或 `-C`/`--no-digit-clamp` 选项（参见 OPTIONS 章节）、`BC_DIGIT_CLAMP` 环境变量的存在和设置（参见 ENVIRONMENT VARIABLES 章节），或可通过 `-h`/`--help` 选项查询的默认值。

如果钳制关闭，则大于或等于当前 `ibase` 值的数字或字母不会更改。相反，它们给定的值乘以 `ibase` 的适当次幂并加到数字中。这意味着 `ibase` 为 3 时，数字 `AB` 等于 `3^1*A+3^0*B`，即 3 乘以 10 加 11，或 41。

如果钳制开启，则大于或等于当前 `ibase` 值的数字或字母在乘以 `ibase` 的适当次幂并加到数字中之前，被设置为 `ibase` 中最高有效数字的值。这意味着 `ibase` 为 3 时，数字 `AB` 等于 `3^1*2+3^0*2`，即 3 乘以 2 加 2，或 8。

钳制有一个例外：单字符数字（即单独的 `A`）。此类数字从不被钳制，始终取在可能的最高 `ibase` 下应有的值。这意味着单独的 `A` 始终等于十进制 10，单独的 `Z` 始终等于十进制 35。此行为由标准要求（参见 STANDARDS 章节），旨在提供一种简单的方法来设置当前 `ibase`（使用 `i` 命令），而不管 `ibase` 的当前值。

如果钳制开启且需要字符的钳制值，请使用前导零，即对于 `A`，使用 `0A`。

此外，`bc(1)` 接受科学计数法表示的数字。形式为 `<number>e<integer>`。指数（`e` 之后的部分）必须是整数。例如 `1.89237e9`，等于 `1892370000`。也允许负指数，因此 `4.2890e-3` 等于 `0.0042890`。

如果给定 `-s` 或 `-w` 命令行选项（或等效项），使用科学计数法分别是错误或警告。

**警告**：科学计数法中的数字和指数都根据当前 `ibase` 解释，但数字仍乘以 `10^exponent`，而不管当前 `ibase`。例如，如果 `ibase` 为 16 且 `bc(1)` 被给定数字字符串 `FFeA`，结果十进制数字将为 `2550000000000`；如果 `bc(1)` 被给定数字字符串 `10e-4`，结果十进制数字将为 `0.0016`。

接受科学计数法输入是**非可移植扩展**。

### 运算符

以下算术和逻辑运算符可用。它们按优先级递减顺序列出。同一组中的运算符具有相同优先级。

**`++`** **`--`** 类型：前缀和后缀 结合性：无 描述：自增、自减

**`-`** **`!`** 类型：前缀 结合性：无 描述：负号、布尔非

**`$`** 类型：后缀 结合性：无 描述：截断

**`@`** 类型：二元 结合性：右 描述：设置精度

**`^`** 类型：二元 结合性：右 描述：幂

**`*`** **`/`** **`%`** 类型：二元 结合性：左 描述：乘、除、模

**`+`** **`-`** 类型：二元 结合性：左 描述：加、减

**`<<`** **`>>`** 类型：二元 结合性：左 描述：左移、右移

**`=`** **`<<=`** **`>>=`** **`+=`** **`-=`** **`*=`** **`/=`** **`%=`** **`^=`** **`@=`** 类型：二元 结合性：右 描述：赋值

**`==`** **`<=`** **`>=`** **`!=`** **`<`** **`>`** 类型：二元 结合性：左 描述：关系

**`&&`** 类型：二元 结合性：左 描述：布尔与

**`||`** 类型：二元 结合性：左 描述：布尔或

下面将更详细地描述这些运算符。

**`++`** **`--`** 前缀和后缀自增、自减运算符的行为与 C 中完全相同。它们要求命名表达式（参见 Named Expressions 小节）作为操作数。

前缀版本的这些运算符更高效；尽可能使用它们。

**`-`** 负号运算符在用户尝试对值为 0 的任何表达式取负时返回 0。否则，返回符号翻转的表达式副本。

**`!`** 布尔非运算符在表达式为 0 时返回 1，否则返回 0。

**警告**：此运算符的优先级与 GNU `bc(1)` 和其他 `bc(1)` 实现中的等效运算符*不同*！

这是**非可移植扩展**。

**`$`** 截断运算符返回给定表达式的副本，去除所有 *scale*。

这是**非可移植扩展**。

**`@`** 设置精度运算符接受两个表达式，返回第一个的副本，其 *scale* 等于第二个表达式的值。这可能意味着数字原样返回（如果第一个表达式的 *scale* 与第二个表达式的值匹配）、扩展（如果更少）或截断（如果更多）。

第二个表达式必须是整数（无 *scale*）且非负。

这是**非可移植扩展**。

**`^`** 幂运算符（不是 C 中的按位异或运算符）接受两个表达式，将第一个提升到第二个值的幂。结果的 *scale* 等于 `scale`。

第二个表达式必须是整数（无 *scale*），如果为负，第一个值必须非零。

**`*`** 乘法运算符接受两个表达式，将它们相乘并返回乘积。如果 `a` 是第一个表达式的 *scale*，`b` 是第二个表达式的 *scale*，结果的 *scale* 等于 `min(a+b,max(scale,a,b))`，其中 `min()` 和 `max()` 返回明显的值。

**`/`** 除法运算符接受两个表达式，将它们相除并返回商。结果的 *scale* 应为 `scale` 的值。

第二个表达式必须非零。

**`%`** 模运算符接受两个表达式 `a` 和 `b`，并通过 1) 将 `a/b` 计算到当前 *scale*，2) 使用步骤 1 的结果计算 `a-(a/b)*b` 到 *scale* `max(scale+scale(b),scale(a))` 来求值。

第二个表达式必须非零。

**`+`** 加法运算符接受两个表达式 `a` 和 `b`，返回和，*scale* 等于 `a` 和 `b` 的 *scale* 的最大值。

**`-`** 减法运算符接受两个表达式 `a` 和 `b`，返回差，*scale* 等于 `a` 和 `b` 的 *scale* 的最大值。

**`<<`** 左移运算符接受两个表达式 `a` 和 `b`，返回 `a` 的值副本，其小数点向右移动 `b` 位。

第二个表达式必须是整数（无 *scale*）且非负。

这是**非可移植扩展**。

**`>>`** 右移运算符接受两个表达式 `a` 和 `b`，返回 `a` 的值副本，其小数点向左移动 `b` 位。

第二个表达式必须是整数（无 *scale*）且非负。

这是**非可移植扩展**。

**`=`** **`<<=`** **`>>=`** **`+=`** **`-=`** **`*=`** **`/=`** **`%=`** **`^=`** **`@=`** 赋值运算符接受两个表达式 `a` 和 `b`，其中 `a` 是命名表达式（参见 Named Expressions 小节）。

对于 `=`，`b` 被复制并将结果分配给 `a`。对于所有其他运算符，`a` 和 `b` 作为操作数应用于相应的算术运算符，结果分配给 `a`。

对应于扩展运算符的赋值运算符本身是**非可移植扩展**。

**`==`** **`<=`** **`>=`** **`!=`** **`<`** **`>`** 关系运算符比较两个表达式 `a` 和 `b`，如果关系根据 C 语言语义成立，结果为 1。否则为 0。

注意，与 C 不同，这些运算符的优先级低于赋值运算符，这意味着 `a=b>c` 被解释为 `(a=b)>c`。

此外，与标准（参见 STANDARDS 章节）要求不同，这些运算符可以出现在任何其他表达式可以使用的任何地方。此允许是**非可移植扩展**。

**`&&`** 布尔与运算符接受两个表达式，如果两个表达式都非零则返回 1，否则返回 0。

这*不*是短路运算符。

这是**非可移植扩展**。

**`||`** 布尔或运算符接受两个表达式，如果其中一个表达式非零则返回 1，否则返回 0。

这*不*是短路运算符。

这是**非可移植扩展**。

### 语句

以下项是语句：

1. `E`
2. `{` `S` `;` ... `;` `S` `}`
3. `if` `(` `E` `)` `S`
4. `if` `(` `E` `)` `S` `else` `S`
5. `while` `(` `E` `)` `S`
6. `for` `(` `E` `;` `E` `;` `E` `)` `S`
7. 空语句
8. `break`
9. `continue`
10. `quit`
11. `halt`
12. `limits`
13. 由双引号包围的字符串
14. `print` `E` `,` ... `,` `E`
15. `stream` `E` `,` ... `,` `E`
16. `I()`、`I(E)`、`I(E, E)` 等，其中 `I` 是 `void` 函数的标识符（参见 FUNCTIONS 章节的 Void Functions 小节）。`E` 参数也可以是 `I[]` 形式的数组，如果函数定义中相应的参数是数组引用，则会自动转换为数组引用（参见 FUNCTIONS 章节的 Array References 小节）。

第 4、9、11、12、14、15 和 16 项是**非可移植扩展**。

此外，作为**非可移植扩展**，for 循环头部的任何或所有表达式都可以省略。如果条件（第二个表达式）被省略，假定为常量 1。

`break` 语句导致循环停止迭代并立即在循环后恢复执行。这仅在循环中允许。

`continue` 语句导致循环迭代提前停止并返回循环开头，包括测试循环条件。这仅在循环中允许。

`if` `else` 语句的作用与 C 中相同。

`quit` 语句导致 `bc(1)` 退出，即使它位于不会执行的分支上（它是编译时命令）。

**警告**：此 `bc(1)` 在 `quit` 上的行为与其他 `bc(1)` 实现略有不同。其他 `bc(1)` 实现会在完成解析 `quit` 命令所在行后立即退出。此 `bc(1)` 会先执行 `quit` 语句之前出现的任何已完成且可执行的语句，然后再退出。

换句话说，对于以下 `bc(1)` 代码：

```sh
for (i = 0; i < 3; ++i) i; quit
```

其他 `bc(1)` 实现不会打印任何内容，而此 `bc(1)` 会在退出前依次打印 `0`、`1` 和 `2`。

`halt` 语句在执行时导致 `bc(1)` 退出。（与 `quit` 不同，如果它位于不会执行的 `if` 语句分支上，`bc(1)` 不会退出。）

`limits` 语句打印此 `bc(1)` 受到的限制。这类似于 `quit` 语句，因为它是编译时命令。

单独的表达式会被求值并打印，后跟换行符。

科学计数法和工程计数法都可用于打印表达式的结果。通过将 `0` 分配给 `obase` 激活科学计数法，通过将 `1` 分配给 `obase` 激活工程计数法。要停用它们，只需将不同的值分配给 `obase`。

如果 `bc(1)` 以 `-s` 或 `-w` 命令行选项（或等效项）运行，则禁用科学计数法和工程计数法。

以科学计数法和/或工程计数法打印数字是**非可移植扩展**。

### 字符串

如果字符串作为语句单独出现，则打印时不带尾随换行符。

除了作为单独语句出现外，字符串还可以分配给变量和数组元素。它们也可以在变量参数中传递给函数。

如果任何期望字符串的语句被给定一个已分配字符串的变量，该语句的行为就像它收到了字符串一样。

如果对字符串或已分配字符串的变量或数组元素尝试任何数学运算，会引发错误，`bc(1)` 重置（参见 RESET 章节）。

将字符串分配给变量和数组元素并将其传递给函数是**非可移植扩展**。

### Print 语句

`print` 语句中的“表达式”也可以是字符串。如果是，则有特别解释的反斜杠转义序列。这些序列是什么以及它们导致打印什么，如下所示：

`\a`: `\a` `\b`: `\b` `\\`: `\` `\e`: `\` `\f`: `\f` `\n`: `\n` `\q`: `"` `\r`: `\r` `\t`: `\t`

反斜杠后的任何其他字符导致反斜杠和字符原样打印。

`print` 语句中的任何非字符串表达式都应分配给 `last`，就像任何其他被打印的表达式一样。

### Stream 语句

`stream` 语句中的表达式也可以是字符串。

如果 `stream` 语句被给定字符串，它会像字符串作为自己的语句出现一样打印该字符串。换句话说，`stream` 语句正常打印字符串，不带换行符。

如果 `stream` 语句被给定数字，会截断其副本并计算其绝对值。然后结果被打印，就像 `obase` 为 256 一样，每个数字被解释为 8 位 ASCII 字符，使其成为字节流。

### 求值顺序

语句中的所有表达式从左到右求值，除非为保持运算顺序所必需。这意味着，例如，假设 `i` 等于 0，在表达式：

```sh
a[i++] = i++
```

中，`a` 的第一个（或第 0 个）元素被设置为 1，表达式结束时 `i` 等于 2。

这包括函数参数。因此，假设 `i` 等于 0，这意味着在表达式：

```sh
x(i++, i++)
```

中，传递给 `x()` 的第一个参数是 0，第二个参数是 1，而 `i` 在函数开始执行前等于 2。

## 函数

函数定义如下：

```sh
define I(I,...,I){
    auto I,...,I
    S;...;S
    return(E)
}
```

参数列表或 `auto` 列表中的任何 `I` 可以替换为 `I[]` 以使参数或 `auto` 变量成为数组，参数列表中的任何 `I` 可以替换为 `*I[]` 以使参数成为数组引用。调用接受数组引用的函数时不应在调用中加星号；必须像普通数组参数一样仅用 `I[]` 调用，并将自动转换为引用。

作为**非可移植扩展**，`define` 语句的左大括号可以出现在下一行。

作为**非可移植扩展**，`return` 语句也可以采用以下形式之一：

1. `return`
2. `return` `(` `)`
3. `return` `E`

前两个或不指定 `return` 语句等效于 `return (0)`，除非函数是 `void` 函数（参见下文 Void Functions 小节）。

### Void 函数

函数也可以是 `void` 函数，定义如下：

```sh
define void I(I,...,I){
    auto I,...,I
    S;...;S
    return
}
```

它们只能用作独立表达式，其中此类表达式会单独打印，但在 `print` 语句中除外。

`void` 函数只能使用上面列出的前两个 `return` 语句。它们也可以完全省略 `return` 语句。

“void”一词不被视为关键字；仍然可以有名为 `void` 的变量、数组和函数。“void”一词仅在 `define` 关键字之后才被特殊处理。

这是**非可移植扩展**。

### 数组引用

对于参数列表中的任何数组，如果数组以以下形式声明：

```sh
*I[]
```

则它是引用。函数中对数组的任何更改在函数返回时会反映到传入的数组上。

除此之外，所有函数参数都按值传递。

这是**非可移植扩展**。

## 库

以下所有函数，包括扩展数学库中的函数（参见下文 Extended Library 小节），在给定 `-l` 或 `--mathlib` 命令行标志时可用，但扩展数学库在给定 `-s` 选项、`-w` 选项或等效项时不可用。

### 标准库

标准（参见 STANDARDS 章节）为数学库定义以下函数：

**`s(x)`** 返回 `x` 的正弦，假定 `x` 以弧度为单位。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`c(x)`** 返回 `x` 的余弦，假定 `x` 以弧度为单位。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`a(x)`** 返回 `x` 的反正切，以弧度为单位。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`l(x)`** 返回 `x` 的自然对数。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`e(x)`** 返回数学常数 `e` 的 `x` 次幂。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`j(x, n)`** 返回 `x` 的整数阶 `n`（截断）贝塞尔函数。

这是超越函数（参见下文 Transcendental Functions 小节）。

### 扩展库

给定 `-s`/`--standard` 或 `-w`/`--warn` 选项时不加载扩展库，因为它们不是标准定义的库的一部分（参见 STANDARDS 章节）。

扩展库是**非可移植扩展**。

**`p(x, y)`** 计算 `x` 的 `y` 次幂，即使 `y` 不是整数，并将结果返回到当前 `scale`。

如果 `y` 为负且 `x` 为 0，则为错误。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`r(x, p)`** 根据“向远离 0 方向舍入”的舍入模式 (<https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero>) 将 `x` 舍入到 `p` 位小数。

**`ceil(x, p)`** 根据“向远离 0 方向舍入”的舍入模式 (<https://en.wikipedia.org/wiki/Rounding#Rounding_away_from_zero>) 将 `x` 舍入到 `p` 位小数。

**`f(x)`** 返回 `x` 的截断绝对值的阶乘。

**`max(a, b)`** 如果 `a` 大于 `b` 则返回 `a`；否则返回 `b`。

**`min(a, b)`** 如果 `a` 小于 `b` 则返回 `a`；否则返回 `b`。

**`perm(n, k)`** 如果 `k <= n`，返回 `n` 的截断绝对值的 `k` 的截断绝对值排列。否则返回 0。

**`comb(n, k)`** 如果 `k <= n`，返回 `n` 的截断绝对值的 `k` 的截断绝对值组合。否则返回 0。

**`fib(n)`** 返回 `n` 的截断绝对值的斐波那契数。

**`l2(x)`** 返回 `x` 的以 2 为底的对数。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`l10(x)`** 返回 `x` 的以 10 为底的对数。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`log(x, b)`** 返回 `x` 的以 `b` 为底的对数。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`cbrt(x)`** 返回 `x` 的立方根。

**`root(x, n)`** 计算 `n` 的截断值 `r`，并返回 `x` 的 `r` 次方根到当前 `scale`。

如果 `r` 为 0 或负，会引发错误并导致 `bc(1)` 重置（参见 RESET 章节）。如果 `r` 为偶且 `x` 为负，也会引发错误并导致 `bc(1)` 重置。

**`gcd(a, b)`** 返回 `a` 的截断绝对值和 `b` 的截断绝对值的最大公约数（因子）。

**`lcm(a, b)`** 返回 `a` 的截断绝对值和 `b` 的截断绝对值的最小公倍数。

**`pi(p)`** 返回 `p` 位小数的 pi。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`t(x)`** 返回 `x` 的正切，假定 `x` 以弧度为单位。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`a2(y, x)`** 返回 `y/x` 的反正切，以弧度为单位。如果 `y` 和 `x` 都等于 0，会引发错误并导致 `bc(1)` 重置（参见 RESET 章节）。否则，如果 `x` 大于 0，返回 `a(y/x)`。如果 `x` 小于 0 且 `y` 大于或等于 0，返回 `a(y/x)+pi`。如果 `x` 小于 0 且 `y` 小于 0，返回 `a(y/x)-pi`。如果 `x` 等于 0 且 `y` 大于 0，返回 `pi/2`。如果 `x` 等于 0 且 `y` 小于 0，返回 `-pi/2`。

此函数与许多编程语言中的 `atan2()` 函数相同。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`sin(x)`** 返回 `x` 的正弦，假定 `x` 以弧度为单位。

这是 `s(x)` 的别名。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`cos(x)`** 返回 `x` 的余弦，假定 `x` 以弧度为单位。

这是 `c(x)` 的别名。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`tan(x)`** 返回 `x` 的正切，假定 `x` 以弧度为单位。

如果 `x` 等于 1 或 -1，会引发错误并导致 `bc(1)` 重置（参见 RESET 章节）。

这是 `t(x)` 的别名。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`atan(x)`** 返回 `x` 的反正切，以弧度为单位。

这是 `a(x)` 的别名。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`atan2(y, x)`** 返回 `y/x` 的反正切，以弧度为单位。如果 `y` 和 `x` 都等于 0，会引发错误并导致 `bc(1)` 重置（参见 RESET 章节）。否则，如果 `x` 大于 0，返回 `a(y/x)`。如果 `x` 小于 0 且 `y` 大于或等于 0，返回 `a(y/x)+pi`。如果 `x` 小于 0 且 `y` 小于 0，返回 `a(y/x)-pi`。如果 `x` 等于 0 且 `y` 大于 0，返回 `pi/2`。如果 `x` 等于 0 且 `y` 小于 0，返回 `-pi/2`。

此函数与许多编程语言中的 `atan2()` 函数相同。

这是 `a2(y, x)` 的别名。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`r2d(x)`** 将 `x` 从弧度转换为角度并返回结果。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`d2r(x)`** 将 `x` 从角度转换为弧度并返回结果。

这是超越函数（参见下文 Transcendental Functions 小节）。

**`frand(p)`** 生成 0（含）到 1（不含）之间的伪随机数，小数点后的十进制位数等于 `p` 的截断绝对值。如果 `p` 不为 0，则调用此函数会更改 `seed` 的值。如果 `p` 为 0，则返回 0，`seed` 不更改。

**`ifrand(i, p)`** 生成 0（含）到 `i` 的截断绝对值（不含）之间的伪随机数，小数点后的十进制位数等于 `p` 的截断绝对值。如果 `i` 的绝对值大于或等于 2 且 `p` 不为 0，则调用此函数会更改 `seed` 的值；否则返回 0，`seed` 不更改。

**`i2rand(a, b)`** 取 `a` 和 `b` 的截断值并将它们作为含边界用于生成伪随机整数。如果 `a` 和 `b` 的截断值之差为 0，则返回截断值，`seed` 不更改。否则，此函数会更改 `seed` 的值。

**`srand(x)`** 以概率 0.5 翻转 `x` 的符号并返回。换句话说，它随机化 `x` 的符号。

**`brand()`** 返回随机布尔值（0 或 1）。

**`band(a, b)`** 取 `a` 和 `b` 的截断绝对值并计算和返回它们之间的按位与运算结果。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bor(a, b)`** 取 `a` 和 `b` 的截断绝对值并计算和返回它们之间的按位或运算结果。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bxor(a, b)`** 取 `a` 和 `b` 的截断绝对值并计算和返回它们之间的按位异或运算结果。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bshl(a, b)`** 取 `a` 和 `b` 的截断绝对值并计算和返回 `a` 左移 `b` 位的结果。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bshr(a, b)`** 取 `a` 和 `b` 的截断绝对值并计算和返回 `a` 右移 `b` 位的截断结果。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnotn(x, n)`** 取 `x` 的截断绝对值并按具有与 `n` 的截断绝对值相同字节数进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnot8(x)`** 对 `x` 的截断绝对值按 8 个二进制位（1 个无符号字节）进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnot16(x)`** 对 `x` 的截断绝对值按 16 个二进制位（2 个无符号字节）进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnot32(x)`** 对 `x` 的截断绝对值按 32 个二进制位（4 个无符号字节）进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnot64(x)`** 对 `x` 的截断绝对值按 64 个二进制位（8 个无符号字节）进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bnot(x)`** 对 `x` 的截断绝对值按最小 2 的幂无符号字节数进行按位非运算。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brevn(x, n)`** 对 `x` 的截断绝对值按具有与 `n` 的截断绝对值相同 8 位字节数进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brev8(x)`** 对 `x` 的截断绝对值按 8 个二进制位（1 个无符号字节）进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brev16(x)`** 对 `x` 的截断绝对值按 16 个二进制位（2 个无符号字节）进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brev32(x)`** 对 `x` 的截断绝对值按 32 个二进制位（4 个无符号字节）进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brev64(x)`** 对 `x` 的截断绝对值按 64 个二进制位（8 个无符号字节）进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brev(x)`** 对 `x` 的截断绝对值按最小 2 的幂无符号字节数进行位反转。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`broln(x, p, n)`** 对 `x` 的截断绝对值按具有与 `n` 的截断绝对值相同无符号 8 位字节数进行左位旋转，旋转位数等于 `p` 的截断绝对值模以 `n` 个 8 位字节的二进制位数的 2 的幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brol8(x, p)`** 对 `x` 的截断绝对值按 8 个二进制位（1 个无符号字节）进行左位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 8 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brol16(x, p)`** 对 `x` 的截断绝对值按 16 个二进制位（2 个无符号字节）进行左位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 16 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brol32(x, p)`** 对 `x` 的截断绝对值按 32 个二进制位（4 个无符号字节）进行左位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 32 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brol64(x, p)`** 对 `x` 的截断绝对值按 64 个二进制位（8 个无符号字节）进行左位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 64 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brol(x, p)`** 对 `x` 的截断绝对值按最小 2 的幂无符号 8 位字节数进行左位旋转，旋转位数等于 `p` 的截断绝对值模以最小 8 位字节数的二进制位数的 2 的幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`brorn(x, p, n)`** 对 `x` 的截断绝对值按具有与 `n` 的截断绝对值相同无符号 8 位字节数进行右位旋转，旋转位数等于 `p` 的截断绝对值模以 `n` 个 8 位字节的二进制位数的 2 的幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bror8(x, p)`** 对 `x` 的截断绝对值按 8 个二进制位（1 个无符号字节）进行右位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 8 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bror16(x, p)`** 对 `x` 的截断绝对值按 16 个二进制位（2 个无符号字节）进行右位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 16 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bror32(x, p)`** 对 `x` 的截断绝对值按 32 个二进制位（2 个无符号字节）进行右位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 32 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bror64(x, p)`** 对 `x` 的截断绝对值按 64 个二进制位（2 个无符号字节）进行右位旋转，旋转位数等于 `p` 的截断绝对值模以 2 的 64 次幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bror(x, p)`** 对 `x` 的截断绝对值按最小 2 的幂无符号 8 位字节数进行右位旋转，旋转位数等于 `p` 的截断绝对值模以最小 8 位字节数的二进制位数的 2 的幂。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bmodn(x, n)`** 返回 `x` 的截断绝对值模以 `n` 的截断绝对值与 8 的乘积的 2 的幂的模数。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bmod8(x, n)`** 返回 `x` 的截断绝对值模以 2 的 8 次幂的模数。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bmod16(x, n)`** 返回 `x` 的截断绝对值模以 2 的 16 次幂的模数。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bmod32(x, n)`** 返回 `x` 的截断绝对值模以 2 的 32 次幂的模数。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`bmod64(x, n)`** 返回 `x` 的截断绝对值模以 2 的 64 次幂的模数。

如果要使用有符号二补码参数，请使用 `s2u(x)` 转换。

**`plz(x)`** 如果 `x` 不等于 0 且大于 -1 且小于 1，则不论是否使用 `-z` 选项（参见 OPTIONS 章节），都打印带前导零的数字，不带尾随换行符。

否则，`x` 正常打印，不带尾随换行符。

**`plznl(x)`** 如果 `x` 不等于 0 且大于 -1 且小于 1，则不论是否使用 `-z` 选项（参见 OPTIONS 章节），都打印带前导零的数字，带尾随换行符。

否则，`x` 正常打印，带尾随换行符。

**`pnlz(x)`** 如果 `x` 不等于 0 且大于 -1 且小于 1，则不论是否使用 `-z` 选项（参见 OPTIONS 章节），都打印不带前导零的数字，不带尾随换行符。

否则，`x` 正常打印，不带尾随换行符。

**`pnlznl(x)`** 如果 `x` 不等于 0 且大于 -1 且小于 1，则不论是否使用 `-z` 选项（参见 OPTIONS 章节），都打印不带前导零的数字，带尾随换行符。

否则，`x` 正常打印，带尾随换行符。

**`ubytes(x)`** 返回保存 `x` 的截断绝对值所需的无符号整数字节数。

**`sbytes(x)`** 返回保存 `x` 的截断值所需的有符号二补码整数字节数。

**`s2u(x)`** 如果 `x` 非负则返回 `x`。如果为负，则计算 `x` 作为 2 补码有符号整数的值，并返回在二进制中具有相同表示的非负整数。

**`s2un(x,n)`** 如果 `x` 非负则返回 `x`。如果为负，则计算 `x` 作为 `n` 字节 2 补码有符号整数的值，并返回在二进制中具有相同表示的非负整数。如果 `x` 不能放入 `n` 个 2 补码有符号字节，则截断以适应。

**`hex(x)`** 输出 `x` 的十六进制（基 16）表示。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`binary(x)`** 输出 `x` 的二进制（基 2）表示。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`output(x, b)`** 输出 `x` 的基 `b` 表示。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uint(x)`** 以尽可能少的 2 的幂字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或为负，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`int(x)`** 以尽可能少的 2 的幂字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uintn(x, n)`** 以 `n` 字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数、为负或不能放入 `n` 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`intn(x, n)`** 以 `n` 字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或不能放入 `n` 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uint8(x)`** 以 1 字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数、为负或不能放入 1 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`int8(x)`** 以 1 字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或不能放入 1 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uint16(x)`** 以 2 字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数、为负或不能放入 2 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`int16(x)`** 以 2 字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或不能放入 2 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uint32(x)`** 以 4 字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数、为负或不能放入 4 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`int32(x)`** 以 4 字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或不能放入 4 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`uint64(x)`** 以 8 字节输出 `x` 作为无符号整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数、为负或不能放入 8 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`int64(x)`** 以 8 字节输出 `x` 作为有符号二补码整数的二进制和十六进制表示。两种输出都按字节以空格分隔。

如果 `x` 不是整数或不能放入 8 字节，则改为打印错误消息，但 `bc(1)` 不重置（参见 RESET 章节）。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`hex_uint(x, n)`** 使用 `n` 字节以十六进制输出 `x` 的截断绝对值作为无符号整数的表示。如果 `n` 太小，不会输出所有值。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`binary_uint(x, n)`** 使用 `n` 字节以二进制输出 `x` 的截断绝对值作为无符号整数的表示。如果 `n` 太小，不会输出所有值。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`output_uint(x, n)`** 使用 `n` 字节以当前 `obase`（参见 SYNTAX 章节）输出 `x` 的截断绝对值作为无符号整数的表示。如果 `n` 太小，不会输出所有值。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

**`output_byte(x, i)`** 输出 `x` 的截断绝对值的第 `i` 字节，其中 0 是最低有效字节，`number_of_bytes - 1` 是最高有效字节。

这是 `void` 函数（参见 FUNCTIONS 章节的 Void Functions 小节）。

### 超越函数

所有超越函数都可能返回略有不准确的结果，误差最多 1 ULP (<https://en.wikipedia.org/wiki/Unit_in_the_last_place>)。这是不可避免的，<https://people.eecs.berkeley.edu/~wkahan/LOG10HAF.TXT> 上的文章解释了为何计算超越函数的精确结果既不可能也不必要。

由于可能的不准确性，建议用户以至少比必要精度高 1 的精度（*scale*）调用这些函数。如果*绝对*需要精确结果，用户可以将精度（*scale*）加倍然后截断。

标准数学库中的超越函数有：

* `s(x)`
* `c(x)`
* `a(x)`
* `l(x)`
* `e(x)`
* `j(x, n)`

扩展数学库中的超越函数有：

* `l2(x)`
* `l10(x)`
* `log(x, b)`
* `pi(p)`
* `t(x)`
* `a2(y, x)`
* `sin(x)`
* `cos(x)`
* `tan(x)`
* `atan(x)`
* `atan2(y, x)`
* `r2d(x)`
* `d2r(x)`

## RESET

当 `bc(1)` 遇到错误或有非默认处理程序的信号时，它会重置。这意味着会发生几件事。

首先，任何正在执行的函数都会停止并从栈中弹出。该行为类似于编程语言中的异常。然后设置执行点，使得任何等待执行（在所有函数返回后）的代码都被跳过。

因此，当 `bc(1)` 重置时，它会跳过任何等待执行的剩余代码。然后，如果处于交互模式且错误不是致命错误（参见 EXIT STATUS 章节），它会请求更多输入；否则，以适当的返回代码退出。

注意，此重置行为与 GNU `bc(1)` 不同，后者尝试在导致错误的语句之后立即开始执行语句。

## 性能

大多数 `bc(1)` 实现使用 `char` 类型一次计算 1 个十进制数字的值，但这可能很慢。此 `bc(1)` 采用不同的方式。

它使用大整数一次计算多于 1 个十进制数字。如果在 `BC_LONG_BIT`（参见 LIMITS 章节）为 64 的环境中构建，则每个整数有 9 个十进制数字。如果在 `BC_LONG_BIT` 为 32 的环境中构建，则每个整数有 4 个十进制数字。此值（每个大整数的十进制数字数）称为 `BC_BASE_DIGS`。

`BC_LONG_BIT` 和 `BC_BASE_DIGS` 的实际值可通过 `limits` 语句查询。

此外，此 `bc(1)` 使用更大的整数进行溢出检查。此整数类型取决于 `BC_LONG_BIT` 的值，但始终至少是用于存储数字的整数类型的两倍大。

## 限制

以下是 `bc(1)` 的限制：

**`BC_LONG_BIT`** 构建 `bc(1)` 的环境中 `long` 类型的位数。这决定了单个大整数可以存储多少十进制数字（参见 PERFORMANCE 章节）。

**`BC_BASE_DIGS`** 每个大整数的十进制数字数（参见 PERFORMANCE 章节）。取决于 `BC_LONG_BIT`。

**`BC_BASE_POW`** 每个大整数可以存储的最大十进制数（参见 `BC_BASE_DIGS`）加 1。取决于 `BC_BASE_DIGS`。

**`BC_OVERFLOW_MAX`** 溢出类型（参见 PERFORMANCE 章节）可以容纳的最大数。取决于 `BC_LONG_BIT`。

**`BC_BASE_MAX`** 最大输出基数。设为 `BC_BASE_POW`。

**`BC_DIM_MAX`** 数组的最大大小。设为 `SIZE_MAX-1`。

**`BC_SCALE_MAX`** 最大 `scale`。设为 `BC_OVERFLOW_MAX-1`。

**`BC_STRING_MAX`** 字符串的最大长度。设为 `BC_OVERFLOW_MAX-1`。

**`BC_NAME_MAX`** 标识符的最大长度。设为 `BC_OVERFLOW_MAX-1`。

**`BC_NUM_MAX`** 数字的最大长度（十进制数字位数），包括小数点后的数字。设为 `BC_OVERFLOW_MAX-1`。

**`BC_RAND_MAX`** `rand()` 操作数返回的最大整数（含）。设为 `2^BC_LONG_BIT-1`。

**Exponent** 最大允许指数（正或负）。设为 `BC_OVERFLOW_MAX`。

**Number of vars** 变量/数组的最大数量。设为 `SIZE_MAX-1`。

实际值可通过 `limits` 语句查询。

这些限制实际上是非存在的；限制如此之大（至少在 64 位机器上），不应有任何它们成为问题的情况。事实上，在达到这些限制之前，内存应已被耗尽。

## 环境变量

作为**非可移植扩展**，`bc(1)` 识别以下环境变量：

**`POSIXLY_CORRECT`** 如果此变量存在（无论内容如何），`bc(1)` 的行为就像给定了 `-s` 选项一样。

**`BC_ENV_ARGS`** 这是向 `bc(1)` 提供命令行参数的另一种方式。它们应采用与所有其他命令行参数相同的格式。这些参数始终先处理，因此 `BC_ENV_ARGS` 中给定的任何文件将在命令行上给定的参数和文件之前处理。这使用户能够设置每次调用时使用的“标准”选项和文件。此类文件最有用的内容是用户每次运行 `bc(1)` 时都可能想要的有用函数。

解析 `BC_ENV_ARGS` 的代码会正确处理带引号的参数，但不理解转义序列。例如，字符串 `/home/gavin/some bc file.bc` 会被正确解析，但字符串 `/home/gavin/some \"bc\" file.bc` 会包含反斜杠。

引号解析会处理任一种引号（`'` 或 `"`）。因此，如果文件名中包含任意数量的单引号，可以使用双引号作为外部引号，如 `some 'bc' file.bc`；反之亦然，如果文件名中包含双引号。但是，由于解析的复杂性，在 `BC_ENV_ARGS` 中处理同时包含两种引号的文件不受支持，尽管此类文件在命令行上仍然受支持（解析由 shell 完成）。

**`BC_LINE_LENGTH`** 如果此环境变量存在并包含一个大于 1 且小于 `UINT16_MAX`（`2^16-1`）的整数，`bc(1)` 会将输出行限制为该长度，包括反斜杠（`\`）。默认行长度为 70。

特殊值 0 将禁用行长度检查并打印数字时不考虑行长度，不带反斜杠和换行符。

**`BC_BANNER`** 如果此环境变量存在并包含整数，则非零值在 `bc(1)` 处于交互模式时激活版权横幅，零值停用。

如果 `bc(1)` 不处于交互模式（参见 INTERACTIVE MODE 章节），则此环境变量无效，因为 `bc(1)` 不处于交互模式时不打印横幅。

此环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

**`BC_SIGINT_RESET`** 如果 `bc(1)` 不处于交互模式（参见 INTERACTIVE MODE 章节），则此环境变量无效，因为 `bc(1)` 不处于交互模式时在 SIGINT 上退出。

但是，当 `bc(1)` 处于交互模式时，如果此环境变量存在并包含整数，非零值使 `bc(1)` 在 SIGINT 上重置而非退出，零值使 `bc(1)` 退出。如果此环境变量存在但*不*是整数，则 `bc(1)` 会在 SIGINT 上退出。

此环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

**`BC_TTY_MODE`** 如果 TTY 模式*不*可用（参见 TTY MODE 章节），则此环境变量无效。

但是，当 TTY 模式可用时，如果此环境变量存在并包含整数，则非零值使 `bc(1)` 使用 TTY 模式，零值使 `bc(1)` 不使用 TTY 模式。

此环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

**`BC_PROMPT`** 如果 TTY 模式*不*可用（参见 TTY MODE 章节），则此环境变量无效。

但是，当 TTY 模式可用时，如果此环境变量存在并包含整数，非零值使 `bc(1)` 使用提示符，零值或非整数使 `bc(1)` 不使用提示符。如果此环境变量不存在但 `BC_TTY_MODE` 存在，则使用 `BC_TTY_MODE` 环境变量的值。

此环境变量和 `BC_TTY_MODE` 环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

**`BC_EXPR_EXIT`** 如果通过 `-e`、`--expression`、`-f` 或 `--file` 在命令行上给定任何表达式或表达式文件，则如果此环境变量存在并包含整数，非零值使 `bc(1)` 在执行表达式和表达式文件后退出，零值使 `bc(1)` 不退出。

此环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

**`BC_DIGIT_CLAMP`** 解析数字时，如果此环境变量存在并包含整数，非零值使 `bc(1)` 钳制大于或等于当前 `ibase` 的数字，使所有此类数字被视为等于 `ibase` 减 1，零值禁用此类钳制，使这些数字始终等于其值，该值乘以 `ibase` 的幂。

根据标准（参见 STANDARDS 章节），这从不适用于单数字数字。

此环境变量覆盖默认值，默认值可通过 `-h` 或 `--help` 选项查询。

## 退出状态

`bc(1)` 返回以下退出状态：

**`0`** 无错误。

**`1`** 发生数学错误。这遵循使用 1 表示预期错误的标准做法，因为数学错误会在正常执行过程中发生。

数学错误包括除以 0、对负数开平方、使用负数作为伪随机数生成器的边界、尝试将负数转换为硬件整数、将数字转换为硬件整数时溢出、计算数字大小时溢出，以及尝试在需要整数处使用非整数。

转换为硬件整数发生在幂（`^`）、精度（`@`）、左移（`<<`）和右移（`>>`）运算符及其相应赋值运算符的第二个操作数上。

**`2`** 发生解析错误。

解析错误包括意外的 EOF、使用无效字符、找不到字符串或注释的结尾、在无效位置使用标记、给定无效表达式、给定无效 `print` 语句、给定无效函数定义、尝试向非命名表达式的表达式赋值（参见 SYNTAX 章节的 Named Expressions 小节）、给定无效 `auto` 列表、有重复的 `auto`/函数参数、找不到代码块的结尾、尝试从 `void` 函数返回值、尝试将变量用作引用，以及在给定 `-s` 选项或任何等效项时使用任何扩展。

**`3`** 发生运行时错误。

运行时错误包括向任何全局变量（`ibase`、`obase` 或 `scale`）分配无效数字、向 `read()` 调用给定错误表达式、在 `read()` 调用内调用 `read()`、类型错误、向函数传递错误数量的参数、尝试调用未定义函数，以及尝试将 `void` 函数调用用作表达式中的值。

**`4`** 发生致命错误。

致命错误包括内存分配错误、I/O 错误、无法打开文件、尝试使用仅含非 ASCII 字符的文件（`bc(1)` 仅接受 ASCII 字符）、尝试将目录作为文件打开，以及给定无效命令行选项。

退出状态 4 是特殊的；发生致命错误时，`bc(1)` 始终退出并返回 4，无论 `bc(1)` 处于何种模式。

其他状态仅在 `bc(1)` 不处于交互模式（参见 INTERACTIVE MODE 章节）时返回，因为在交互模式下发生这些错误之一时，`bc(1)` 会重置其状态（参见 RESET 章节）并接受更多输入。当通过 `-i` 标志或 `--interactive` 选项强制交互模式时也是如此。

这些退出状态允许 `bc(1)` 在 shell 脚本中使用并进行错误检查，其正常行为可通过使用 `-i` 标志或 `--interactive` 选项强制执行。

## 交互模式

根据标准（参见 STANDARDS 章节），`bc(1)` 有交互模式和非交互模式。当 stdin 和 stdout 都连接到终端时，交互模式会自动开启，但 `-i` 标志和 `--interactive` 选项可在其他情况下开启它。

在交互模式下，`bc(1)` 尝试从错误中恢复（参见 RESET 章节），并在正常执行中，一旦当前输入执行完毕就刷新 stdout。`bc(1)` 也可能在 SIGINT 上重置而非退出，这取决于 `BC_SIGINT_RESET` 环境变量的内容或默认值（参见 ENVIRONMENT VARIABLES 章节）。

## TTY 模式

如果 stdin、stdout 和 stderr 都连接到 TTY，则认为“TTY 模式”可用，因此 `bc(1)` 可以开启 TTY 模式（受某些设置约束）。

如果环境中存在 `BC_TTY_MODE` 环境变量（参见 ENVIRONMENT VARIABLES 章节），且该环境变量包含非零整数，则 `bc(1)` 会在 stdin、stdout 和 stderr 都连接到 TTY 时开启 TTY 模式。如果 `BC_TTY_MODE` 环境变量存在但*不*是非零整数，则 `bc(1)` 不会开启 TTY 模式。

如果 `BC_TTY_MODE` 环境变量*不*存在，则使用默认设置。默认设置可通过 `-h` 或 `--help` 选项查询。

TTY 模式与交互模式不同，因为交互模式在 `bc(1)` 标准中是必需的（参见 STANDARDS 章节），而交互模式仅要求 stdin 和 stdout 连接到终端。

### 命令行历史

仅当 TTY 模式开启时才启用命令行历史，即 stdin、stdout 和 stderr 都连接到 TTY 且 `BC_TTY_MODE` 环境变量（参见 ENVIRONMENT VARIABLES 章节）及其默认值未禁用 TTY 模式。更多信息参见 COMMAND LINE HISTORY 章节。

### 提示符

如果 TTY 模式可用，则可以启用提示符。与 TTY 模式本身一样，可以使用环境变量 `BC_PROMPT`（参见 ENVIRONMENT VARIABLES 章节）开启或关闭。

如果 `BC_PROMPT` 环境变量存在且为非零整数，则当 stdin、stdout 和 stderr 都连接到 TTY 且未使用 `-P` 和 `--no-prompt` 选项时，提示符会开启。读取提示符在相同条件下会开启，但还必须未使用 `-R` 和 `--no-read-prompt` 选项。

但是，如果 `BC_PROMPT` 不存在，则可以使用 `BC_TTY_MODE` 环境变量、`-P` 和 `--no-prompt` 选项，以及 `-R` 和 `--no-read-prompt` 选项启用或禁用提示符。参见 ENVIRONMENT VARIABLES 和 OPTIONS 章节了解更多详情。

## 信号处理

发送 SIGINT 会导致 `bc(1)` 执行以下两种操作之一。

如果 `bc(1)` 不处于交互模式（参见 INTERACTIVE MODE 章节），或 `BC_SIGINT_RESET` 环境变量（参见 ENVIRONMENT VARIABLES 章节）或其默认值不是整数或为零，`bc(1)` 会退出。

但是，如果 `bc(1)` 处于交互模式，且 `BC_SIGINT_RESET` 或其默认值是整数且非零，则 `bc(1)` 在收到 SIGINT 时会停止执行当前输入并重置（参见 RESET 章节）。

注意，“当前输入”可能意味着两种情况之一。如果 `bc(1)` 在交互模式下处理来自 stdin 的输入，它会请求更多输入。如果 `bc(1)` 在交互模式下处理来自文件的输入，它会停止处理该文件并开始处理下一个文件（如果存在），或在没有其他文件时从 stdin 请求输入。

这意味着如果在 `bc(1)` 执行文件时向其发送 SIGINT，可能看起来 `bc(1)` 没有响应信号，因为它会立即开始执行下一个文件。这是设计使然；用户与 `bc(1)` 交互时执行的大多数文件都包含函数定义，这些定义解析很快。如果文件执行需要很长时间，该文件可能存在 bug。其余文件仍可无问题执行，允许用户继续。

为保护自己，你应警惕任何来自不可信来源的归档。

SIGTERM 和 SIGQUIT 导致 `bc(1)` 清理并退出，对其他所有信号使用默认处理程序。一个例外是 SIGHUP；在这种情况下，且仅当 `bc(1)` 处于 TTY 模式（参见 TTY MODE 章节）时，SIGHUP 会导致 `bc(1)` 清理并退出。

## 命令行历史

`bc(1)` 支持交互式命令行编辑。

如果 `bc(1)` 可以处于 TTY 模式（参见 TTY MODE 章节），则可以启用历史。这意味着仅当 stdin、stdout 和 stderr 都连接到 TTY 时才能启用命令行历史。

与 TTY 模式本身一样，可以使用环境变量 `BC_TTY_MODE`（参见 ENVIRONMENT VARIABLES 章节）开启或关闭。

如果启用历史，可以使用箭头键调用和编辑以前的行。

**注意**：制表符被转换为 8 个空格。

## 区域设置

此 `bc(1)` 附带对不同区域设置添加错误消息的支持，因此支持 `LC_MESSAGES`。

## 参见

dc(1)

## 标准

`bc(1)` 符合 IEEE Std 1003.1-2017（“POSIX.1-2017”）规范 <https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html>。标志 `-efghiqsvVw`、所有长选项以及上面注明的扩展是对该规范的扩展。

此外，`quit` 的行为实现了对该规范的一种解释，这种解释与所有已知实现都不同。更多信息参见 SYNTAX 章节的 Statements 小节。

注意，规范明确说明 `bc(1)` 仅接受使用句点（`.`）作为小数点的数字，而不管 `LC_NUMERIC` 的值如何。

此 `bc(1)` 支持不同区域设置的错误消息，因此支持 `LC_MESSAGES`。

## 缺陷

在 6.1.0 版本之前，此 `bc(1)` 对 `quit` 语句的行为不正确。

没有其他已知缺陷。请在 <https://github.com/gavinhoward/bc> 报告缺陷。

## 作者

Gavin D. Howard <gavin@gavinhoward.com> 和贡献者。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man1/bc.1.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
