forked from gavin/bc
1
0
Fork 0

Move sections of the README to their own manuals

The sections are Build and Algorithms. They were just cluttering the
README. I did put links to the manuals in the places where they were. I
also added a short blurb to the README about compiling with default
options.
rand
Gavin Howard 4 years ago
parent 6f1aa5a5bf
commit 573c939e70
Signed by untrusted user who does not match committer: gavin
GPG Key ID: C08038BDF280D33E
  1. 347
      README.md
  2. 186
      manuals/algorithms.md
  3. 262
      manuals/build.md

@ -4,8 +4,7 @@ This is an implementation of POSIX `bc` that implements
[GNU `bc`](https://www.gnu.org/software/bc/) extensions, as well as the period
(`.`) extension for the BSD flavor of `bc`.
For more information, see this `bc`'s
[full manual](https://github.com/gavinhoward/bc/blob/master/manuals/bc.md).
For more information, see this `bc`'s [full manual](./manuals/bc.md).
This `bc` also includes an implementation of `dc` in the same binary, accessible
via a symbolic link, which implements all FreeBSD and GNU extensions. If a
@ -13,138 +12,17 @@ single `dc` binary is desired, `bc` can be copied and renamed to `dc`. The `!`
command is omitted; I believe this is poses security concerns and that such
functionality is unnecessary.
For more information, see the `dc`'s
[full manual](https://github.com/gavinhoward/bc/blob/master/manuals/dc.md).
For more information, see the `dc`'s [full manual](./manuals/dc.md).
This `bc` is Free and Open Source Software (FOSS). It is offered under the BSD
0-clause License. Full license text may be found in the `LICENSE.md` file.
## Other Projects
Other projects based on this bc are:
* [busybox `bc`](https://git.busybox.net/busybox/tree/miscutils/bc.c). The
busybox maintainers have made their own changes, so any bugs in the busybox
`bc` should be reported to them.
* [toybox `bc`](https://github.com/landley/toybox/blob/master/toys/pending/bc.c)
The maintainer has also made his own changes, so bugs in the toybox `bc`
should be reported there.
## Build
In order to use POSIX-compatible Makefiles, this `bc` uses a POSIX shell script
as a configure step.
To get all of the options, including any useful environment variables, use the
following command:
```
./configure.sh -h
```
This `bc` should build unmodified on any POSIX-compliant system.
To learn the available `make` targets run the following command:
```
make help
```
To build both the `bc` and `dc`, use the following commands:
```
./configure.sh
make
make install
```
To build just the `bc`, use the following commands:
```
./configure.sh -b
make
make install
```
To build just the `dc`, use the following commands:
```
./configure.sh -d
make
make install
```
This `bc` supports `CC`, `CFLAGS`, `CPPFLAGS`, `LDFLAGS`, `LDLIBS`, `PREFIX`,
and `DESTDIR` `make` variables in the configure script. Any values of those
variables given to the configure command will be put into the generated
Makefile.
Note that to cross-compile this `bc`, an appropriate compiler must be present
and assigned to the environment variable `HOSTCC`. This is in order to bootstrap
core file(s), if the architectures are not compatible (i.e., unlike i686 on
x86_64). Thus, the approach is:
```
HOSTCC="/path/to/native/compiler" ./configure.sh
make
make install
```
It is expected that `CC` produces code for the target system.
Users can also disable signal handling by compiling as follows:
```
./configure.sh -S
make
make install
```
The same can be done for history as follows:
```
./configure.sh -H
make
make install
```
The same also be done for array references as follows:
```
./configure.sh -R
make
make install
```
This `bc` has 7 extra operators: `$` (truncation to integer), `@` (set precision
for a number), `<<` (shift number left; shifts radix right), `>>` (shift number
right; shifts radix left), and assignment versions of the last three (`@=`,
`<<=`, and `>>=`), though not for `$` since it is a unary operator. The
assignment versions are not available in `dc`, but the others are, as the
operators `$`, `@`, `H`, and `h`, respectively.
Extra operators can be disabled as follows:
```
./configure.sh -E
make
make install
```
This `bc` also has a larger library that is only enabled if extra operators are.
More information about the functions can be found in the
[full manual](https://github.com/gavinhoward/bc/blob/master/manuals/bc.md).
Signal handling, history, references, and extra operators are on by default.
Of course, any and all of the above options may be mixed, though array
references are turned off if only `dc` is built.
### Optimization
The configure script will accept an optimization level to pass to the compiler.
Because `bc` is orders of magnitude faster with optimization, I ***highly***
recommend package and distro maintainers pass the highest optimization level
available in `CC` to the configure script, as follows:
For the default build with optimization, use the following commands in the root
directory:
```
./configure.sh -O3
@ -152,28 +30,7 @@ make
make install
```
As usual, the configure script will also accept additional `CFLAGS` on the
command line, so for SSE4 architectures, the following can add a bit more speed:
```
CFLAGS="-march=native -msse4" ./configure.sh -O3
make
make install
```
Building with link-time optimization can further increase the performance.
Manual stripping is not necessary; non-debug builds are automatically stripped
in the link stage.
Debug builds (which also disable optimization if no optimization level is given
and if no extra `CFLAGS` are given) can be enabled with:
```
./configure.sh -g
make
make install
```
For more complex build requirements, see the [build manual](./manuals/build.md).
## Status
@ -198,192 +55,22 @@ This `bc` has similar performance to GNU `bc`. It is slightly slower on certain
operations and slightly faster on others. Full benchmark data are not yet
available.
#### Algorithms
This `bc` uses the math algorithms below:
##### Addition
This `bc` uses brute force addition, which is linear (`O(n)`) in the number of
digits.
##### Subtraction
This `bc` uses brute force subtraction, which is linear (`O(n)`) in the number
of digits.
##### Multiplication
This `bc` uses two algorithms:
[Karatsuba](https://en.wikipedia.org/wiki/Karatsuba_algorithm) and brute force.
Karatsuba is used for "large" numbers. ("Large" numbers are defined as any
number with `BC_NUM_KARATSUBA_LEN` digits or larger. `BC_NUM_KARATSUBA_LEN` has
a sane default, but may be configured by the user.) Karatsuba, as implemented in
this `bc`, is superlinear but subpolynomial (bounded by `O(n^log_2(3))`).
Brute force multiplication is used below `BC_NUM_KARATSUBA_LEN` digits. It is
polynomial (`O(n^2)`), but since Karatsuba requires both more intermediate
values (which translate to memory allocations) and a few more additions, there
is a "break even" point in the number of digits where brute force multiplication
is faster than Karatsuba. There is a script (`$ROOT/karatsuba.py`) that will
find the break even point on a particular machine.
***WARNING: The Karatsuba script requires Python 3.***
##### Division
This `bc` uses Algorithm D
([long division](https://en.wikipedia.org/wiki/Long_division)). Long division is
polynomial (`O(n^2)`), but unlike Karatsuba, any division "divide and conquer"
algorithm reaches its "break even" point with significantly larger numbers.
"Fast" algorithms become less attractive with division as this operation
typically reduces the problem size.
While the implementation of long division may appear to use the subtractive
chunking method, it only uses subtraction to find a quotient digit. It avoids
unnecessary work by aligning digits prior to performing subtraction.
Subtraction was used instead of multiplication for two reasons:
1. Division and subtraction can share code (one of the less important goals of
this `bc` is small code).
2. It minimizes algorithmic complexity.
Using multiplication would make division have the even worse algorithmic
complexity of `O(n^(2*log_2(3)))` (best case) and `O(n^3)` (worst case).
##### Power
This `bc` implements
[Exponentiation by Squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring),
and (via Karatsuba) has a complexity of `O((n*log(n))^log_2(3))` which is
favorable to the `O((n*log(n))^2)` without Karatsuba.
##### Square Root
This `bc` implements the fast algorithm
[Newton's Method](https://en.wikipedia.org/wiki/Newton%27s_method#Square_root_of_a_number)
(also known as the Newton-Raphson Method, or the
[Babylonian Method](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method))
to perform the square root operation. Its complexity is `O(log(n)*n^2)` as it
requires one division per iteration.
##### Sine and Cosine
This `bc` uses the series
```
x - x^3/3! + x^5/5! - x^7/7! + ...
```
to calculate `sin(x)` and `cos(x)`. It also uses the relation
```
cos(x) = sin(x + pi/2)
```
to calculate `cos(x)`. It has a complexity of `O(n^3)`.
**Note**: this series has a tendency to *occasionally* produce an error of 1
[ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place). (It is an
unfortunate side effect of the algorithm, and there isn't any way around it;
[this article](https://people.eecs.berkeley.edu/~wkahan/LOG10HAF.TXT) explains
why calculating sine and cosine, and the other transcendental functions below,
within less than 1 ULP is nearly impossible and unnecessary.) Therefore, I
recommend that users do their calculations with the precision (`scale`) set to
at least 1 greater than is needed.
##### Exponentiation (Power of `e`)
This `bc` uses the series
```
1 + x + x^2/2! + x^3/3! + ...
```
to calculate `e^x`. Since this only works when `x` is small, it uses
```
e^x = (e^(x/2))^2
```
to reduce `x`. It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
##### Natural Log
This `bc` uses the series
```
a + a^3/3 + a^5/5 + ...
```
(where `a` is equal to `(x - 1)/(x + 1)`) to calculate `ln(x)` when `x` is small
and uses the relation
```
ln(x^2) = 2 * ln(x)
```
to sufficiently reduce `x`. It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
##### Arctangent
This `bc` uses the series
```
x - x^3/3 + x^5/5 - x^7/7 + ...
```
to calculate `atan(x)` for small `x` and the relation
```
atan(x) = atan(c) + atan((x - c)/(1 + x * c))
```
to reduce `x` to small enough. It has a complexity of `O(n^3)`.
## Algorithms
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
To see what algorithms this `bc` uses, see the
[algorithms manual](./manuals/algorithms.md).
##### Bessel
This `bc` uses the series
```
x^n/(2^n * n!) * (1 - x^2 * 2 * 1! * (n + 1)) + x^4/(2^4 * 2! * (n + 1) * (n + 2)) - ...
```
to calculate the bessel function (integer order only).
It also uses the relation
```
j(-n,x) = (-1)^n * j(n,x)
```
to calculate the bessel when `x < 0`, It has a complexity of `O(n^3)`.
## Other Projects
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
Other projects based on this bc are:
##### Modular Exponentiation (`dc` Only)
* [busybox `bc`](https://git.busybox.net/busybox/tree/miscutils/bc.c). The
busybox maintainers have made their own changes, so any bugs in the busybox
`bc` should be reported to them.
This `dc` uses the
[Memory-efficient method](https://en.wikipedia.org/wiki/Modular_exponentiation#Memory-efficient_method)
to compute modular exponentiation. The complexity is `O(e*n^2)`, which may
initially seem inefficient, but `n` is kept small by maintaining small numbers.
In practice, it is extremely fast.
* [toybox `bc`](https://github.com/landley/toybox/blob/master/toys/pending/bc.c)
The maintainer has also made his own changes, so bugs in the toybox `bc`
should be reported there.
## Language

@ -0,0 +1,186 @@
# Algorithms
This `bc` uses the math algorithms below:
### Addition
This `bc` uses brute force addition, which is linear (`O(n)`) in the number of
digits.
### Subtraction
This `bc` uses brute force subtraction, which is linear (`O(n)`) in the number
of digits.
### Multiplication
This `bc` uses two algorithms:
[Karatsuba](https://en.wikipedia.org/wiki/Karatsuba_algorithm) and brute force.
Karatsuba is used for "large" numbers. ("Large" numbers are defined as any
number with `BC_NUM_KARATSUBA_LEN` digits or larger. `BC_NUM_KARATSUBA_LEN` has
a sane default, but may be configured by the user.) Karatsuba, as implemented in
this `bc`, is superlinear but subpolynomial (bounded by `O(n^log_2(3))`).
Brute force multiplication is used below `BC_NUM_KARATSUBA_LEN` digits. It is
polynomial (`O(n^2)`), but since Karatsuba requires both more intermediate
values (which translate to memory allocations) and a few more additions, there
is a "break even" point in the number of digits where brute force multiplication
is faster than Karatsuba. There is a script (`$ROOT/karatsuba.py`) that will
find the break even point on a particular machine.
***WARNING: The Karatsuba script requires Python 3.***
### Division
This `bc` uses Algorithm D
([long division](https://en.wikipedia.org/wiki/Long_division)). Long division is
polynomial (`O(n^2)`), but unlike Karatsuba, any division "divide and conquer"
algorithm reaches its "break even" point with significantly larger numbers.
"Fast" algorithms become less attractive with division as this operation
typically reduces the problem size.
While the implementation of long division may appear to use the subtractive
chunking method, it only uses subtraction to find a quotient digit. It avoids
unnecessary work by aligning digits prior to performing subtraction.
Subtraction was used instead of multiplication for two reasons:
1. Division and subtraction can share code (one of the less important goals of
this `bc` is small code).
2. It minimizes algorithmic complexity.
Using multiplication would make division have the even worse algorithmic
complexity of `O(n^(2*log_2(3)))` (best case) and `O(n^3)` (worst case).
### Power
This `bc` implements
[Exponentiation by Squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring),
and (via Karatsuba) has a complexity of `O((n*log(n))^log_2(3))` which is
favorable to the `O((n*log(n))^2)` without Karatsuba.
### Square Root
This `bc` implements the fast algorithm
[Newton's Method](https://en.wikipedia.org/wiki/Newton%27s_method#Square_root_of_a_number)
(also known as the Newton-Raphson Method, or the
[Babylonian Method](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method))
to perform the square root operation. Its complexity is `O(log(n)*n^2)` as it
requires one division per iteration.
### Sine and Cosine (`bc` Only)
This `bc` uses the series
```
x - x^3/3! + x^5/5! - x^7/7! + ...
```
to calculate `sin(x)` and `cos(x)`. It also uses the relation
```
cos(x) = sin(x + pi/2)
```
to calculate `cos(x)`. It has a complexity of `O(n^3)`.
**Note**: this series has a tendency to *occasionally* produce an error of 1
[ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place). (It is an
unfortunate side effect of the algorithm, and there isn't any way around it;
[this article](https://people.eecs.berkeley.edu/~wkahan/LOG10HAF.TXT) explains
why calculating sine and cosine, and the other transcendental functions below,
within less than 1 ULP is nearly impossible and unnecessary.) Therefore, I
recommend that users do their calculations with the precision (`scale`) set to
at least 1 greater than is needed.
### Exponentiation (`bc` Only)
This `bc` uses the series
```
1 + x + x^2/2! + x^3/3! + ...
```
to calculate `e^x`. Since this only works when `x` is small, it uses
```
e^x = (e^(x/2))^2
```
to reduce `x`. It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
### Natural Logarithm (`bc` Only)
This `bc` uses the series
```
a + a^3/3 + a^5/5 + ...
```
(where `a` is equal to `(x - 1)/(x + 1)`) to calculate `ln(x)` when `x` is small
and uses the relation
```
ln(x^2) = 2 * ln(x)
```
to sufficiently reduce `x`. It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
### Arctangent (`bc` Only)
This `bc` uses the series
```
x - x^3/3 + x^5/5 - x^7/7 + ...
```
to calculate `atan(x)` for small `x` and the relation
```
atan(x) = atan(c) + atan((x - c)/(1 + x * c))
```
to reduce `x` to small enough. It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
### Bessel (`bc` Only)
This `bc` uses the series
```
x^n/(2^n * n!) * (1 - x^2 * 2 * 1! * (n + 1)) + x^4/(2^4 * 2! * (n + 1) * (n + 2)) - ...
```
to calculate the bessel function (integer order only).
It also uses the relation
```
j(-n,x) = (-1)^n * j(n,x)
```
to calculate the bessel when `x < 0`, It has a complexity of `O(n^3)`.
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
their calculations with the precision (`scale`) set to at least 1 greater than
is needed.
### Modular Exponentiation (`dc` Only)
This `dc` uses the
[Memory-efficient method](https://en.wikipedia.org/wiki/Modular_exponentiation#Memory-efficient_method)
to compute modular exponentiation. The complexity is `O(e*n^2)`, which may
initially seem inefficient, but `n` is kept small by maintaining small numbers.
In practice, it is extremely fast.

@ -0,0 +1,262 @@
# Build
This `bc` attempts to be as portable as possible. It can be built on any
POSIX-compliant system.
To accomplish that, a POSIX-compatible `configure.sh` script is used to select
build options, compiler, and compiler flags and generate a `Makefile`.
The general form of configuring, building, and installing this `bc` is as
follows:
```
[ENVIRONMENT_VARIABLE=<value>...] ./configure.sh [build_options...]
make
make install
```
To get all of the options, including any useful environment variables, use the
following command:
```
./configure.sh -h
```
To learn the available `make` targets run the following command:
```
make help
```
See [Build Environment Variables](#build-environment-variables) for a more
detailed description of all accepted environment variables and
[Build Options](#build-options) for more detail about all accepted build
options.
<a name="cross-compiling"/>
## Cross Compiling
To cross-compile this `bc`, an appropriate compiler must be present and assigned
to the environment variable `HOSTCC`. This is in order to bootstrap core
file(s), if the architectures are not compatible (i.e., unlike i686 on x86_64).
Thus, the approach is:
```
HOSTCC="/path/to/native/compiler" ./configure.sh
make
make install
```
It is expected that `CC` produces code for the target system. See
[Build Environment Variables](#build-environment-variables) for more details.
<a name="build-environment-variables"/>
## Build Environment Variables
This `bc` supports `CC`, `CFLAGS`, `CPPFLAGS`, `LDFLAGS`, `LDLIBS`, `PREFIX`,
`DESTDIR`, and `HOSTCC` environment variables in the configure script. Any
values of those variables given to the configure command will be put into the
generated Makefile.
More detail on what those environment variables do can be found in the following
sections.
### `CC`
C compiler for the target system. `CC` must be compatible with POSIX `c99`
behavior and options.
Defaults to `c99`.
### `HOSTCC`
C compiler for the host system, used only in [cross compiling](#cross-compiling).
Defaults to `CC`.
### `CFLAGS`
Command-line flags that will be passed verbatim to both compilers (`CC` and
`HOSTCC`).
Defaults to empty.
### `CPPFLAGS`
Command-line flags for the C preprocessor. These are also passed verbatim to
both compilers (`CC` and `HOSTCC`); they are supported just for legacy reasons.
Defaults to empty.
### `LDFLAGS`
Command-line flags for the linker. These are also passed verbatim to both
compilers (`CC` and `HOSTCC`); they are supported just for legacy reasons.
Defaults to empty.
### `LDLIBS`
Libraries to link to. These are also passed verbatim to both compilers (`CC` and
`HOSTCC`); they are supported just for legacy reasons and for cross compiling
with different C standard libraries (like [musl][3]).
Defaults to empty.
### `PREFIX`
The prefix to install to.
Defaults to `/usr/local`.
### `DESTDIR`
Path to prepend onto `PREFIX`. This is mostly for distro and package
maintainers.
Defaults to empty.
<a name="build-options"/>
## Build Options
This `bc` comes with several build options, all of which are enabled by default.
All options can be used with each other, with a few exceptions that will be
noted below. Also, array references are turned off automatically when building
only `dc`.
### `bc` Only
To build `bc` only (no `dc`), use either one of the following commands for the
configure step:
```
./configure.sh -b
./configure.sh -D
```
Those two commands are equivalent.
***Warning***: It is an error to use those options if `bc` has also been
disabled (see below).
### `dc` Only
To build `dc` only (no `bc`), use either one of the following commands for the
configure step:
```
./configure.sh -d
./configure.sh -B
```
Those two commands are equivalent.
***Warning***: It is an error to use those options if `dc` has also been
disabled (see above).
### Signal Handling
To disable signal handling, use the `-S` flag in the configure step:
```
./configure.sh -S
```
### History
To disable signal handling, use the `-H` flag in the configure step:
```
./configure.sh -H
```
***WARNING***: Of all of the code in the `bc`, this is the only code that is not
completely portable. If the `bc` does not work on your platform, your first step
should be to retry with history disabled.
### Array References
Array references are an extension to the [standard][1] first implemented by the
[GNU `bc`][2]. They can be disabled by using the `-R` flag in the configure
step:
```
./configure.sh -R
```
### Extra Math
This `bc` has 7 extra operators: `$` (truncation to integer), `@` (set
precision), `<<` (shift number left; shifts radix right), `>>` (shift number
right; shifts radix left), and assignment versions of the last three (`@=`,
`<<=`, and `>>=`), though not for `$` since it is a unary operator. The
assignment versions are not available in `dc`, but the others are, as the
operators `$`, `@`, `H`, and `h`, respectively.
Extra operators can be disabled using the `-E` flag in the configure step:
```
./configure.sh -E
```
This `bc` also has a larger library that is only enabled if extra operators are.
More information about the functions can be found in the
[Extended Library](./bc.md#extended-library) section of the
[full manual](./bc.md).
## Optimization
The configure script will accept an optimization level to pass to the compiler.
Because `bc` is orders of magnitude faster with optimization, I ***highly***
recommend package and distro maintainers pass the highest optimization level
available in `CC` to the configure script, as follows:
```
./configure.sh -O3
make
make install
```
As usual, the configure script will also accept additional `CFLAGS` on the
command line, so for SSE4 architectures, the following can add a bit more speed:
```
CFLAGS="-march=native -msse4" ./configure.sh -O3
make
make install
```
Building with link-time optimization can further increase the performance.
Manual stripping is not necessary; non-debug builds are automatically stripped
in the link stage.
## Debug Builds
Debug builds (which also disable optimization if no optimization level is given
and if no extra `CFLAGS` are given) can be enabled with:
```
./configure.sh -g
make
make install
```
### Testing
All available tests can be run by running the following command:
```
make test
```
This `bc`, if built, assumes a working `bc` in the `PATH` to generate some
tests. The same goes for `dc`.
[1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
[2]: https://www.gnu.org/software/bc/
[3]: https://www.musl-libc.org/
Loading…
Cancel
Save