contrib/bc: update to version 6.4.0

This version contains a fix for an issue that can affect complex
bc scripts that use multiple read() functions that receive input from
an interactive user. The same value could be returned multiple times.

MFC after:	2 weeks
This commit is contained in:
Stefan Eßer 2023-03-10 11:33:33 +01:00
parent cc0fe048ec
commit 175a4d1042
16 changed files with 1693 additions and 443 deletions

View file

@ -536,7 +536,6 @@ clean:%%CLEAN_PREREQS%%
@$(RM) -f $(BC_HELP_C) $(BC_HELP_O)
@$(RM) -f $(DC_HELP_C) $(DC_HELP_O)
@$(RM) -fr vs/bin/ vs/lib/
@$(RM) -f $(BCL_PC)
clean_benchmarks:
@printf 'Cleaning benchmarks...\n'
@ -550,6 +549,7 @@ clean_config: clean clean_benchmarks
@$(RM) -f $(BC_MD) $(BC_MANPAGE)
@$(RM) -f $(DC_MD) $(DC_MANPAGE)
@$(RM) -f compile_commands.json
@$(RM) -f $(BCL_PC)
clean_coverage:
@printf 'Cleaning coverage files...\n'

View file

@ -1,5 +1,24 @@
# News
## 6.4.0
This is a production release that fixes a `read()`/`?` bug and adds features to
`bcl`.
The bug was that multiple read calls could repeat old data.
The new features in `bcl` are functions to preserve `BclNumber` arguments and
not free them.
***WARNING for `bcl` Users***: The `bcl_rand_seedWithNum()` function used to not
consume its arguments. Now it does. This change could have made this version
`7.0.0`, but I'm 99.9% confident that there are no `bcl` users, or if there are,
they probably don't use the PRNG. So I took a risk and didn't update the major
version.
`bcl` now includes more capacity to check for invalid numbers when built to run
under Valgrind.
## 6.3.1
This is a production release that fixes a `bc` dependency loop for minimal

View file

@ -1801,7 +1801,7 @@ if [ "$library" -ne 0 ]; then
contents=$(replace "$contents" "LIBDIR" "$LIBDIR")
contents=$(replace "$contents" "VERSION" "$version")
printf '%s\n' "$contents" > "./bcl.pc"
printf '%s\n' "$contents" > "$scriptdir/bcl.pc"
pkg_config_install="\$(SAFE_INSTALL) \$(PC_INSTALL_ARGS) \"\$(BCL_PC)\" \"\$(DESTDIR)\$(PC_PATH)/\$(BCL_PC)\""
pkg_config_uninstall="\$(RM) -f \"\$(DESTDIR)\$(PC_PATH)/\$(BCL_PC)\""

View file

@ -36,6 +36,9 @@
#ifndef BC_BCL_H
#define BC_BCL_H
// TODO: Add a generation index when building with Valgrind to check for
// use-after-free's or double frees.
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
@ -238,42 +241,78 @@ bcl_dup(BclNumber s);
BclError
bcl_bigdig(BclNumber n, BclBigDig* result);
BclError
bcl_bigdig_keep(BclNumber n, BclBigDig* result);
BclNumber
bcl_bigdig2num(BclBigDig val);
BclNumber
bcl_add(BclNumber a, BclNumber b);
BclNumber
bcl_add_keep(BclNumber a, BclNumber b);
BclNumber
bcl_sub(BclNumber a, BclNumber b);
BclNumber
bcl_sub_keep(BclNumber a, BclNumber b);
BclNumber
bcl_mul(BclNumber a, BclNumber b);
BclNumber
bcl_mul_keep(BclNumber a, BclNumber b);
BclNumber
bcl_div(BclNumber a, BclNumber b);
BclNumber
bcl_div_keep(BclNumber a, BclNumber b);
BclNumber
bcl_mod(BclNumber a, BclNumber b);
BclNumber
bcl_mod_keep(BclNumber a, BclNumber b);
BclNumber
bcl_pow(BclNumber a, BclNumber b);
BclNumber
bcl_pow_keep(BclNumber a, BclNumber b);
BclNumber
bcl_lshift(BclNumber a, BclNumber b);
BclNumber
bcl_lshift_keep(BclNumber a, BclNumber b);
BclNumber
bcl_rshift(BclNumber a, BclNumber b);
BclNumber
bcl_rshift_keep(BclNumber a, BclNumber b);
BclNumber
bcl_sqrt(BclNumber a);
BclNumber
bcl_sqrt_keep(BclNumber a);
BclError
bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d);
BclError
bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d);
BclNumber
bcl_modexp(BclNumber a, BclNumber b, BclNumber c);
BclNumber
bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c);
ssize_t
bcl_cmp(BclNumber a, BclNumber b);
@ -289,18 +328,30 @@ bcl_parse(const char* restrict val);
char*
bcl_string(BclNumber n);
char*
bcl_string_keep(BclNumber n);
BclNumber
bcl_irand(BclNumber a);
BclNumber
bcl_irand_keep(BclNumber a);
BclNumber
bcl_frand(size_t places);
BclNumber
bcl_ifrand(BclNumber a, size_t places);
BclNumber
bcl_ifrand_keep(BclNumber a, size_t places);
BclError
bcl_rand_seedWithNum(BclNumber n);
BclError
bcl_rand_seedWithNum_keep(BclNumber n);
BclError
bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]);

View file

@ -47,6 +47,145 @@
#include <num.h>
#include <vm.h>
#if BC_ENABLE_MEMCHECK
/**
* A typedef for Valgrind builds. This is to add a generation index for error
* checking.
*/
typedef struct BclNum
{
/// The number.
BcNum n;
/// The generation index.
size_t gen_idx;
} BclNum;
/**
* Clears the generation byte in a BclNumber and returns the value.
* @param n The BclNumber.
* @return The value of the index.
*/
#define BCL_NO_GEN(n) \
((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
/**
* Gets the generation index in a BclNumber.
* @param n The BclNumber.
* @return The generation index.
*/
#define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
/**
* Turns a BclNumber into a BcNum.
* @param c The context.
* @param n The BclNumber.
*/
#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
/**
* Clears the generation index top byte in the BclNumber.
* @param n The BclNumber.
*/
#define BCL_CLEAR_GEN(n) \
do \
{ \
(n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
} \
while (0)
#define BCL_CHECK_NUM_GEN(c, bn) \
do \
{ \
size_t gen_ = BCL_GET_GEN(bn); \
BclNum* ptr_ = BCL_NUM(c, bn); \
if (BCL_NUM_ARRAY(ptr_) == NULL) \
{ \
bcl_nonexistentNum(); \
} \
if (gen_ != ptr_->gen_idx) \
{ \
bcl_invalidGeneration(); \
} \
} \
while (0)
#define BCL_CHECK_NUM_VALID(c, bn) \
do \
{ \
size_t idx_ = BCL_NO_GEN(bn); \
if ((c)->nums.len <= idx_) \
{ \
bcl_numIdxOutOfRange(); \
} \
BCL_CHECK_NUM_GEN(c, bn); \
} \
while (0)
/**
* Returns the limb array of the number.
* @param bn The number.
* @return The limb array.
*/
#define BCL_NUM_ARRAY(bn) ((bn)->n.num)
/**
* Returns the limb array of the number for a non-pointer.
* @param bn The number.
* @return The limb array.
*/
#define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
/**
* Returns the BcNum pointer.
* @param bn The number.
* @return The BcNum pointer.
*/
#define BCL_NUM_NUM(bn) (&(bn)->n)
/**
* Returns the BcNum pointer for a non-pointer.
* @param bn The number.
* @return The BcNum pointer.
*/
#define BCL_NUM_NUM_NP(bn) (&(bn).n)
// These functions only abort. They exist to give developers some idea of what
// went wrong when bugs are found, if they look at the Valgrind stack trace.
BC_NORETURN void
bcl_invalidGeneration(void);
BC_NORETURN void
bcl_nonexistentNum(void);
BC_NORETURN void
bcl_numIdxOutOfRange(void);
#else // BC_ENABLE_MEMCHECK
/**
* A typedef for non-Valgrind builds.
*/
typedef BcNum BclNum;
#define BCL_NO_GEN(n) ((n).i)
#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i))
#define BCL_CLEAR_GEN(n) ((void) (n))
#define BCL_CHECK_NUM_GEN(c, bn)
#define BCL_CHECK_NUM_VALID(c, n)
#define BCL_NUM_ARRAY(bn) ((bn)->num)
#define BCL_NUM_ARRAY_NP(bn) ((bn).num)
#define BCL_NUM_NUM(bn) (bn)
#define BCL_NUM_NUM_NP(bn) (&(bn))
#endif // BC_ENABLE_MEMCHECK
/**
* A header that sets a jump.
* @param vm The thread data.
@ -88,19 +227,19 @@
* idx.
* @param c The context.
* @param e The error.
* @param n The number.
* @param bn The number.
* @param idx The idx to set as the return value.
*/
#define BC_MAYBE_SETUP(c, e, n, idx) \
do \
{ \
if (BC_ERR((e) != BCL_ERROR_NONE)) \
{ \
if ((n).num != NULL) bc_num_free(&(n)); \
idx.i = 0 - (size_t) (e); \
} \
else idx = bcl_num_insert(c, &(n)); \
} \
#define BC_MAYBE_SETUP(c, e, bn, idx) \
do \
{ \
if (BC_ERR((e) != BCL_ERROR_NONE)) \
{ \
if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
idx.i = 0 - (size_t) (e); \
} \
else idx = bcl_num_insert(c, &(bn)); \
} \
while (0)
/**
@ -108,17 +247,17 @@
* is bad.
* @param c The context.
*/
#define BC_CHECK_CTXT(vm, c) \
do \
{ \
c = bcl_contextHelper(vm); \
if (BC_ERR(c == NULL)) \
{ \
BclNumber n_num; \
n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
return n_num; \
} \
} \
#define BC_CHECK_CTXT(vm, c) \
do \
{ \
c = bcl_contextHelper(vm); \
if (BC_ERR(c == NULL)) \
{ \
BclNumber n_num_; \
n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
return n_num_; \
} \
} \
while (0)
/**
@ -157,16 +296,18 @@
#define BC_CHECK_NUM(c, n) \
do \
{ \
if (BC_ERR((n).i >= (c)->nums.len)) \
size_t no_gen_ = BCL_NO_GEN(n); \
if (BC_ERR(no_gen_ >= (c)->nums.len)) \
{ \
if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
else \
{ \
BclNumber n_num; \
n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
return n_num; \
BclNumber n_num_; \
n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
return n_num_; \
} \
} \
BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
@ -181,7 +322,8 @@
#define BC_CHECK_NUM_ERR(c, n) \
do \
{ \
if (BC_ERR((n).i >= (c)->nums.len)) \
size_t no_gen_ = BCL_NO_GEN(n); \
if (BC_ERR(no_gen_ >= (c)->nums.len)) \
{ \
if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
{ \
@ -189,17 +331,25 @@
} \
else return BCL_ERROR_INVALID_NUM; \
} \
BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
//clang-format on
/**
* Turns a BclNumber into a BcNum.
* Grows the context's nums array if necessary.
* @param c The context.
* @param n The BclNumber.
*/
#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
#define BCL_GROW_NUMS(c) \
do \
{ \
if ((c)->free_nums.len == 0) \
{ \
bc_vec_grow(&((c)->nums), 1); \
} \
} \
while (0)
/**
* Frees a BcNum for bcl. This is a destructor.

View file

@ -904,148 +904,82 @@ extern const char bc_program_esc_seqs[];
#if BC_ENABLE_EXTRA_MATH
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_NEG, \
&&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_TRUNC, \
&&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_PLACES, \
&&lbl_BC_INST_LSHIFT, \
&&lbl_BC_INST_RSHIFT, \
&&lbl_BC_INST_REL_EQ, \
&&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, \
&&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, \
&&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, \
&&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_NO_VAL, \
&&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, \
&&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, \
&&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, \
&&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, \
&&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_SEED, \
&&lbl_BC_INST_LENGTH, \
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_RAND, \
&&lbl_BC_INST_MAXIBASE, \
&&lbl_BC_INST_MAXOBASE, \
&&lbl_BC_INST_MAXSCALE, \
&&lbl_BC_INST_MAXRAND, \
&&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_LEADING_ZERO, \
&&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, \
&&lbl_BC_INST_STR, \
&&lbl_BC_INST_POP, \
&&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, \
&&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, \
&&lbl_BC_INST_EXTENDED_REGISTERS, \
&&lbl_BC_INST_POP_EXEC, \
&&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, \
&&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, \
&&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, \
&&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, \
&&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, \
&&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, \
&&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_NEG, &&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_TRUNC, &&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, &&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, &&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, &&lbl_BC_INST_PLACES, \
&&lbl_BC_INST_LSHIFT, &&lbl_BC_INST_RSHIFT, \
&&lbl_BC_INST_REL_EQ, &&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, &&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, &&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, &&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_NO_VAL, &&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, &&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, &&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, &&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, &&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_SEED, &&lbl_BC_INST_LENGTH, \
&&lbl_BC_INST_SCALE_FUNC, &&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, &&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, &&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, &&lbl_BC_INST_READ, \
&&lbl_BC_INST_RAND, &&lbl_BC_INST_MAXIBASE, \
&&lbl_BC_INST_MAXOBASE, &&lbl_BC_INST_MAXSCALE, \
&&lbl_BC_INST_MAXRAND, &&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_LEADING_ZERO, &&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, &&lbl_BC_INST_STR, \
&&lbl_BC_INST_POP, &&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, &&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, &&lbl_BC_INST_EXTENDED_REGISTERS, \
&&lbl_BC_INST_POP_EXEC, &&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, &&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, &&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, &&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, &&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, &&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, &&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
}
#else // BC_ENABLE_EXTRA_MATH
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_NEG, \
&&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_REL_EQ, \
&&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, \
&&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, \
&&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, \
&&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_NO_VAL, \
&&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, \
&&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, \
&&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, \
&&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, \
&&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_LENGTH, \
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
&&lbl_BC_INST_MAXOBASE, \
&&lbl_BC_INST_MAXSCALE, \
&&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_LEADING_ZERO, \
&&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, \
&&lbl_BC_INST_STR, \
&&lbl_BC_INST_POP, \
&&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, \
&&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, \
&&lbl_BC_INST_EXTENDED_REGISTERS, \
&&lbl_BC_INST_POP_EXEC, \
&&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, \
&&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, \
&&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, \
&&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, \
&&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, \
&&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, \
&&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_NEG, &&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_POWER, &&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, &&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, &&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_REL_EQ, &&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, &&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, &&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, &&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_NO_VAL, &&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, &&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, &&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, &&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, &&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_LENGTH, &&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, &&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, &&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, &&lbl_BC_INST_MAXOBASE, \
&&lbl_BC_INST_MAXSCALE, &&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_LEADING_ZERO, &&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, &&lbl_BC_INST_STR, \
&&lbl_BC_INST_POP, &&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, &&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, &&lbl_BC_INST_EXTENDED_REGISTERS, \
&&lbl_BC_INST_POP_EXEC, &&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, &&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, &&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, &&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, &&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, &&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, &&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
}
#endif // BC_ENABLE_EXTRA_MATH

View file

@ -37,6 +37,6 @@
#define BC_VERSION_H
/// The current version.
#define VERSION 6.3.1
#define VERSION 6.4.0
#endif // BC_VERSION_H

View file

@ -560,9 +560,13 @@ typedef struct BcVm
/// The vector for creating strings to pass to the client.
BcVec out;
#if BC_ENABLE_EXTRA_MATH
/// The PRNG.
BcRNG rng;
#endif // BC_ENABLE_EXTRA_MATH
/// The current error.
BclError err;

View file

@ -139,9 +139,14 @@ integers.
.PP
\f[B]char* bcl_string(BclNumber\f[R] \f[I]n\f[R]\f[B]);\f[R]
.PP
\f[B]char* bcl_string_keep(BclNumber\f[R] \f[I]n\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_bigdig(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig
*\f[R]\f[I]result\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_bigdig_keep(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig
*\f[R]\f[I]result\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_bigdig2num(BclBigDig\f[R] \f[I]val\f[R]\f[B]);\f[R]
.SS Math
.PP
@ -150,35 +155,68 @@ These items allow clients to run math on numbers.
\f[B]BclNumber bcl_add(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_add_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_sub(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_sub_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_mul(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_mul_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_div(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_div_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_mod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_mod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_pow(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_pow_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_lshift(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_lshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_rshift(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_rshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_sqrt(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_sqrt_keep(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_divmod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber
*\f[R]\f[I]d\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_divmod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B],
BclNumber *\f[R]\f[I]d\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_modexp(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_modexp_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B]);\f[R]
.SS Miscellaneous
.PP
These items are miscellaneous.
@ -209,14 +247,22 @@ generator in bcl(3).
.PP
\f[B]BclNumber bcl_irand(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_irand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_frand(size_t\f[R] \f[I]places\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_ifrand(BclNumber\f[R] \f[I]a\f[R]\f[B], size_t\f[R]
\f[I]places\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_ifrand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
size_t\f[R] \f[I]places\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_rand_seedWithNum(BclNumber\f[R]
\f[I]n\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_rand_seedWithNum_keep(BclNumber\f[R]
\f[I]n\f[R]\f[B]);\f[R]
.PP
\f[B]BclError bcl_rand_seed(unsigned char\f[R]
\f[I]seed\f[R]\f[B][\f[R]\f[I]BCL_SEED_SIZE\f[R]\f[B]]);\f[R]
.PP
@ -608,8 +654,9 @@ Returns the number of \f[I]significant decimal digits\f[R] in
.PP
All procedures in this section require a valid current context.
.PP
All procedures in this section consume the given \f[B]BclNumber\f[R]
arguments that are not given to pointer arguments.
All procedures in this section without the \f[B]_keep\f[R] suffix in
their name consume the given \f[B]BclNumber\f[R] arguments that are not
given to pointer arguments.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.TP
\f[B]BclNumber bcl_parse(const char *restrict\f[R] \f[I]val\f[R]\f[B])\f[R]
@ -644,6 +691,11 @@ The string is dynamically allocated and must be freed by the caller.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.RE
.TP
\f[B]char* bcl_string_keep(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
Returns a string representation of \f[I]n\f[R] according the the current
context\[cq]s \f[B]ibase\f[R].
The string is dynamically allocated and must be freed by the caller.
.TP
\f[B]BclError bcl_bigdig(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig *\f[R]\f[I]result\f[R]\f[B])\f[R]
Converts \f[I]n\f[R] into a \f[B]BclBigDig\f[R] and returns the result
in the space pointed to by \f[I]result\f[R].
@ -665,6 +717,24 @@ Otherwise, this function can return:
See the \f[B]Consumption and Propagation\f[R] subsection below.
.RE
.TP
\f[B]BclError bcl_bigdig_keep(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig *\f[R]\f[I]result\f[R]\f[B])\f[R]
Converts \f[I]n\f[R] into a \f[B]BclBigDig\f[R] and returns the result
in the space pointed to by \f[I]result\f[R].
.RS
.PP
\f[I]a\f[R] must be smaller than \f[B]BC_OVERFLOW_MAX\f[R].
See the \f[B]LIMITS\f[R] section.
.PP
If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
Otherwise, this function can return:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_OVERFLOW\f[R]
.RE
.TP
\f[B]BclNumber bcl_bigdig2num(BclBigDig\f[R] \f[I]val\f[R]\f[B])\f[R]
Creates a \f[B]BclNumber\f[R] from \f[I]val\f[R].
.RS
@ -681,6 +751,11 @@ Possible errors include:
.PP
All procedures in this section require a valid current context.
.PP
All procedures in this section without the \f[B]_keep\f[R] suffix in
their name consume the given \f[B]BclNumber\f[R] arguments that are not
given to pointer arguments.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.PP
All procedures in this section can return the following errors:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
@ -712,6 +787,25 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_add_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Adds \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
\f[I]a\f[R] and \f[I]b\f[R].
.RS
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_sub(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Subtracts \f[I]b\f[R] from \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
@ -735,6 +829,25 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_sub_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Subtracts \f[I]b\f[R] from \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
\f[I]a\f[R] and \f[I]b\f[R].
.RS
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_mul(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Multiplies \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
If \f[I]ascale\f[R] is the \f[I]scale\f[R] of \f[I]a\f[R] and
@ -761,6 +874,28 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_mul_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Multiplies \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
If \f[I]ascale\f[R] is the \f[I]scale\f[R] of \f[I]a\f[R] and
\f[I]bscale\f[R] is the \f[I]scale\f[R] of \f[I]b\f[R], the
\f[I]scale\f[R] of the result is equal to
\f[B]min(ascale+bscale,max(scale,ascale,bscale))\f[R], where
\f[B]min()\f[R] and \f[B]max()\f[R] return the obvious values.
.RS
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_div(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the \f[I]scale\f[R] of the current
@ -788,6 +923,29 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_div_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the \f[I]scale\f[R] of the current
context.
.RS
.PP
\f[I]b\f[R] cannot be \f[B]0\f[R].
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_mod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] to the \f[I]scale\f[R] of the current
context, computes the modulus \f[B]a-(a/b)*b\f[R], and returns the
@ -815,6 +973,29 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_mod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] to the \f[I]scale\f[R] of the current
context, computes the modulus \f[B]a-(a/b)*b\f[R], and returns the
modulus.
.RS
.PP
\f[I]b\f[R] cannot be \f[B]0\f[R].
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_pow(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Calculates \f[I]a\f[R] to the power of \f[I]b\f[R] to the
\f[I]scale\f[R] of the current context.
@ -851,6 +1032,38 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_pow_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Calculates \f[I]a\f[R] to the power of \f[I]b\f[R] to the
\f[I]scale\f[R] of the current context.
\f[I]b\f[R] must be an integer, but can be negative.
If it is negative, \f[I]a\f[R] must be non-zero.
.RS
.PP
\f[I]b\f[R] must be an integer.
If \f[I]b\f[R] is negative, \f[I]a\f[R] must not be \f[B]0\f[R].
.PP
\f[I]a\f[R] must be smaller than \f[B]BC_OVERFLOW_MAX\f[R].
See the \f[B]LIMITS\f[R] section.
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_OVERFLOW\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_lshift(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] left (moves the radix right) by \f[I]b\f[R] places
and returns the result.
@ -879,6 +1092,30 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_lshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] left (moves the radix right) by \f[I]b\f[R] places
and returns the result.
This is done in decimal.
\f[I]b\f[R] must be an integer.
.RS
.PP
\f[I]b\f[R] must be an integer.
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_rshift(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] right (moves the radix left) by \f[I]b\f[R] places
and returns the result.
@ -907,6 +1144,30 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_rshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] right (moves the radix left) by \f[I]b\f[R] places
and returns the result.
This is done in decimal.
\f[I]b\f[R] must be an integer.
.RS
.PP
\f[I]b\f[R] must be an integer.
.PP
\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_sqrt(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
Calculates the square root of \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
@ -931,6 +1192,27 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_sqrt_keep(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
Calculates the square root of \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
current context.
.RS
.PP
\f[I]a\f[R] cannot be negative.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclError bcl_divmod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber *\f[R]\f[I]d\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the quotient in a new
number which is put into the space pointed to by \f[I]c\f[R], and puts
@ -959,6 +1241,30 @@ Otherwise, this function can return:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclError bcl_divmod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber *\f[R]\f[I]d\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the quotient in a new
number which is put into the space pointed to by \f[I]c\f[R], and puts
the modulus in a new number which is put into the space pointed to by
\f[I]d\f[R].
.RS
.PP
\f[I]b\f[R] cannot be \f[B]0\f[R].
.PP
\f[I]c\f[R] and \f[I]d\f[R] cannot point to the same place, nor can they
point to the space occupied by \f[I]a\f[R] or \f[I]b\f[R].
.PP
If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
Otherwise, this function can return:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_modexp(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B])\f[R]
Computes a modular exponentiation where \f[I]a\f[R] is the base,
\f[I]b\f[R] is the exponent, and \f[I]c\f[R] is the modulus, and returns
@ -991,6 +1297,35 @@ Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_modexp_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B])\f[R]
Computes a modular exponentiation where \f[I]a\f[R] is the base,
\f[I]b\f[R] is the exponent, and \f[I]c\f[R] is the modulus, and returns
the result.
The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
current context.
.RS
.PP
\f[I]a\f[R], \f[I]b\f[R], and \f[I]c\f[R] must be integers.
\f[I]c\f[R] must not be \f[B]0\f[R].
\f[I]b\f[R] must not be negative.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.SS Miscellaneous
.TP
\f[B]void bcl_zero(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
@ -1060,6 +1395,11 @@ char[\f[R]\f[I]BCL_SEED_SIZE\f[R]\f[B]])\f[R]
.IP \[bu] 2
\f[B]bcl_rand_reseed(\f[R]\f[I]void\f[R]\f[B])\f[R]
.PP
All procedures in this section without the \f[B]_keep\f[R] suffix in
their name consume the given \f[B]BclNumber\f[R] arguments that are not
given to pointer arguments.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.PP
The following items allow clients to use the pseudo-random number
generator.
All procedures require a valid current context.
@ -1112,6 +1452,36 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_irand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
Returns a random number that is not larger than \f[I]a\f[R] in a new
number.
If \f[I]a\f[R] is \f[B]0\f[R] or \f[B]1\f[R], the new number is equal to
\f[B]0\f[R].
The bound is unlimited, so it is not bound to the size of
\f[B]BclRandInt\f[R].
This is done by generating as many random numbers as necessary,
multiplying them by certain exponents, and adding them all together.
.RS
.PP
\f[I]a\f[R] must be an integer and non-negative.
.PP
This procedure requires a valid current context.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_frand(size_t\f[R] \f[I]places\f[R]\f[B])\f[R]
Returns a random number between \f[B]0\f[R] (inclusive) and \f[B]1\f[R]
(exclusive) that has \f[I]places\f[R] decimal digits after the radix
@ -1158,11 +1528,55 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclNumber bcl_ifrand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], size_t\f[R] \f[I]places\f[R]\f[B])\f[R]
Returns a random number less than \f[I]a\f[R] with \f[I]places\f[R]
decimal digits after the radix (decimal point).
There are no limits on \f[I]a\f[R] or \f[I]places\f[R].
.RS
.PP
\f[I]a\f[R] must be an integer and non-negative.
.PP
This procedure requires a valid current context.
.PP
bcl(3) will encode an error in the return value, if there was one.
The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
\f[B]BclError bcl_rand_seedWithNum(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
Seeds the PRNG with \f[I]n\f[R].
.RS
.PP
\f[I]n\f[R] is \f[I]not\f[R] consumed.
\f[I]n\f[R] is consumed.
.PP
This procedure requires a valid current context.
.PP
If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
Otherwise, this function can return:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
.PP
Note that if \f[B]bcl_rand_seed2num(\f[R]\f[I]void\f[R]\f[B])\f[R] or
\f[B]bcl_rand_seed2num_err(BclNumber)\f[R] are called right after this
function, they are not guaranteed to return a number equal to
\f[I]n\f[R].
.RE
.TP
\f[B]BclError bcl_rand_seedWithNum_keep(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
Seeds the PRNG with \f[I]n\f[R].
.RS
.PP
This procedure requires a valid current context.
.PP
@ -1253,7 +1667,7 @@ so the example above should properly be:
.nf
\f[C]
BclNumber n = bcl_num_add(bcl_num_mul(a, b), bcl_num_div(c, d));
if (bc_num_err(n) != BCL_ERROR_NONE) {
if (bcl_err(n) != BCL_ERROR_NONE) {
// Handle the error.
}
\f[R]

View file

@ -136,8 +136,12 @@ These items allow clients to convert numbers into and from strings and integers.
**char\* bcl_string(BclNumber** _n_**);**
**char\* bcl_string_keep(BclNumber** _n_**);**
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**);**
**BclError bcl_bigdig_keep(BclNumber** _n_**, BclBigDig \***_result_**);**
**BclNumber bcl_bigdig2num(BclBigDig** _val_**);**
## Math
@ -146,26 +150,48 @@ These items allow clients to run math on numbers.
**BclNumber bcl_add(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_add_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_sub_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_mul_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_div_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_mod_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_pow_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_lshift_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_rshift_keep(BclNumber** _a_**, BclNumber** _b_**);**
**BclNumber bcl_sqrt(BclNumber** _a_**);**
**BclNumber bcl_sqrt_keep(BclNumber** _a_**);**
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**);**
**BclError bcl_divmod_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**);**
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**);**
**BclNumber bcl_modexp_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**);**
## Miscellaneous
These items are miscellaneous.
@ -195,12 +221,18 @@ generator in bcl(3).
**BclNumber bcl_irand(BclNumber** _a_**);**
**BclNumber bcl_irand_keep(BclNumber** _a_**);**
**BclNumber bcl_frand(size_t** _places_**);**
**BclNumber bcl_ifrand(BclNumber** _a_**, size_t** _places_**);**
**BclNumber bcl_ifrand_keep(BclNumber** _a_**, size_t** _places_**);**
**BclError bcl_rand_seedWithNum(BclNumber** _n_**);**
**BclError bcl_rand_seedWithNum_keep(BclNumber** _n_**);**
**BclError bcl_rand_seed(unsigned char** _seed_**[**_BCL_SEED_SIZE_**]);**
**void bcl_rand_reseed(**_void_**);**
@ -548,9 +580,9 @@ All procedures in this section require a valid current context.
All procedures in this section require a valid current context.
All procedures in this section consume the given **BclNumber** arguments that
are not given to pointer arguments. See the **Consumption and Propagation**
subsection below.
All procedures in this section without the **_keep** suffix in their name
consume the given **BclNumber** arguments that are not given to pointer
arguments. See the **Consumption and Propagation** subsection below.
**BclNumber bcl_parse(const char \*restrict** _val_**)**
@ -578,6 +610,12 @@ subsection below.
*n* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
**char\* bcl_string_keep(BclNumber** _n_**)**
: Returns a string representation of *n* according the the current context's
**ibase**. The string is dynamically allocated and must be freed by the
caller.
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**)**
: Converts *n* into a **BclBigDig** and returns the result in the space
@ -595,6 +633,20 @@ subsection below.
*n* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
**BclError bcl_bigdig_keep(BclNumber** _n_**, BclBigDig \***_result_**)**
: Converts *n* into a **BclBigDig** and returns the result in the space
pointed to by *result*.
*a* must be smaller than **BC_OVERFLOW_MAX**. See the **LIMITS** section.
If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
function can return:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_OVERFLOW**
**BclNumber bcl_bigdig2num(BclBigDig** _val_**)**
: Creates a **BclNumber** from *val*.
@ -609,6 +661,10 @@ subsection below.
All procedures in this section require a valid current context.
All procedures in this section without the **_keep** suffix in their name
consume the given **BclNumber** arguments that are not given to pointer
arguments. See the **Consumption and Propagation** subsection below.
All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_NUM**
@ -632,6 +688,20 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_add_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Adds *a* and *b* and returns the result. The *scale* of the result is the
max of the *scale*s of *a* and *b*.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**)**
: Subtracts *b* from *a* and returns the result. The *scale* of the result is
@ -649,6 +719,20 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_sub_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Subtracts *b* from *a* and returns the result. The *scale* of the result is
the max of the *scale*s of *a* and *b*.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**)**
: Multiplies *a* and *b* and returns the result. If *ascale* is the *scale* of
@ -668,6 +752,22 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_mul_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Multiplies *a* and *b* and returns the result. If *ascale* is the *scale* of
*a* and *bscale* is the *scale* of *b*, the *scale* of the result is equal
to **min(ascale+bscale,max(scale,ascale,bscale))**, where **min()** and
**max()** return the obvious values.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* and returns the result. The *scale* of the result is the
@ -688,6 +788,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_div_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* and returns the result. The *scale* of the result is the
*scale* of the current context.
*b* cannot be **0**.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* to the *scale* of the current context, computes the
@ -708,6 +825,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_mod_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* to the *scale* of the current context, computes the
modulus **a-(a/b)\*b**, and returns the modulus.
*b* cannot be **0**.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**)**
: Calculates *a* to the power of *b* to the *scale* of the current context.
@ -733,6 +867,28 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_pow_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Calculates *a* to the power of *b* to the *scale* of the current context.
*b* must be an integer, but can be negative. If it is negative, *a* must
be non-zero.
*b* must be an integer. If *b* is negative, *a* must not be **0**.
*a* must be smaller than **BC_OVERFLOW_MAX**. See the **LIMITS** section.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_MATH_OVERFLOW**
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* left (moves the radix right) by *b* places and returns the
@ -753,6 +909,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_lshift_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* left (moves the radix right) by *b* places and returns the
result. This is done in decimal. *b* must be an integer.
*b* must be an integer.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* right (moves the radix left) by *b* places and returns the
@ -773,6 +946,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_rshift_keep(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* right (moves the radix left) by *b* places and returns the
result. This is done in decimal. *b* must be an integer.
*b* must be an integer.
*a* and *b* can be the same number.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_sqrt(BclNumber** _a_**)**
: Calculates the square root of *a* and returns the result. The *scale* of the
@ -791,6 +981,21 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_sqrt_keep(BclNumber** _a_**)**
: Calculates the square root of *a* and returns the result. The *scale* of the
result is equal to the **scale** of the current context.
*a* cannot be negative.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**)**
: Divides *a* by *b* and returns the quotient in a new number which is put
@ -813,6 +1018,25 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclError bcl_divmod_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**)**
: Divides *a* by *b* and returns the quotient in a new number which is put
into the space pointed to by *c*, and puts the modulus in a new number which
is put into the space pointed to by *d*.
*b* cannot be **0**.
*c* and *d* cannot point to the same place, nor can they point to the space
occupied by *a* or *b*.
If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
function can return:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**)**
: Computes a modular exponentiation where *a* is the base, *b* is the
@ -835,6 +1059,25 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_modexp_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**)**
: Computes a modular exponentiation where *a* is the base, *b* is the
exponent, and *c* is the modulus, and returns the result. The *scale* of the
result is equal to the **scale** of the current context.
*a*, *b*, and *c* must be integers. *c* must not be **0**. *b* must not be
negative.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
## Miscellaneous
**void bcl_zero(BclNumber** _n_**)**
@ -891,6 +1134,10 @@ If necessary, the PRNG can be reseeded with one of the following functions:
* **bcl_rand_seed(unsigned char[**_BCL_SEED_SIZE_**])**
* **bcl_rand_reseed(**_void_**)**
All procedures in this section without the **_keep** suffix in their name
consume the given **BclNumber** arguments that are not given to pointer
arguments. See the **Consumption and Propagation** subsection below.
The following items allow clients to use the pseudo-random number generator. All
procedures require a valid current context.
@ -921,8 +1168,29 @@ procedures require a valid current context.
*a* must be an integer and non-negative.
*a* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
*a* is consumed; it cannot be used after the call. See the **Consumption and
Propagation** subsection below.
This procedure requires a valid current context.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_irand_keep(BclNumber** _a_**)**
: Returns a random number that is not larger than *a* in a new number. If *a*
is **0** or **1**, the new number is equal to **0**. The bound is unlimited,
so it is not bound to the size of **BclRandInt**. This is done by generating
as many random numbers as necessary, multiplying them by certain exponents,
and adding them all together.
*a* must be an integer and non-negative.
This procedure requires a valid current context.
@ -956,8 +1224,26 @@ procedures require a valid current context.
*a* must be an integer and non-negative.
*a* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
*a* is consumed; it cannot be used after the call. See the **Consumption and
Propagation** subsection below.
This procedure requires a valid current context.
bcl(3) will encode an error in the return value, if there was one. The error
can be queried with **bcl_err(BclNumber)**. Possible errors include:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
**BclNumber bcl_ifrand_keep(BclNumber** _a_**, size_t** _places_**)**
: Returns a random number less than *a* with *places* decimal digits after the
radix (decimal point). There are no limits on *a* or *places*.
*a* must be an integer and non-negative.
This procedure requires a valid current context.
@ -974,7 +1260,23 @@ procedures require a valid current context.
: Seeds the PRNG with *n*.
*n* is *not* consumed.
*n* is consumed.
This procedure requires a valid current context.
If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
function can return:
* **BCL_ERROR_INVALID_NUM**
* **BCL_ERROR_INVALID_CONTEXT**
Note that if **bcl_rand_seed2num(**_void_**)** or
**bcl_rand_seed2num_err(BclNumber)** are called right after this function,
they are not guaranteed to return a number equal to *n*.
**BclError bcl_rand_seedWithNum_keep(BclNumber** _n_**)**
: Seeds the PRNG with *n*.
This procedure requires a valid current context.
@ -1046,7 +1348,7 @@ checked with **bcl_err(BclNumber)**, so the example above should properly
be:
BclNumber n = bcl_num_add(bcl_num_mul(a, b), bcl_num_div(c, d));
if (bc_num_err(n) != BCL_ERROR_NONE) {
if (bcl_err(n) != BCL_ERROR_NONE) {
// Handle the error.
}

View file

@ -1151,47 +1151,60 @@ const uchar dc_parse_insts[] = {
#if BC_ENABLE_EXTRA_MATH
BC_INST_TRUNC,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
BC_INST_POWER, BC_INST_MULTIPLY,
BC_INST_DIVIDE, BC_INST_MODULUS,
BC_INST_PLUS, BC_INST_MINUS,
#if BC_ENABLE_EXTRA_MATH
BC_INST_PLACES, BC_INST_LSHIFT, BC_INST_RSHIFT,
BC_INST_PLACES, BC_INST_LSHIFT,
BC_INST_RSHIFT,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_BOOL_OR, BC_INST_BOOL_AND,
#if BC_ENABLED
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID,
#endif // BC_ENABLE_EXTRA_MATH
#endif // BC_ENABLED
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_REL_GT, BC_INST_REL_LT, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
BC_INST_INVALID, BC_INST_REL_LE, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_REL_GT,
BC_INST_REL_LT, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_REL_GE, BC_INST_INVALID,
BC_INST_REL_LE, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
#if BC_ENABLED
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID,
#endif // BC_ENABLED
BC_INST_IBASE, BC_INST_OBASE, BC_INST_SCALE,
BC_INST_IBASE, BC_INST_OBASE,
BC_INST_SCALE,
#if BC_ENABLE_EXTRA_MATH
BC_INST_SEED,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_LENGTH, BC_INST_PRINT, BC_INST_SQRT,
BC_INST_ABS, BC_INST_IS_NUMBER, BC_INST_IS_STRING,
BC_INST_LENGTH, BC_INST_PRINT,
BC_INST_SQRT, BC_INST_ABS,
BC_INST_IS_NUMBER, BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
BC_INST_IRAND,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_ASCIIFY, BC_INST_MODEXP, BC_INST_DIVMOD,
BC_INST_QUIT, BC_INST_INVALID,
BC_INST_ASCIIFY, BC_INST_MODEXP,
BC_INST_DIVMOD, BC_INST_QUIT,
BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
BC_INST_RAND,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_MAXIBASE, BC_INST_MAXOBASE, BC_INST_MAXSCALE,
BC_INST_MAXIBASE, BC_INST_MAXOBASE,
BC_INST_MAXSCALE,
#if BC_ENABLE_EXTRA_MATH
BC_INST_MAXRAND,
#endif // BC_ENABLE_EXTRA_MATH
@ -1199,17 +1212,21 @@ const uchar dc_parse_insts[] = {
#if BC_ENABLED
BC_INST_INVALID,
#endif // BC_ENABLED
BC_INST_LEADING_ZERO, BC_INST_PRINT_STREAM, BC_INST_INVALID,
BC_INST_EXTENDED_REGISTERS, BC_INST_REL_EQ, BC_INST_INVALID,
BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
BC_INST_INVALID, BC_INST_STACK_LEN, BC_INST_DUPLICATE,
BC_INST_SWAP, BC_INST_POP, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_LEADING_ZERO, BC_INST_PRINT_STREAM,
BC_INST_INVALID, BC_INST_EXTENDED_REGISTERS,
BC_INST_REL_EQ, BC_INST_INVALID,
BC_INST_EXECUTE, BC_INST_PRINT_STACK,
BC_INST_CLEAR_STACK, BC_INST_INVALID,
BC_INST_STACK_LEN, BC_INST_DUPLICATE,
BC_INST_SWAP, BC_INST_POP,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
BC_INST_INVALID,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_PRINT_POP, BC_INST_NQUIT, BC_INST_EXEC_STACK_LEN,
BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_PRINT_POP,
BC_INST_NQUIT, BC_INST_EXEC_STACK_LEN,
BC_INST_SCALE_FUNC, BC_INST_INVALID,
};
#endif // DC_ENABLED

File diff suppressed because it is too large Load diff

View file

@ -757,9 +757,16 @@ bc_program_read(BcProgram* p)
// struct.
bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
}
// This needs to be updated because the parser could have been used
// somewhere else
else bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
else
{
// This needs to be updated because the parser could have been used
// somewhere else.
bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
// The read buffer also needs to be emptied or else it will still
// contain previous read expressions.
bc_vec_empty(&vm->read_buf);
}
BC_SETJMP_LOCKED(vm, exec_err);

View file

@ -643,12 +643,14 @@ bc_vm_shutdown(void)
if (vm->catalog != BC_VM_INVALID_CATALOG) catclose(vm->catalog);
#endif // BC_ENABLE_NLS
#if !BC_ENABLE_LIBRARY
#if BC_ENABLE_HISTORY
// This must always run to ensure that the terminal is back to normal, i.e.,
// has raw mode disabled. But we should only do it if we did not have a bad
// terminal because history was not initialized if it is a bad terminal.
if (BC_TTY && !vm->history.badTerm) bc_history_free(&vm->history);
#endif // BC_ENABLE_HISTORY
#endif // !BC_ENABLE_LIBRARY
#if BC_DEBUG
#if !BC_ENABLE_LIBRARY

View file

@ -55,7 +55,7 @@ main(void)
BclError e;
BclContext ctxt;
size_t scale;
BclNumber n, n2, n3, n4, n5, n6;
BclNumber n, n2, n3, n4, n5, n6, n7;
char* res;
BclBigDig b = 0;
@ -123,16 +123,42 @@ main(void)
// parse numbers as negative.
if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
// Add them and check the result.
n5 = bcl_add_keep(n3, n4);
err(bcl_err(n5));
res = bcl_string(n5);
if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
// We want to ensure all memory gets freed because we run this under
// Valgrind.
free(res);
// Add them and check the result.
n3 = bcl_add(n3, n4);
err(bcl_err(n3));
res = bcl_string(bcl_dup(n3));
res = bcl_string_keep(n3);
if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
// We want to ensure all memory gets freed because we run this under
// Valgrind.
free(res);
// Ensure that divmod, a special case, works.
n4 = bcl_parse("8937458902.2890347");
err(bcl_err(n4));
e = bcl_divmod_keep(n4, n3, &n5, &n6);
err(e);
res = bcl_string(n5);
if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
res = bcl_string(n6);
if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
// Ensure that divmod, a special case, works.
n4 = bcl_parse("8937458902.2890347");
err(bcl_err(n4));
@ -140,15 +166,11 @@ main(void)
err(e);
res = bcl_string(n5);
if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
res = bcl_string(n6);
if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
// Ensure that sqrt works. This is also a special case. The reason is
@ -213,10 +235,18 @@ main(void)
n3 = bcl_irand(n4);
err(bcl_err(n3));
// Repeat.
n2 = bcl_ifrand_keep(n3, 10);
err(bcl_err(n2));
// Repeat.
n2 = bcl_ifrand(bcl_dup(n3), 10);
err(bcl_err(n2));
// Still checking asserts.
e = bcl_rand_seedWithNum_keep(n3);
err(e);
// Still checking asserts.
e = bcl_rand_seedWithNum(n3);
err(e);
@ -229,9 +259,12 @@ main(void)
n5 = bcl_parse("10");
err(bcl_err(n5));
n6 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
n6 = bcl_modexp_keep(n5, n5, n5);
err(bcl_err(n6));
n7 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
err(bcl_err(n7));
// Clean up.
bcl_num_free(n);
@ -250,6 +283,11 @@ main(void)
n4 = bcl_parse("-1.01");
err(bcl_err(n4));
res = bcl_string_keep(n);
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
res = bcl_string(bcl_dup(n));
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);

View file

@ -74,6 +74,7 @@ results="$testdir/$d/read_results.txt"
errors="$testdir/$d/read_errors.txt"
out="$outputdir/${d}_outputs/read_results.txt"
multiple_res="$outputdir/${d}_outputs/read_multiple_results.txt"
outdir=$(dirname "$out")
# Make sure the directory exists.
@ -89,11 +90,13 @@ if [ "$d" = "bc" ]; then
halt="halt"
read_call="read()"
read_expr="${read_call}\n5+5;"
read_multiple=$(printf '%s\n%s\n%s\n' "3" "2" "1")
else
options="-x"
halt="q"
read_call="?"
read_expr="${read_call}"
read_multiple=$(printf '%spR\n%spR\n%spR\n' "3" "2" "1")
fi
# I use these, so unset them to make the tests work.
@ -116,6 +119,16 @@ done < "$name"
printf 'pass\n'
printf 'Running %s read multiple...' "$d"
printf '3\n2\n1\n' > "$multiple_res"
# Run multiple read() calls.
printf '%s\n' "$read_multiple" | "$exe" "$@" "$options" -e "$read_call" -e "$read_call" -e "$read_call" > "$out"
checktest "$d" "$?" 'read multiple' "$multiple_res" "$out"
printf 'pass\n'
printf 'Running %s read errors...' "$d"
# Run read on every line.