parrotcode: A decimal arithmetic library for Perl and Parrot | |
Contents | Big Number Arithmetic |
types/bignum.c - A decimal arithmetic library for Perl and Parrot
This code is intended for inclusion in the parrot project, and also for backporting into Perl5 (as a CPAN module). Any patches to this code will likely find their way back to the Mother Ship, as it were.
There is a good deal of scope for improving the speed of this code, modifications are encouraged as long as the extended regression tests continue to pass. Alex Gough, 2002
It was a very inconvenient habit of kittens (Alice had once made the remark) that, whatever you say to them, they always purr. "If they would only purr for `yes,' and mew for `no,' or any rule of that sort," she had said, "so that one could keep up a conversation! But how can you talk with a person if they always say the same thing?"
On this occasion the kitten only purred: and it was impossible to guess whether it meant `yes' or `no'.
When the library is used within parrot, all calls expect an additional first argument of an interpreter, for the purposes of memory allocation, some internal macros do not (getd/setd and CHECK(O|U)FLOW.
If you're being useful and inserting proper rapid fillins,
start with the BN_i*
methods,
but make sure any errors can still be thrown.
Access digits, macros assume length given.
BN_setd(BIGNUM*, pos, value)
pos
(zero is lsd) to value
.int BN_getd(BIGNUM*, pos)
pos
.CHECK_OVERFLOW(bn, incr, context)
bn
by incr
will cause overflow (as decided by elimit
),
returns true.CHECK_UNDERFLOW(bn, decrement, context)
decrement
(a positive number) from the exponent of bn
would cause underflow,
returns true.Special Values
am_INF(bn)
bn
is +Infinity or -Infinity.am_NAN(bn)
bn
is either a quiet or signalling NaN.am_sNAN(bn)
bn
is a signalling NaN.am_qNAN(bn)
bn
is a quiet NaN.BIGNUM *BN_new(PINTD_ INTVAL length)
BIGNUM
.
length
is number of decimal digits required.
The bignumber will be equal to zero.void BN_grow(PINTD_ BIGNUM *in, INTVAL length)
length
decimal digits,
does not modify the value of the bignumber.void BN_destroy(PINTD_ BIGNUM *bn)
BN_CONTEXT *BN_create_context(PINTD_ INTVAL precision)
elimit = BN_HARD_EXPN_LIMIT ( defined during configure)
rounding = ROUND_HALF_UP
extended = 1
flags = 0
traps = Division by zero, invalid operation, overflow, underflow
and rounded are enabled.
Lost digits and inexact are disabled.
free()
.INTVAL BN_set_digit(PINT_ BIGNUM *bn, INTVAL pos, INTVAL value)
pos
(zero based) to value
. Number is grown if digits > allocated space are accessed, but intermediate digits will have undefined values. If pos
is beyond digits
then digits
is also updated.INTVAL BN_get_digit(PINTD_ BIGNUM *bn, INTVAL pos)
pos
, returns -1 if pos
is out of bounds.int BN_set_inf(PINTD_ BIGNUM *bn)
int BN_set_qNAN(PINTD_ BIGNUM *bn)
int BN_set_sNAN(PINTD_ BIGNUM *bn)
flags
set to BN_inf_FLAGS
.int BN_set_verybig(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
bn
according to context->rounding
and the sign of bn
: ROUND_HALF_UP, ROUND_HALF_EVEN => sign Infinity
ROUND_DOWN => sign, largest finite number in given precision (or Inf, if
infinite precision is specified)
ROUND_CEILING => same as round down, if sign is 1, +Inf otherwise
ROUND_FLOOR => same as round down, if sign is 0, -Inf otherwise
BIGNUM *BN_copy(PINTD_ BIGNUM *one, BIGNUM *two)
BIGNUM *BN_new_from_int(PINTD_ INTVAL value)
INTVAL
) We assume that the implementation limits are somewhat larger than those required to store a single integer into a bignum.void BN_PRINT_DEBUG (BIGNUM *bn, char *mesg)
INTVAL BN_nonfatal(PINTD_ BN_CONTEXT *context, BN_EXCEPTIONS except, char *msg)
void BN_exception(PINTD_ BN_EXCEPTIONS exception, char *message)
BN_EXCEPT
macro, this version is provided until Parrot exceptions are sorted out properly.INTVAL BN_to_scientific_string(PINTD_ BIGNUM*bn, char **dest)
INTVAL BN_to_engineering_string(PINTD_ BIGNUM*bn, char **dest)
*bn
into a engineering representation, stored in **dest
.char*
strings only, parrot may want to reimplement these so that locales and the like are nicely coped with.#ifdef
ed out if this is done.dest
is not freed by this function.INTVAL BN_to_scieng_string(PINTD_ BIGNUM *bn, char **dest, int eng)
eng
defines the conversion to perform.BIGNUM *BN_from_string(PINTD_ char *s2, BN_CONTEXT *context)
context
has extended
as a true value, then the full range of extended number is made available, and any string which does not match the numeric syntax is converted to a quiet NaN.int BN_strip_lead_zeros(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
int BN_strip_tail_zeros(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
int BN_make_integer(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
int BN_really_zero(PINTD_ BIGNUM *bn, int allow_neg_zero)
BN_is_zero()
.void BN_round(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
*bn
according to *context
.int BN_iround (PINTD_ BIGNUM *bn, BN_CONTEXT *context)
precision
is positive, the digit string is rounded to have no more than precision
digits. If precision
is equal to zero, the number is treated as an integer, and any digits after the number's decimal point are removed. If precision
is negative, the number is rounded so that there are no more than - precision
digits after the decimal point.ROUND_DOWN
precision: 4 => 1.234E+3 1234
precision: 6 => 1.234567E+3 1234.56
precision: 9 => 1.234567E+3 1234.567
precision: 0 => 1234 1234
precision: -1 => 1.2345E+3 1234.5
precision: -9 => 1.234567E+3 1234.567
int BN_round_up(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
bn
to have precision
digits, then adds 1 to the last digits and carries until done. Do not call this function with non-positive values of precision
.int BN_round_down(PINT_ BIGNUM *bn, BN_CONTEXT *context)
bn
to have precision
digits. Do not call this function with non-positive precision.void BN_round_as_integer(PINTD_ BIGNUM *bn, BN_CONTEXT *context)
precision
must be less than one. This rounds so that expn
is at least precision
. Name is slightly misleading.Operations are performed like this:
context->precision
digits.The general form for all arithmetic operations is:
void BN_operation(result, one, two, context)
int BN_arith_setup(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context, BN_SAVE_PREC *restore)
&restore
as a NULL
pointer to both setup and cleanup.int BN_arith_cleanup(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context, BN_SAVE_PREC *restore)
result
, one
, two
, checks for zeroness and makes integers. Fixes one
and two
so they don't gain precision by mistake.int BN_align(PINTD_ BIGNUM *one, BIGNUM *two)
void BN_add(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
int BN_iadd (PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
void BN_subtract(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*two
from *one
, returning value in *result
.int BN_isubtract (PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
void BN_plus(PINTD_ BIGNUM *result, BIGNUM *one, BN_CONTEXT *context)
+
on *one
. Does all the rounding and what have you.void BN_minus(PINTD_ BIGNUM *result, BIGNUM *one, BN_CONTEXT *context)
-
(minus) on *one
. Does all the rounding and what have you.void BN_compare (PINT_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*one
and *two
, storing the result (as a BIGNUM) in *result
. result = 1 => one > two
result = -1 => two > one
result = 0 => one == two
void BN_multiply (PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*one
and *two
, storing the result in *result
.int BN_imultiply (PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
void BN_divide(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
precision
digits in result. Performs own rounding. We also assume that this function will not be used to produce a BigInt. That is the job of divide_integer()
.precision
greater than the number of significant digits in either operand. If you want the result to be an integer or a numer with a fixed fractional partvoid BN_divide_integer (PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*one
divided by *two
into *result
.void BN_remainder(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*result
.BN_idivide(PINT_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context, BN_DIV_ENUM operation, BIGNUM *rem)
INTVAL BN_comp (PINTD_ BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
void BN_power(PINTD_ BIGNUM *result, BIGNUM *bignum, BIGNUM *expn, BN_CONTEXT *context)
result
= bignum
to the power of *expn
;void BN_rescale(PINTD_ BIGNUM *result, BIGNUM *one, BIGNUM *two, BN_CONTEXT *context)
*one
to have an exponent of *two
.INTVAL BN_to_int(PINT_ BIGNUM *bn, BN_CONTEXT *context)
INTVAL BN_is_zero(BIGNUM *foo, BN_CONTEXT *context)
*foo
is zero.Parrot string playing, exception raising
|