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
(denominator is taken to be 1)
QQ
ZZ
s) specifying numerator
and denominator in that order; you may supply a third argument of
QQ::AlreadyReduced
if you are absolutely certain that there is no
common factor between the given numerator and denominator
N
or N/D
where N
is the decimal
representation of the numerator and D
that of the denominator
+ 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.
Note that the ctor call QQ(0)
actually calls the ctor from a C string!!
This a C++ "feature".
I have replaced the bodies of the QQ
ctors which take two integers
as arguments by a call to the common body QQ::myAssign
. This does
mean that some wasteful temporaries are created when either of the
arguments is a machine integer. Time will tell whether this waste is
intolerable.
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.
Should the QQ
ctor from a string (or C string) also accept an
optional ReduceFlag
?