The call RingZ()
produces the CoCoA ring which represents Z, the
ring of integers. Calling RingZ()
several times will always produce
the same unique CoCoA ring representing Z.
Please see the documentation in ring
for a full description of
operations elements of a ring. Strictly, there is a limit on the size
of elements you can create, but the limit is typically high enough not
to be bothersome.
Efficiency of arithmetic on elements of RingZ()
should be reasonable
rather than spectacular. If you wish to compute purely with integers
(without exploiting CoCoALib's rings) then see the documentation in
ZZ
.
Here is a summary of the functions offered:
RingZ() |
returns the CoCoALib ring representing Z |
IsZ(R) |
says whether the ring R is actually RingZ() |
NewZEmbeddingHom(S) |
creates the homomorphism Z --> S |
(but see also CanonicalHom ) |
The function RingZ()
simply returns the unique instance of the CoCoALib
ring representing Z. This instance is managed by GlobalManager
, see its
documentation.
The function MakeUniqueInstanceOfRingZ
is the only function which can
call the ctor of RingZImpl
. The only function which is supposed to
call MakeUniqueInstanceOfRingZ
is the ctor of GlobalManager
. I have
discouraged others from calling MakeUniqueInstanceOfRingZ
by not putting
it in the header file RingZ.H
-- see bugs section in GlobalManager
.
The class RingZImpl
is really very simple. It may look daunting and
complex because it inherits lots of virtual functions from RingBase
.
It contains just three data members: a MemPool
for managing the storage
of the mpz_t
headers, and pointers to the ring's own zero and one elements.
The member functions for arithmetic are all quite simple. The only
minor difficulty is in the function AsMPZ
which gets at the mpz_t
hidden inside a RingElemRawPtr
. I have decided to stick with the C
interface to GMP for the moment (even though GMP 4 does offer a C++
interface). This appears to be more a personal choice than a technical
one.
Recall (from ring
) that arithmetic on ring elements always passes
via the virtual member functions of the concrete rings, and that these
expect arguments to be of type RawPtr
or ConstRawPtr
. The arguments
are pointers to the mpz_t
headers which reside in a region of memory
controlled by the MemPool
belonging to the RingZImpl
class.
Given that the mpz_t
values must live on the free store, we use a MemPool
to handle the space for their headers (which are of fixed size). Note that
this MemPool
is NOT what handles the memory used for the digits (or limbs)
of the GMP integer values! Currently limb space is handled by whatever is
the default allocator (malloc
, I suppose).
The data members myZeroPtr
and myOnePtr
just hold auto_ptr
s to the zero
and one elements of the RingZImpl
. I used an auto_ptr
to avoid having
to worry about freeing it in the destructor; the zero and one values cannot be
RingElem
s because their creation must be deferred. I opted not to store the
values in RingElem
fields to avoid any possible problem due to a "race
condition" where elements of the ring would be constructed before the
body of the constructor of the ring had begun execution (might be OK
anyway, but could easily lead to hair-raising bugs (e.g. in the dtor)).
This code is probably not "exception safe"; I do not know what the mpz_*
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 mpz_t value might be needed.
Should I switch to the C++ interface for GMP integers?
It is a shame that the mpz_t headers are "out of line". How much this may affect run-time performance I don't know.
Generation of random elements in RingZ is not possible (yet???).