QQ

© 2009 John Abbott
GNU Free Documentation License, Version 1.2



index page

User documentation for QQ

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).

The Functions Available For Use

Constructors: A value of type QQ may be created from:

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.

Infix operators for QQs

(A) normal arithmetic (potentially inefficient because of temporaries)
    +    the sum
    -    the difference
    *    the product
    /    floor quotient (divisor must be positive)
    =    assignment

(B) arithmetic and assignment
   +=, -=, *=, /=  definitions as expected; LHS must be of type QQ

(C) arithmetic ordering
    ==, !=, <, <=, >, >=  comparison (using the normal arithmetic ordering)
See also the cmp function below.

(D) increment/decrement
    ++, -- (prefix)   use these if you can
    ++, -- (postfix)  avoid these if you can, as they create temporaries

Functions applicable to QQs

(A) query functions (all take 1 argument)
     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.

(B) Exponentiation (the exponent of the power must be non-negative)
     power(a, b)          returns a to the power b;

(C) the cmp function
     cmp(a, b)      returns an ``int`` which is
                      < 0    if a < b,
                      == 0   if a == b,
                      > 0    if a > b.

(D) Other functions
     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

(E) Functions violating encapsulation

Maintainer documentation for the class QQ

Nothing very clever. Conversion from a string was a bit tedious.

Bugs, Shortcomings and other ideas

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.