The class QQ
is intended to represent (exact) rational numbers of
practically unlimited range; it is currently based on the implementation in
the GMP "big integer" library. This code forms the interface between
CoCoALib and the big integer/rational library upon which it relies. It
seems most unlikely that GMP will be displaced from its position as the
foremost library of this type; as a consequence the class QQ
may
eventually be replaced by GMP's own C++ interface.
The usual arithmetic operations are available with standard C++ syntax but
generally these incur run-time overhead since results are returned through
temporaries which are created and destroyed silently by the compiler. Thus
if the variables a
, b
and c
are each of type QQ
then a = b+c;
is a
valid C++ statement for placing the sum of b
and c
in a
,
but the sum is first computed into a hidden temporary which is then
copied to a
, and then finally the temporary is destroyed. As a general
principle, the type QQ
is provided for convenience of representing rational
vallues rather than for rapid computation.
There is an important exception to the natural syntax: ^
does not
denote exponentiation; you must use the function power
instead.
We have chosen not to define operator^
to perform exponentiation
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.
Arithmetic may also be performed between a QQ
and a machine integer or
a ZZ
. The result is always of type QQ
(even if the value turns out
to be an integer). Do remember, though, that operations between two
machine integers are handled directly by C++, and problems of overflow can
occur.
It is important not to confuse values of type QQ
with values of type
RingElem
which happen to belong to the ring RingQ
. The distinction
is analogous to that between values of type ZZ
and value of type
RingElem
which happen to belong to the ring RingZ
. In summary, the
operations available for RingElem
are those applicable to elements of
any ordered commutative ring, whereas the range of operations on QQ
values is wider (since we have explicit knowledge of the type).
Constructors:
A value of type QQ
may be created from:
ZZ
QQ
ZZ
s) specifying numerator
and denominator in that order; you may supply a third argument of
QQ::AlreadyNormalized
if you are absolutely certain that the given denominator
is positive and that there is no common factor between numerator and denominator
No constructor for creating a QQ
from a std::string
(or a
char*
) is provided. This is for two reasons: (A) a technical
ambiguity in QQ(0)
since 0
is valid as a char*
; (B) conversion
from a decimal string representation is sufficiently costly that it
should be highly visible. Conversion from a string to a value of type
QQ
can be effected using the convert
function (see convert
) or
using operator>>
and std::istringstream
from the C++ library.
+ the sum - the difference * the product / floor quotient (divisor must be positive) = assignment
+=, -=, *=, /= definitions as expected; LHS must be of type QQ
==, !=, <, <=, >, >= comparison (using the normal arithmetic ordering)See also the
cmp
function below.
++, -- (prefix) use these if you can ++, -- (postfix) avoid these if you can, as they create temporaries
IsZero(q) true iff q is zero IsOne(q) true iff q == 1 IsMinusOne(q) true iff q == -1 IsOneDen(q) true iff den(q) == 1 sign(q) gives -1 (machine integer) to mean q is negative, 0 (machine integer) to mean q is zero, +1 (machine integer) to mean q is positive.
power(a, b) returns a to the power b;
cmp(a, b) returns an ``int`` which is < 0 if a < b, == 0 if a == b, > 0 if a > b.
abs(q) gives the absolute value of q floor(q) returns a ZZ for the greatest integer <= q ceil(q) returns a ZZ for the leaast integer >= q round(q) returns a ZZ which is the nearest to q (in case of ambiguity it rounds towards +infinity) num(q) returns a ZZ which is the numerator of q den(q) returns a positive ZZ which is the denominator of q log(q) returns a double whose value is (approximately) the natural logarithm of q
mpqref(n)
this gives a (const) reference to the mpq_t
value inside
a QQ
object. You should use this accessor very sparingly!
Nothing very clever. Conversion from a string was a bit tedious.
This code is probably not "exception safe"; I do not know what the mpq_*
functions do when there is insufficient memory to proceed. Making the
code "exception safe" could well be non-trivial: I suspect a sort of
auto_ptr
to an mpq_t
value might be needed.
Should the QQ ctor from string also accept numbers with decimal points? e.g. QQ("3.14159")? We'll wait and see whether there is demand for this before implementing; note that GMP does NOT offer this capability.