Here is a collection of basic operations available for integer values;
see also the more advanced functions in NumTheory
.
CoCoALib functions which expect integer values will accept either
machine integer values or BigInt
values -- they may be mixed. The
return type is usually BigInt
; the few cases where the return type
is long
are clearly indicated. Remember that basic arithmetic
operations between two machine integers are handled directly by C++
(with its rules and restrictions e.g. overflow).
If you want to write new functions which accept machine integers as
arguments, take a look at the class MachineInt
which is designed
for this purpose (handling both signed and unsigned machine integers
safely).
IsEven(n)
-- true iff n
is even
IsOdd(n)
-- true iff n
is odd
IsPowerOf2(n)
-- true iff n
is a (positive) power of 2
IsDivisible(n,d)
-- true iff n
is divisible by d
(throws ERR::DivByZero
if d
is zero)
IsSquare(n)
-- true iff n
is a perfect square
IsPower(n)
-- true iff n
is a perfect k-th power for some k > 1
IsExactIroot(X,n,r)
-- true iff n
is a perfect r
-th power, assigns iroot(N,r)
to X
Only for BigInt
IsZero(N)
-- true iff N
is zero
IsOne(N)
-- true iff N
is 1
IsMinusOne(N)
-- true iff N
is -1
=
assignment
+
the sum
-
the difference
*
the product
/
integer quotient (truncated "towards zero")
%
remainder, satisfies a = b*(a/b)+(a%b); see also LeastNNegRemainder
and SymmRemainder
NOTE: you cannot use ^
for exponentiation; you must use the function power
instead. We decided this
because it is too easy to write misleading code: for instance,
a*b^2
is interpreted by the compiler as (a*b)^2
. There is no
way to make the C++ compiler use the expected interpretation.
==
, !=
<
, <=
, >
, >=
-- comparison (using the normal arithmetic ordering)
-- see also the cmp
function below.
++
, --
(prefix, e.g. ++a
) use these if you can
++
, --
(postfix, e.g. a++
) avoid these if you can, as they create temporaries
(three way comparison)
cmp(a, b)
-- returns an int
which is
< 0
, == 0
, or > 0
if
a < b
, a == b
, or a > b
respectively
CmpAbs(a,b)
-- same as cmp(abs(a),abs(b))
but might be faster.
(Several basic number theoretical operations are defined in NumTheory
)
Let n
be an integer,
abs(n)
-- the absolute value of n
sign(n)
-- (returns int
) returns
-1 if n<0
, 0 if n==0
, and +1 if n>0
LeastNNegRemainder(x,m)
-- least non-negative remainder; throws ERR::DivByZero
if m==0
SymmRemainder(x,m)
-- symmetric remainder; throws ERR::DivByZero
if m==0
log(n)
-- natural logarithm of the absolute value of n
(as a double
)
RoundDiv(n,d)
-- rounded division of n
by d
, (currently halves round away from 0)
isqrt(n)
-- the (truncated) integer part of the square root of n
ILogBase(n,b)
-- (returns long
) the integer part of log(abs(n))/log(b)
;
error if n=0
or b<2
These functions return BigInt
power(a, b)
-- returns a
to the power b
(error if b<0
); power(0,0)
gives 1
SmallPower(a, b)
-- (returns long
) returns a
to the power b
(error if b<0
; no check for overflow)
factorial(n)
-- factorial for non-negative n
LogFactorial(n)
-- approx natural log of factorial(n)
(abs.err. < 5*10^(-8))
RangeFactorial(lo,hi)
-- lo*(lo+1)*(lo+2)*...*hi
binomial(n, r)
-- binomial coefficient
fibonacci(n)
-- n
-th Fibonacci number
iroot(N,r)
-- the (truncated) integer part of the r
-th root of N
(error if r<2
or even root of negative); see also IsExactIroot
RandomBigInt(lo, hi)
-- a uniform random integer N
s.t. lo <= N <= hi
(see random
for details).
Only for BigInt
mantissa(N)
-- N
represented as a floating-point number.
If N
is zero, produces 0.0.
If N>0
, produces a value between 0.5 and 0.999...;
otherwise (when N<0
) a value between -0.5 and -0.999...
The bits of the floating point result are the topmost
bits of the binary representation of N
.
exponent(N)
-- result is a long
whose value is the least integer e such that
2^e > abs(n). If N
is zero, result is zero.
Only for BigInt
NumDigits(N, b)
-- (returns long
) the number of digits N
has
when written in base b
(the result may sometimes to be too large by 1)
These procedures are ugly but may give a slight gain in speed. Use them only if you really must; it is probably better to use GMP directly if speed is so very important.
We expect these procedures (except quorem
) to become obsolete
when CoCoALib upgrades to the C++11 standard.
Assignment is always to leftmost argument(s) a
, a BigInt
.
Second and/or third argument of type BigInt
.
add(a, b, c)
-- a = b+c
sub(a, b, c)
-- a = b-c
mul(a, b, c)
-- a = b*c
div(a, b, c)
-- a = b/c (truncated integer quotient)
mod(a, b, c)
-- a = b%c (remainder s.t. b = quot*c + rem)
quorem(a, b, c, d)
-- same as a = c/d, b = c%d
divexact(a, b, c)
-- a = b/c (fast, but division must be exact)
power(a, b, c)
-- a = b^c, where 0^0 gives 1
neg(a, b)
-- a = -b
abs(a, b)
-- a = abs(b)
Error conditions are signalled by exceptions. Examples of error conditions
are impossible arithmetic operations such as division by zero, overly large
arguments (e.g. second argument to binomial must fit into a machine
long
), and exhaustion of resources.
Currently the exception structure is very simplistic:
CoCoA::ErrorInfo
exception; for instance
ERR::ArgTooBig |
value supplied is too large for the answer to be computed |
ERR::BadArg |
unsuitable arg(s) supplied (or input number too large) |
ERR::BadNumBase |
the base must be between 2 and 36 |
ERR::BadPwrZero |
attempt to raise 0 to negative power |
ERR::DivByZero |
division by zero |
ERR::ExpTooBig |
exponent is too large |
ERR::IntDivByNeg |
inexact integer division by a negative divisor |
ERR::NegExp |
negative exponent |
ERR::ZeroModulus |
the modulus specified is zero |
The implementation of cmp
is more convoluted than I'd like; it must
avoid internal overflow.
The implementation of RoundDiv
was more difficult than I had expected.
Part of the problem was making sure that needless overflow would never
occur: this was especially relevant in the auxiliary functions
uround_half_up
and uround_half_down
. It would be nice if a
neater implementation could be achieved -- it seems strange that the
C/C++ standard libraries do not already offer such a function. The
standard C functions lround
almost achieves what is needed here, but
there are two significant shortcomings: rounding is always away from zero
(rather than towards +infinity), and there could be loss of accuracy if
the quotient exceeds 1/epsilon. There is also a standard function ldiv
which computes quotient and remainder, but it seems to be faster to compute
the two values explicitly.
NOTE: if you change rounding of halves, you must change TWO fns (RoundDiv
for machine ints and RoundDiv
for big ints).
The power functions could allow high powers of -1,0,1 (without complaining about the exponent being too big). But is it worth it?
Only partial access to all the various division functions offered by the C interface to GMP. Many other GMP functions are not directly accessible.
IsExactIroot
has rather a lot of signatures.
2014
BigInt
and MachineInt
together into IntOperations
-