Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/src/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 47 kB image not shown  

Quelle  finfield.c   Sprache: C

 
/****************************************************************************
**
**  This file is part of GAP, a system for computational discrete algebra.
**
**  Copyright of GAP belongs to its developers, whose names are too numerous
**  to list here. Please refer to the COPYRIGHT file for details.
**
**  SPDX-License-Identifier: GPL-2.0-or-later
**
**  This file contains the  functions  to compute  with elements  from  small
**  finite fields.
**
**  The concepts of this kernel module are documented in finfield.h
*/


#include "finfield.h"

#include "ariths.h"
#include "bool.h"
#include "calls.h"
#include "error.h"
#include "finfield_conway.h"
#include "gvars.h"
#include "io.h"
#include "lists.h"
#include "modules.h"
#include "opers.h"
#include "plist.h"

#ifdef HPCGAP
#include "hpc/aobjects.h"
#include "hpc/thread.h"
#endif

/****************************************************************************
**
*V  SuccFF  . . . . .  Tables for finite fields which are computed on demand
*V  TypeFF
*V  TypeFF0
**
**  SuccFF holds a plain list of successor lists.
**  TypeFF holds the types of typical elements of the finite fields.
**  TypeFF0 holds the types of the zero elements of the finite fields.
*/


Obj SuccFF;
static Obj TypeFF;
static Obj TypeFF0;


/****************************************************************************
**
*V  TYPE_FFE  . . . . . kernel copy of GAP function TYPE_FFE
*V  TYPE_FFE0 . . . . . kernel copy of GAP function TYPE_FFE0
**
**  These GAP functions are called to compute types of finite field elemnents
*/

static Obj TYPE_FFE;
static Obj TYPE_FFE0;

/****************************************************************************
**
*V  PrimitiveRootMod
**
**  Local copy of GAP function PrimitiveRootMod, used when initializing new
**  fields.
*/

static Obj PrimitiveRootMod;


/****************************************************************************
**
*F  LookupPrimePower(<q>) . . . . . . . .  search for a prime power in tables
**
**  Searches the tables of prime powers from ffdata.c for q, returns the
**  index of q in SizeFF if it is present and 0 if not (the 0 position of
**  SizeFF is unused).
*/

static FF LookupPrimePower(UInt q)
{
    UInt l, n;
    FF   ff;
    UInt e;

    // search through the finite field table
    l = 1;
    n = NUM_SHORT_FINITE_FIELDS;
    ff = 0;
    while (l <= n && SizeFF[l] <= q && q <= SizeFF[n]) {
        // interpolation search
        /* cuts iterations roughly in half compared to binary search at
         * the expense of additional divisions. */

        e = (q - SizeFF[l] + 1) * (n - l) / (SizeFF[n] - SizeFF[l] + 1);
        ff = l + e;
        if (SizeFF[ff] == q)
            break;
        if (SizeFF[ff] < q)
            l = ff + 1;
        else
            n = ff - 1;
    }
    if (ff < 1 || ff > NUM_SHORT_FINITE_FIELDS)
        return 0;
    if (SizeFF[ff] != q)
        return 0;
    return ff;
}


/****************************************************************************
**
*F  FiniteField(<p>,<d>) .  make the small finite field with <p>^<d> elements
*F  FiniteFieldBySize(<q>) . .  make the small finite field with <q> elements
**
**  The work is done in the Lookup function above, and in FiniteFieldBySize
**  where the successor tables are computed.
*/


FF FiniteFieldBySize(UInt q)
{
    FF    ff;            // finite field, result
    Obj   tmp;           // temporary bag
    Obj   succBag;       // successor table bag
    FFV * succ;          // successor table
    FFV * indx;          // index table
    UInt  p;             // characteristic of the field
    UInt  poly;          // Conway polynomial of extension
    UInt  i, l, f, n, e; // loop variables
    Obj   root;          // will be a primitive root mod p

    ff = LookupPrimePower(q);
    if (!ff)
        return 0;

#ifdef HPCGAP
    /* Important correctness concern here:
     *
     * The values of SuccFF, TypeFF, and TypeFF0 are set in that
     * order, separated by write barriers. This can happen concurrently
     * in a different thread.
     *
     * Thus, after observing that TypeFF0 has been set, we can be sure
     * that the thread also sees the values of SuccFF and TypeFF.
     * This is ensured by the read barrier in ATOMIC_ELM_PLIST().
     *
     * In the worst case, we may do the following calculations once per
     * thread and throw them away for all but one thread. Correctness
     * is still ensured through the use of ATOMIC_SET_ELM_PLIST_ONCE(),
     * which results in all threads sharing the same types and successor
     * tables.
     */

    if (ATOMIC_ELM_PLIST(TypeFF0, ff))
        return ff;
#else
    if (ELM_PLIST(TypeFF0, ff))
        return ff;
#endif

    // determine the characteristic of the field
    p = CHAR_FF(ff);

    // allocate a bag for the successor table and one for a temporary
    tmp = NewKernelBuffer(sizeof(Obj) + q * sizeof(FFV));
    succBag = NewKernelBuffer(sizeof(Obj) + q * sizeof(FFV));

    indx = (FFV *)(1 + ADDR_OBJ(tmp));
    succ = (FFV *)(1 + ADDR_OBJ(succBag));

    // if q is a prime find the smallest primitive root $e$, use $x - e$

    if (DEGR_FF(ff) == 1) {
        if (p < 65537) {
            /* for smaller primes we do this in the kernel for performance and
            bootstrapping reasons
            TODO -- review the threshold */

            for (e = 1, i = 1; i != p - 1; ++e) {
                for (f = e, i = 1; f != 1; ++i)
                    f = (f * e) % p;
            }
        }
        else {
            // Otherwise we ask the library
            root = CALL_1ARGS(PrimitiveRootMod, INTOBJ_INT(p));
            e = INT_INTOBJ(root) + 1;
        }
        poly = p - (e - 1);
    }

    // otherwise look up the polynomial used to construct this field
    else {
        for (i = 0; PolsFF[i] != q; i += 2)
            ;
        poly = PolsFF[i + 1];
    }

    // construct 'indx' such that 'e = x^(indx[e]-1) % poly' for every e
    indx[0] = 0;
    for (e = 1, n = 0; n < q - 1; ++n) {
        indx[e] = n + 1;
        // e =p*e mod poly =x*e mod poly =x*x^n mod poly =x^{n+1} mod poly
        if (p != 2) {
            f = p * (e % (q / p));
            l = ((p - 1) * (e / (q / p))) % p;
            e = 0;
            for (i = 1; i < q; i *= p)
                e = e + i * ((f / i + l * (poly / i)) % p);
        }
        else {
            if (2 * e & q)
                e = 2 * e ^ poly ^ q;
            else
                e = 2 * e;
        }
    }

    // construct 'succ' such that 'x^(n-1)+1 = x^(succ[n]-1)' for every n
    succ[0] = q - 1;
    for (e = 1, f = p - 1; e < q; e++) {
        if (e < f) {
            succ[indx[e]] = indx[e + 1];
        }
        else {
            succ[indx[e]] = indx[e + 1 - p];
            f += p;
        }
    }

    // enter the finite field in the tables
#ifdef HPCGAP
    MakeBagReadOnly(succBag);
    ATOMIC_SET_ELM_PLIST_ONCE(SuccFF, ff, succBag);
    CHANGED_BAG(SuccFF);
    tmp = CALL_1ARGS(TYPE_FFE, INTOBJ_INT(p));
    ATOMIC_SET_ELM_PLIST_ONCE(TypeFF, ff, tmp);
    CHANGED_BAG(TypeFF);
    tmp = CALL_1ARGS(TYPE_FFE0, INTOBJ_INT(p));
    ATOMIC_SET_ELM_PLIST_ONCE(TypeFF0, ff, tmp);
    CHANGED_BAG(TypeFF0);
#else
    ASS_LIST(SuccFF, ff, succBag);
    CHANGED_BAG(SuccFF);
    tmp = CALL_1ARGS(TYPE_FFE, INTOBJ_INT(p));
    ASS_LIST(TypeFF, ff, tmp);
    CHANGED_BAG(TypeFF);
    tmp = CALL_1ARGS(TYPE_FFE0, INTOBJ_INT(p));
    ASS_LIST(TypeFF0, ff, tmp);
    CHANGED_BAG(TypeFF0);
#endif

    // return the finite field
    return ff;
}

FF FiniteField(UInt p, UInt d)
{
    UInt q, i;
    FF   ff;

    q = 1;
    for (i = 1; i <= d; i++)
        q *= p;

    ff = FiniteFieldBySize(q);
    if (ff != 0 && CHAR_FF(ff) != p)
        return 0;
    return ff;
}


/****************************************************************************
**
*F  CommonFF(<f1>,<d1>,<f2>,<d2>) . . . . . . . . . . . . find a common field
**
**  'CommonFF' returns  a small finite field  that can represent  elements of
**  degree <d1> from the small finite field <f1> and  elements of degree <d2>
**  from the small finite field <f2>.  Note that this is not guaranteed to be
**  the smallest such field.  If  <f1> and <f2> have different characteristic
**  or the smallest common field, is too large, 'CommonFF' returns 0.
*/

FF              CommonFF (
    FF                  f1,
    UInt                d1,
    FF                  f2,
    UInt                d2 )
{
    UInt                p;              // characteristic
    UInt                d;              // degree

    // trivial case first
    if ( f1 == f2 ) {
        return f1;
    }

    // get and check the characteristics
    p = CHAR_FF( f1 );
    if ( p != CHAR_FF( f2 ) ) {
        return 0;
    }

    // check whether one of the fields will do
    if ( DEGR_FF(f1) % d2 == 0 ) {
        return f1;
    }
    if ( DEGR_FF(f2) % d1 == 0 ) {
        return f2;
    }

    // compute the necessary degree
    d = d1;
    while ( d % d2 != 0 ) {
        d += d1;
    }

    // try to build the field
    return FiniteField( p, d );
}


/****************************************************************************
**
*F  CharFFE(<ffe>)  . . . . . . . . .  characteristic of a small finite field
**
**  'CharFFE' returns the characteristic of the small finite field  in  which
**  the element <ffe> lies.
*/

UInt CharFFE (
    Obj                 ffe )
{
    return CHAR_FF( FLD_FFE(ffe) );
}

static Obj FuncCHAR_FFE_DEFAULT(Obj self, Obj ffe)
{
    return INTOBJ_INT( CHAR_FF( FLD_FFE(ffe) ) );
}


/****************************************************************************
**
*F  DegreeFFE(<ffe>)  . . . . . . . . . . . .  degree of a small finite field
**
**  'DegreeFFE' returns the degree of the smallest finite field in which  the
**  element <ffe> lies.
*/

UInt DegreeFFE (
    Obj                 ffe )
{
    UInt                d;              // degree, result
    FFV                 val;            // value of element
    FF                  fld;            // field of element
    UInt                q;              // size  of field
    UInt                p;              // char. of field
    UInt                m;              // size  of minimal field

    // get the value, the field, the size, and the characteristic
    val = VAL_FFE( ffe );
    fld = FLD_FFE( ffe );
    q = SIZE_FF( fld );
    p = CHAR_FF( fld );

    // the zero element has a degree of one
    if ( val == 0 ) {
        return 1;
    }

    // compute the degree
    m = p;
    d = 1;
    while ( (q-1) % (m-1) != 0 || (val-1) % ((q-1)/(m-1)) != 0 ) {
        m *= p;
        d += 1;
    }

    // return the degree
    return d;
}

static Obj FuncDEGREE_FFE_DEFAULT(Obj self, Obj ffe)
{
    return INTOBJ_INT( DegreeFFE( ffe ) );
}


/****************************************************************************
**
*F  TypeFFE(<ffe>)  . . . . . . . . . . type of element of small finite field
**
**  'TypeFFE' returns the type of the element <ffe> of a small finite field.
**
**  'TypeFFE' is the function in 'TypeObjFuncs' for  elements in small finite
**  fields.
*/

Obj TypeFFE(Obj ffe)
{
    Obj types = (VAL_FFE(ffe) == 0) ? TypeFF0 : TypeFF;
#ifdef HPCGAP
    return ATOMIC_ELM_PLIST(types, FLD_FFE(ffe));
#else
    return ELM_PLIST(types, FLD_FFE(ffe));
#endif
}


/****************************************************************************
**
*F  EqFFE(<opL>,<opR>)  . . . . . . . test if finite field elements are equal
**
**  'EqFFE' returns  'True' if the two  finite field elements <opL> and <opR>
**  are equal and 'False' othwise.
**
**  This is complicated because it must account  for the following situation.
**  Suppose 'a' is 'Z(3)', 'b' is 'Z(3^2)^4' and  finally 'c' is 'Z(3^3)^13'.
**  Mathematically 'a' is equal to 'b', so we  want 'a =  b' to be 'true' and
**  since 'a' is represented over a  subfield of 'b'  this is no big problem.
**  Again  'a' is equal to  'c', and again we want  'a = c'  to be 'true' and
**  again this is no problem since 'a' is represented over a subfield of 'c'.
**  Since '=' ought  to be transitive we also  want 'b = c'  to be 'true' and
**  this is a problem, because they are represented over incompatible fields.
*/

static Int EqFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR;         // value of left and right
    FF                  fL, fR;         // field of left and right
    UInt                pL, pR;         // char. of left and right
    UInt                qL, qR;         // size  of left and right
    UInt                mL, mR;         // size  of minimal field

    // get the values and the fields over which they are represented
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );
    fL = FLD_FFE( opL );
    fR = FLD_FFE( opR );

    // if the elements are represented over the same field, it is easy
    if ( fL == fR ) {
        return (vL == vR);
    }

    // elements in fields of different characteristic are different too
    pL = CHAR_FF( fL );
    pR = CHAR_FF( fR );
    if ( pL != pR ) {
        return 0;
    }

    // the zero element is not equal to any other element
    if ( vL == 0 || vR == 0 ) {
        return (vL == 0 && vR == 0);
    }

    // compute the sizes of the minimal fields in which the elements lie
    qL = SIZE_FF( fL );
    mL = pL;
    while ( (qL-1) % (mL-1) != 0 || (vL-1) % ((qL-1)/(mL-1)) != 0 ) mL *= pL;
    qR = SIZE_FF( fR );
    mR = pR;
    while ( (qR-1) % (mR-1) != 0 || (vR-1) % ((qR-1)/(mR-1)) != 0 ) mR *= pR;

    // elements in different fields are different too
    if ( mL != mR ) {
        return 0;
    }

    // otherwise compare the elements in the common minimal field
    return ((vL-1)/((qL-1)/(mL-1)) == (vR-1)/((qR-1)/(mR-1)));
}


/****************************************************************************
**
*F  LtFFE(<opL>,<opR>)  . . . . . .  test if finite field elements is smaller
**
**  'LtFFEFFE' returns 'True' if the  finite field element <opL> is  strictly
**  less than the finite field element <opR> and 'False' otherwise.
*/

static Int LtFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR;         // value of left and right
    FF                  fL, fR;         // field of left and right
    UInt                pL, pR;         // char. of left and right
    UInt                qL, qR;         // size  of left and right
    UInt                mL, mR;         // size  of minimal field

    // get the values and the fields over which they are represented
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );
    fL = FLD_FFE( opL );
    fR = FLD_FFE( opR );

    // elements in fields of different characteristic are not comparable
    pL = CHAR_FF( fL );
    pR = CHAR_FF( fR );
    if ( pL != pR ) {
        return (DoOperation2Args( LtOper, opL, opR ) == True);
    }

    // the zero element is smaller than any other element
    if ( vL == 0 || vR == 0 ) {
        return (vL == 0 && vR != 0);
    }

    // get the sizes of the fields over which the elements are written
    qL = SIZE_FF( fL );
    qR = SIZE_FF( fR );

    // Deal quickly with the case where both elements are written over the ground field
    if (qL ==pL &&  qR == pR)
      return vL < vR;

    // compute the sizes of the minimal fields in which the elements lie
    mL = pL;
    while ( (qL-1) % (mL-1) != 0 || (vL-1) % ((qL-1)/(mL-1)) != 0 ) mL *= pL;
    mR = pR;
    while ( (qR-1) % (mR-1) != 0 || (vR-1) % ((qR-1)/(mR-1)) != 0 ) mR *= pR;

    // elements in smaller fields are smaller too
    if ( mL != mR ) {
        return (mL < mR);
    }

    // otherwise compare the elements in the common minimal field
    return ((vL-1)/((qL-1)/(mL-1)) < (vR-1)/((qR-1)/(mR-1)));
}


/****************************************************************************
**
*F  PrFFV(<fld>,<val>)  . . . . . . . . . . . . .  print a finite field value
**
**  'PrFFV' prints the value <val> from the finite field <fld>.
**
*/

static void PrFFV(FF fld, FFV val)
{
    UInt                q;              // size   of finite field
    UInt                p;              // char.  of finite field
    UInt                m;              // size   of minimal field
    UInt                d;              // degree of minimal field

    // get the characteristic, order of the minimal field and the degree
    q = SIZE_FF( fld );
    p = CHAR_FF( fld );

    // print the zero
    if ( val == 0 ) {
        Pr("%>0*Z(%>%d%2<)", (Int)p, 0);
    }

    // print a nonzero element as power of the primitive root
    else {

        // find the degree of the minimal field in that the element lies
        d = 1;  m = p;
        while ( (q-1) % (m-1) != 0 || (val-1) % ((q-1)/(m-1)) != 0 ) {
            d++;  m *= p;
        }
        val = (val-1) / ((q-1)/(m-1)) + 1;

        // print the element
        Pr("%>Z(%>%d%<", (Int)p, 0);
        if ( d == 1 ) {
            Pr("%<)", 0, 0);
        }
        else {
            Pr("^%>%d%2<)", (Int)d, 0);
        }
        if ( val != 2 ) {
            Pr("^%>%d%<", (Int)(val-1), 0);
        }
    }

}


/****************************************************************************
**
*F  PrFFE(<ffe>)  . . . . . . . . . . . . . . .  print a finite field element
**
**  'PrFFE' prints the finite field element <ffe>.
*/

static void PrFFE(Obj ffe)
{
    PrFFV( FLD_FFE(ffe), VAL_FFE(ffe) );
}


/****************************************************************************
**
*F  SumFFEFFE(<opL>,<opR>)  . . . . . . . . . .  sum of finite field elements
**
**  'SumFFEFFE' returns  the sum of the  two finite  field elements <opL> and
**  <opR>.  The sum is represented over the field over which the operands are
**  represented, even if it lies in a much smaller field.
**
**  If one of the  elements is represented over  a subfield of the field over
**  which the  other element  is  represented, it is  lifted  into the larger
**  field before the addition.
**
**  'SumFFEFFE' just does the conversions mentioned  above and then calls the
**  macro 'SUM_FFV' to do the actual addition.
*/

static Obj SUM_FFE_LARGE;

static Obj SumFFEFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fL, fR, fX;     // field of left, right, result
    UInt                qL, qR, qX;     // size  of left, right, result

    // get the values, handle trivial cases
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );

    // bring the two operands into a common field <fX>
    fL = FLD_FFE( opL );
    qL = SIZE_FF( fL );
    fR = FLD_FFE( opR );
    qR = SIZE_FF( fR  );

    if ( qL == qR ) {
        fX = fL;
    }
    else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {
        fX = fL;
        if ( vR != 0 )  vR = (qL-1) / (qR-1) * (vR-1) + 1;
    }
    else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {
        fX = fR;
        if ( vL != 0 )  vL = (qR-1) / (qL-1) * (vL-1) + 1;
    }
    else {
        fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );
        if ( fX == 0 )  return CALL_2ARGS( SUM_FFE_LARGE, opL, opR );
        qX = SIZE_FF( fX );
        // if ( vL != 0 )  vL = (qX-1) / (qL-1) * (vL-1) + 1;
        if ( vL != 0 )  vL = ((qX-1) * (vL-1)) / (qL-1) + 1;
        // if ( vR != 0 )  vR = (qX-1) / (qR-1) * (vR-1) + 1;
        if ( vR != 0 )  vR = ((qX-1) * (vR-1)) / (qR-1) + 1;
    }

    vX = SUM_FFV( vL, vR, SUCC_FF(fX) );
    return NEW_FFE( fX, vX );
}

static Obj SumFFEInt(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opL );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the right operand
    vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vR = 0;
    }
    else {
        vR = 1;
        for ( ; 1 < vX; vX-- )  vR = sX[vR];
    }

    // get the left operand
    vL = VAL_FFE( opL );

    vX = SUM_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}

static Obj SumIntFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opR );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the left operand
    vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vL = 0;
    }
    else {
        vL = 1;
        for ( ; 1 < vX; vX-- )  vL = sX[vL];
    }

    // get the right operand
    vR = VAL_FFE( opR );

    vX = SUM_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  ZeroFFE(<op>) . . . . . . . . . . . . . .  zero of a finite field element
*/

static Obj ZeroFFE(Obj op)
{
    FF                  fX;             // field of result

    // get the field for the result
    fX = FLD_FFE( op );

    return NEW_FFE( fX, 0 );
}


/****************************************************************************
**
*F  AInvFFE(<op>) . . . . . . . . . . additive inverse of finite field element
*/

static Obj AInvFFE(Obj op)
{
    FFV                 v, vX;          // value of operand, result
    FF                  fX;             // field of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( op );
    sX = SUCC_FF( fX );

    // get the operand
    v = VAL_FFE( op );

    vX = NEG_FFV( v, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  DiffFFEFFE(<opL>,<opR>) . . . . . . . difference of finite field elements
**
**  'DiffFFEFFE' returns  the difference  of  the two  finite  field elements
**  <opL> and <opR>.  The difference is represented over the field over which
**  the operands are represented, even if it lies in a much smaller field.
**
**  If one of the elements is  represented over a subfield  of the field over
**  which the  other element is  represented,  it is  lifted into  the larger
**  field before the subtraction.
**
**  'DiffFFEFFE' just does the conversions mentioned above and then calls the
**  macros 'NEG_FFV' and 'SUM_FFV' to do the actual subtraction.
*/

static Obj DIFF_FFE_LARGE;

static Obj DiffFFEFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fL, fR, fX;     // field of left, right, result
    UInt                qL, qR, qX;     // size  of left, right, result

    // get the values, handle trivial cases
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );

    // bring the two operands into a common field <fX>
    fL = FLD_FFE( opL );
    qL = SIZE_FF( fL );
    fR = FLD_FFE( opR );
    qR = SIZE_FF( fR  );

    if ( qL == qR ) {
        fX = fL;
    }
    else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {
        fX = fL;
        if ( vR != 0 )  vR = (qL-1) / (qR-1) * (vR-1) + 1;
    }
    else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {
        fX = fR;
        if ( vL != 0 )  vL = (qR-1) / (qL-1) * (vL-1) + 1;
    }
    else {
        fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );
        if ( fX == 0 )  return CALL_2ARGS( DIFF_FFE_LARGE, opL, opR );
        qX = SIZE_FF( fX );
        // if ( vL != 0 )  vL = (qX-1) / (qL-1) * (vL-1) + 1;
        if ( vL != 0 )  vL = ((qX-1) * (vL-1)) / (qL-1) + 1;
        // if ( vR != 0 )  vR = (qX-1) / (qR-1) * (vR-1) + 1;
        if ( vR != 0 )  vR = ((qX-1) * (vR-1)) / (qR-1) + 1;
    }

    vR = NEG_FFV( vR, SUCC_FF(fX) );
    vX = SUM_FFV( vL, vR, SUCC_FF(fX) );
    return NEW_FFE( fX, vX );
}

static Obj DiffFFEInt(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opL );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the right operand
    vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vR = 0;
    }
    else {
        vR = 1;
        for ( ; 1 < vX; vX-- )  vR = sX[vR];
    }

    // get the left operand
    vL = VAL_FFE( opL );

    vR = NEG_FFV( vR, sX );
    vX = SUM_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}

static Obj DiffIntFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opR );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the left operand
    vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vL = 0;
    }
    else {
        vL = 1;
        for ( ; 1 < vX; vX-- )  vL = sX[vL];
    }

    // get the right operand
    vR = VAL_FFE( opR );

    vR = NEG_FFV( vR, sX );
    vX = SUM_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  ProdFFEFFE(<opL>,<opR>) . . . . . . . .  product of finite field elements
**
**  'ProdFFEFFE'  returns the product of  the two finite field elements <opL>
**  and <opR>.   The  product is  represented  over the field  over which the
**  operands are represented, even if it lies in a much smaller field.
**
**  If one of the elements  is represented over a  subfield of the field over
**  which the other element  is  represented, it  is  lifted into the  larger
**  field before the multiplication.
**
**  'ProdFFEFFE' just does the conversions mentioned above and then calls the
**  macro 'PROD_FFV' to do the actual multiplication.
*/

static Obj PROD_FFE_LARGE;

static Obj ProdFFEFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fL, fR, fX;     // field of left, right, result
    UInt                qL, qR, qX;     // size  of left, right, result

    // get the values, handle trivial cases
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );

    // bring the two operands into a common field <fX>
    fL = FLD_FFE( opL );
    qL = SIZE_FF( fL );
    fR = FLD_FFE( opR );
    qR = SIZE_FF( fR  );

    if ( qL == qR ) {
        fX = fL;
    }
    else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {
        fX = fL;
        if ( vR != 0 )  vR = (qL-1) / (qR-1) * (vR-1) + 1;
    }
    else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {
        fX = fR;
        if ( vL != 0 )  vL = (qR-1) / (qL-1) * (vL-1) + 1;
    }
    else {
        fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );
        if ( fX == 0 )  return CALL_2ARGS( PROD_FFE_LARGE, opL, opR );
        qX = SIZE_FF( fX );
        // if ( vL != 0 )  vL = (qX-1) / (qL-1) * (vL-1) + 1;
        if ( vL != 0 )  vL = ((qX-1) * (vL-1)) / (qL-1) + 1;
        // if ( vR != 0 )  vR = (qX-1) / (qR-1) * (vR-1) + 1;
        if ( vR != 0 )  vR = ((qX-1) * (vR-1)) / (qR-1) + 1;
    }

    vX = PROD_FFV( vL, vR, SUCC_FF(fX) );
    return NEW_FFE( fX, vX );
}

static Obj ProdFFEInt(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opL );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the right operand
    vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vR = 0;
    }
    else {
        vR = 1;
        for ( ; 1 < vX; vX-- )  vR = sX[vR];
    }

    // get the left operand
    vL = VAL_FFE( opL );

    vX = PROD_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}

static Obj ProdIntFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opR );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the left operand
    vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vL = 0;
    }
    else {
        vL = 1;
        for ( ; 1 < vX; vX-- )  vL = sX[vL];
    }

    // get the right operand
    vR = VAL_FFE( opR );

    vX = PROD_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  OneFFE(<op>)  . . . . . . . . . . . . . . . one of a finite field element
*/

static Obj OneFFE(Obj op)
{
    FF                  fX;             // field of result

    // get the field for the result
    fX = FLD_FFE( op );

    return NEW_FFE( fX, 1 );
}


/****************************************************************************
**
*F  InvFFE(<op>)  . . . . . . . . . . . . . . inverse of finite field element
*/

static Obj InvFFE(Obj op)
{
    FFV                 v, vX;          // value of operand, result
    FF                  fX;             // field of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( op );
    sX = SUCC_FF( fX );

    // get the operand
    v = VAL_FFE( op );
    if ( v == 0 ) return Fail;

    vX = QUO_FFV( 1, v, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  QuoFFEFFE(<opL>,<opR>) . . . . . . . .  quotient of finite field elements
**
**  'QuoFFEFFE' returns  the quotient of  the two finite field elements <opL>
**  and <opR>.  The  quotient is represented  over  the field  over which the
**  operands are represented, even if it lies in a much smaller field.
**
**  If one of the  elements is represented over  a subfield of the field over
**  which the  other  element is represented,  it is  lifted into the  larger
**  field before the division.
**
**  'QuoFFEFFE' just does the conversions mentioned  above and then calls the
**  macro 'QUO_FFV' to do the actual division.
*/

static Obj QUO_FFE_LARGE;

static Obj QuoFFEFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fL, fR, fX;     // field of left, right, result
    UInt                qL, qR, qX;     // size  of left, right, result

    // get the values, handle trivial cases
    vL = VAL_FFE( opL );
    vR = VAL_FFE( opR );

    // bring the two operands into a common field <fX>
    fL = FLD_FFE( opL );
    qL = SIZE_FF( fL );
    fR = FLD_FFE( opR );
    qR = SIZE_FF( fR  );

    if ( qL == qR ) {
        fX = fL;
    }
    else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {
        fX = fL;
        if ( vR != 0 )  vR = (qL-1) / (qR-1) * (vR-1) + 1;
    }
    else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {
        fX = fR;
        if ( vL != 0 )  vL = (qR-1) / (qL-1) * (vL-1) + 1;
    }
    else {
        fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );
        if ( fX == 0 )  return CALL_2ARGS( QUO_FFE_LARGE, opL, opR );
        qX = SIZE_FF( fX );
        // if ( vL != 0 )  vL = (qX-1) / (qL-1) * (vL-1) + 1;
        if ( vL != 0 )  vL = ((qX-1) * (vL-1)) / (qL-1) + 1;
        // if ( vR != 0 )  vR = (qX-1) / (qR-1) * (vR-1) + 1;
        if ( vR != 0 )  vR = ((qX-1) * (vR-1)) / (qR-1) + 1;
    }

    if ( vR == 0 ) {
        ErrorMayQuit("FFE operations: must not be zero", 0, 0);
    }
    vX = QUO_FFV( vL, vR, SUCC_FF(fX) );
    return NEW_FFE( fX, vX );
}

static Obj QuoFFEInt(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opL );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the right operand
    vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vR = 0;
    }
    else {
        vR = 1;
        for ( ; 1 < vX; vX-- )  vR = sX[vR];
    }

    // get the left operand
    vL = VAL_FFE( opL );

    if ( vR == 0 ) {
        ErrorMayQuit("FFE operations: must not be zero", 0, 0);
    }
    vX = QUO_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}

static Obj QuoIntFFE(Obj opL, Obj opR)
{
    FFV                 vL, vR, vX;     // value of left, right, result
    FF                  fX;             // field of result
    Int                 pX;             // char. of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opR );
    pX = CHAR_FF( fX );
    sX = SUCC_FF( fX );

    // get the left operand
    vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;
    if ( vX == 0 ) {
        vL = 0;
    }
    else {
        vL = 1;
        for ( ; 1 < vX; vX-- )  vL = sX[vL];
    }

    // get the right operand
    vR = VAL_FFE( opR );

    if ( vR == 0 ) {
        ErrorMayQuit("FFE operations: must not be zero", 0, 0);
    }
    vX = QUO_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  PowFFEInt(<opL>,<opR>)  . . . . . . . . . power of a finite field element
**
**  'PowFFEInt' returns the  power of the finite  field element <opL> and the
**  integer <opR>.  The power is  represented over the  field over which  the
**  left operand is represented, even if it lies in a much smaller field.
**
**  'PowFFEInt' just does the conversions mentioned  above and then calls the
**  macro 'POW_FFV' to do the actual exponentiation.
*/

static Obj PowFFEInt(Obj opL, Obj opR)
{
    FFV                 vL, vX;         // value of left, result
    Int                 vR;             // value of right
    FF                  fX;             // field of result
    const FFV*          sX;             // successor table of result field

    // get the field for the result
    fX = FLD_FFE( opL );
    sX = SUCC_FF( fX );

    // get the right operand
    vR = INT_INTOBJ( opR );

    // get the left operand
    vL = VAL_FFE( opL );

    // if the exponent is negative, invert the left operand
    if ( vR < 0 ) {
        if ( vL == 0 ) {
            ErrorMayQuit("FFE operations: must not be zero", 0, 0);
        }
        vL = QUO_FFV( 1, vL, sX );
        vR = -vR;
    }

    // catch the case when vL is zero.
    if( vL == 0 ) return NEW_FFE( fX, (vR == 0 ? 1 : 0 ) );

    // reduce vR modulo the order of the multiplicative group first.
    vR %= *sX;

    vX = POW_FFV( vL, vR, sX );
    return NEW_FFE( fX, vX );
}


/****************************************************************************
**
*F  PowFFEFFE( <opL>, <opR> ) . . . . . . conjugate of a finite field element
*/

static Obj PowFFEFFE(Obj opL, Obj opR)
{
    // get the field for the result
    if ( CHAR_FF( FLD_FFE(opL) ) != CHAR_FF( FLD_FFE(opR) ) ) {
        ErrorMayQuit(" and have different characteristic", 0, 0);
    }

    return opL;
}


/****************************************************************************
**
*F  FiltIS_FFE( <self>, <obj> ) . . . . . . .  test for finite field elements
**
**  'FuncIsFFE' implements the internal function 'IsFFE( <obj> )'.
**
**  'IsFFE' returns  'true' if its argument  <obj> is a finite  field element
**  and 'false' otherwise.   'IsFFE' will cause  an  error if  called with an
**  unbound variable.
*/

static Obj IsFFEFilt;

static Obj FiltIS_FFE(Obj self, Obj obj)
{
    // return 'true' if <obj> is a finite field element
    if ( IS_FFE(obj) ) {
        return True;
    }
    else if ( TNUM_OBJ(obj) < FIRST_EXTERNAL_TNUM ) {
        return False;
    }
    else {
        return DoFilter( self, obj );
    }
}


/****************************************************************************
**
*F  FuncLOG_FFE_DEFAULT( <self>, <opZ>, <opR> ) .  logarithm of a ff constant
**
**  'FuncLOG_FFE_DEFAULT' implements the function 'LogFFE( <z>, <r> )'.
**
**  'LogFFE'  returns the logarithm of  the nonzero finite  field element <z>
**  with respect to the root <r> which must lie in the same field like <z>.
*/

static Obj LOG_FFE_LARGE;

static Obj FuncLOG_FFE_DEFAULT(Obj self, Obj opZ, Obj opR)
{
    FFV                 vZ, vR;         // value of left, right
    FF                  fZ, fR, fX;     // field of left, right, common
    UInt                qZ, qR, qX;     // size  of left, right, common
    Int                 a, b, c, d, t;  // temporaries

    if (!IS_FFE(opZ) || VAL_FFE(opZ) == 0) {
        ErrorMayQuit("LogFFE: must be a nonzero finite field element", 0,
                     0);
    }
    if (!IS_FFE(opR) || VAL_FFE(opR) == 0) {
        ErrorMayQuit("LogFFE: must be a nonzero finite field element", 0,
                     0);
    }

    // get the values, handle trivial cases
    vZ = VAL_FFE( opZ );
    vR = VAL_FFE( opR );

    // bring the two operands into a common field <fX>
    fZ = FLD_FFE( opZ );
    qZ = SIZE_FF( fZ );
    fR = FLD_FFE( opR );
    qR = SIZE_FF( fR  );

    if ( qZ == qR ) {
        qX = qZ;
    }
    else if ( qZ % qR == 0 && (qZ-1) % (qR-1) == 0 ) {
        qX = qZ;
        if ( vR != 0 )  vR = (qZ-1) / (qR-1) * (vR-1) + 1;
    }
    else if ( qR % qZ == 0 && (qR-1) % (qZ-1) == 0 ) {
        qX = qR;
        if ( vZ != 0 )  vZ = (qR-1) / (qZ-1) * (vZ-1) + 1;
    }
    else {
        fX = CommonFF( fZ, DegreeFFE(opZ), fR, DegreeFFE(opR) );
        if ( fX == 0 )  return CALL_2ARGS( LOG_FFE_LARGE, opZ, opR );
        qX = SIZE_FF( fX );
        // if ( vZ != 0 )  vZ = (qX-1) / (qZ-1) * (vZ-1) + 1;
        if ( vZ != 0 )  vZ = ((qX-1) * (vZ-1)) / (qZ-1) + 1;
        // if ( vR != 0 )  vR = (qX-1) / (qR-1) * (vR-1) + 1;
        if ( vR != 0 )  vR = ((qX-1) * (vR-1)) / (qR-1) + 1;
    }

    // now solve <l> * (<vR>-1) = (<vZ>-1) % (<qX>-1)
    a = 1;             b = 0;
    c = (Int) (vR-1);  d = (Int) (qX-1);
    while ( d != 0 ) {
        t = b;  b = a - (c/d) * b;  a = t;
        t = d;  d = c - (c/d) * d;  c = t;
    }
    if ( ((Int) (vZ-1)) % c != 0 ) {
      return Fail;
    }


    while (a < 0)
      a+= (qX -1)/c;

    // return the logarithm
    return INTOBJ_INT( (((UInt) (vZ-1) / c) * a) % ((UInt) (qX-1)) );
}


/****************************************************************************
**
*F  FuncINT_FFE_DEFAULT( <self>, <z> )  . . . .   convert a ffe to an integer
**
**  'FuncINT_FFE_DEFAULT' implements the internal function 'IntFFE( <z> )'.
**
**  'IntFFE'  returns  the integer  that  corresponds  to  the  finite  field
**  element <z>, which must of course be  an element  of a prime field, i.e.,
**  the smallest integer <i> such that '<i> * <z>^0 = <z>'.
*/

static Obj IntFF;
#ifdef HPCGAP
static Int NumFF;
#endif

static Obj INT_FF(FF ff)
{
    Obj                 conv;           // conversion table, result
    Int                 q;              // size of finite field
    Int                 p;              // char of finite field
    const FFV *         succ;           // successor table of finite field
    FFV                 z;              // one element of finite field
    UInt                i;              // loop variable

    // if the conversion table is not already known, construct it
#ifdef HPCGAP
    if ( NumFF < ff || (MEMBAR_READ(), ATOMIC_ELM_PLIST(IntFF, ff) == 0)) {
        HashLock(&IntFF);
#else
    if ( LEN_PLIST(IntFF) < ff || ELM_PLIST(IntFF,ff) == 0 ) {
#endif
        q = SIZE_FF( ff );
        p = CHAR_FF( ff );
        conv = NEW_PLIST_IMM( T_PLIST, p-1 );
        succ = SUCC_FF( ff );
        SET_LEN_PLIST( conv, p-1 );
        z = 1;
        for ( i = 1; i < p; i++ ) {
            SET_ELM_PLIST( conv, (z-1)/((q-1)/(p-1))+1, INTOBJ_INT(i) );
            z = succ[ z ];
        }
#ifdef HPCGAP
        GROW_PLIST(IntFF, ff);
        ATOMIC_SET_ELM_PLIST( IntFF, ff, conv );
        MEMBAR_WRITE();
        NumFF = LEN_PLIST(IntFF);
        HashUnlock(&IntFF);
#else
        AssPlist( IntFF, ff, conv );
#endif
    }

    // return the conversion table
#ifdef HPCGAP
    return ATOMIC_ELM_PLIST( IntFF, ff);
#else
    return ELM_PLIST( IntFF, ff );
#endif
}


static Obj FuncINT_FFE_DEFAULT(Obj self, Obj z)
{
    FFV                 v;              // value of finite field element
    FF                  ff;             // finite field
    Int                 q;              // size of finite field
    Int                 p;              // char of finite field
    Obj                 conv;           // conversion table

    // get the value
    v  = VAL_FFE( z );

    // special case for 0
    if ( v == 0 ) {
        return INTOBJ_INT( 0 );
    }

    // get the field, size, characteristic, and conversion table
    ff   = FLD_FFE( z );
    q    = SIZE_FF( ff );
    p    = CHAR_FF( ff );
    conv = INT_FF( ff );

    // check the argument
    if ( (v-1) % ((q-1)/(p-1)) != 0 ) {
        ErrorMayQuit("IntFFE: must lie in prime field", 0, 0);
    }

    // convert the value into the prime field
    v = (v-1) / ((q-1)/(p-1)) + 1;

    // return the integer value
    return ELM_PLIST( conv, v );
}


/****************************************************************************
**
*F  FuncZ( <self>, <q> )  . . .  return the generator of a small finite field
**
**  'FuncZ' implements the internal function 'Z( <q> )'.
**
**  'Z' returns the generators  of the small finite  field with <q> elements.
**  <q> must be a positive prime power.
*/

static Obj ZOp;

static Obj FuncZ(Obj self, Obj q)
{
    FF                  ff;             // the finite field

    // check the argument
    if ((IS_INTOBJ(q) && (INT_INTOBJ(q) > MAXSIZE_GF_INTERNAL)) ||
        (TNUM_OBJ(q) == T_INTPOS))
        return CALL_1ARGS(ZOp, q);

    if ( !IS_INTOBJ(q) || INT_INTOBJ(q)<=1 ) {
        RequireArgument(SELF_NAME, q, "must be a positive prime power");
    }

    ff = FiniteFieldBySize(INT_INTOBJ(q));

    if (!ff) {
        RequireArgument(SELF_NAME, q, "must be a positive prime power");
    }

    // make the root
    return NEW_FFE(ff, (q == INTOBJ_INT(2)) ? 1 : 2);
}

static Obj FuncZ2(Obj self, Obj p, Obj d)
{
    FF   ff;
    Int  ip, id, id1;
    UInt q;
    if (ARE_INTOBJS(p, d)) {
        ip = INT_INTOBJ(p);
        id = INT_INTOBJ(d);
        if (ip > 1 && id > 0 && id <= DEGREE_LARGEST_INTERNAL_FF &&
            ip <= MAXSIZE_GF_INTERNAL) {
            id1 = id;
            q = ip;
            while (--id1 > 0 && q <= MAXSIZE_GF_INTERNAL)
                q *= ip;
            if (q <= MAXSIZE_GF_INTERNAL) {
                // get the finite field
                ff = FiniteFieldBySize(q);

                if (ff == 0 || CHAR_FF(ff) != ip)
                    RequireArgument(SELF_NAME, p, "must be a prime");

                // make the root
                return NEW_FFE(ff, (q == 2) ? 1 : 2);
            }
        }
    }
    return CALL_2ARGS(ZOp, p, d);
}


/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  BagNames  . . . . . . . . . . . . . . . . . . . . . . . list of bag names
*/

static StructBagNames BagNames[] = {
  { T_FFE, "ffe" },
  { -1,    "" }
};


/****************************************************************************
**
*V  GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export
*/

static StructGVarFilt GVarFilts [] = {

    GVAR_FILT(IS_FFE, "obj", &IsFFEFilt),
    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*V  GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/

static StructGVarFunc GVarFuncs [] = {

    GVAR_FUNC_1ARGS(CHAR_FFE_DEFAULT, z),
    GVAR_FUNC_1ARGS(DEGREE_FFE_DEFAULT, z),
    GVAR_FUNC_2ARGS(LOG_FFE_DEFAULT, z, root),
    GVAR_FUNC_1ARGS(INT_FFE_DEFAULT, z),
    GVAR_FUNC_1ARGS(Z, q),
    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
*/

static Int InitKernel (
    StructInitInfo *    module )
{
    // set the bag type names (for error messages and debugging)
    InitBagNamesFromTable( BagNames );

    // install the type functions
    ImportFuncFromLibrary( "TYPE_FFE", &TYPE_FFE );
    ImportFuncFromLibrary( "TYPE_FFE0", &TYPE_FFE0 );
    ImportFuncFromLibrary( "ZOp", &ZOp );
    InitFopyGVar( "PrimitiveRootMod", &PrimitiveRootMod );
    TypeObjFuncs[ T_FFE ] = TypeFFE;

    // register global bags with the garbage collector
    InitGlobalBag( &SuccFF, "src/finfield.c:SuccFF" );
    InitGlobalBag( &TypeFF, "src/finfield.c:TypeFF" );
    InitGlobalBag( &TypeFF0, "src/finfield.c:TypeFF0" );
    InitGlobalBag( &IntFF, "src/finfield.c:IntFF" );

    // install the functions that handle overflow
    ImportFuncFromLibrary( "SUM_FFE_LARGE",  &SUM_FFE_LARGE  );
    ImportFuncFromLibrary( "DIFF_FFE_LARGE", &DIFF_FFE_LARGE );
    ImportFuncFromLibrary( "PROD_FFE_LARGE", &PROD_FFE_LARGE );
    ImportFuncFromLibrary( "QUO_FFE_LARGE",  &QUO_FFE_LARGE  );
    ImportFuncFromLibrary( "LOG_FFE_LARGE",  &LOG_FFE_LARGE  );

    // init filters and functions
    InitHdlrFiltsFromTable( GVarFilts );
    InitHdlrFuncsFromTable( GVarFuncs );
    InitHandlerFunc( FuncZ2, "src/finfield.c: Z (2 args)");


    // install the printing method
    PrintObjFuncs[ T_FFE ] = PrFFE;

    // install the comparison methods
    EqFuncs[   T_FFE ][ T_FFE ] = EqFFE;
    LtFuncs[   T_FFE ][ T_FFE ] = LtFFE;

    // install the arithmetic methods
    ZeroSameMutFuncs[T_FFE] = ZeroFFE;
    ZeroMutFuncs[ T_FFE ] = ZeroFFE;
    AInvSameMutFuncs[T_FFE] = AInvFFE;
    AInvMutFuncs[ T_FFE ] = AInvFFE;
    OneFuncs [ T_FFE ] = OneFFE;
    OneSameMut[T_FFE] = OneFFE;
    InvFuncs [ T_FFE ] = InvFFE;
    InvSameMutFuncs[T_FFE] = InvFFE;
    SumFuncs[  T_FFE ][ T_FFE ] = SumFFEFFE;
    SumFuncs[  T_FFE ][ T_INT ] = SumFFEInt;
    SumFuncs[  T_INT ][ T_FFE ] = SumIntFFE;
    DiffFuncs[ T_FFE ][ T_FFE ] = DiffFFEFFE;
    DiffFuncs[ T_FFE ][ T_INT ] = DiffFFEInt;
    DiffFuncs[ T_INT ][ T_FFE ] = DiffIntFFE;
    ProdFuncs[ T_FFE ][ T_FFE ] = ProdFFEFFE;
    ProdFuncs[ T_FFE ][ T_INT ] = ProdFFEInt;
    ProdFuncs[ T_INT ][ T_FFE ] = ProdIntFFE;
    QuoFuncs[  T_FFE ][ T_FFE ] = QuoFFEFFE;
    QuoFuncs[  T_FFE ][ T_INT ] = QuoFFEInt;
    QuoFuncs[  T_INT ][ T_FFE ] = QuoIntFFE;
    PowFuncs[  T_FFE ][ T_INT ] = PowFFEInt;
    PowFuncs[  T_FFE ][ T_FFE ] = PowFFEFFE;

    return 0;
}


/****************************************************************************
**
*F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
*/

static Int InitLibrary (
    StructInitInfo *    module )
{
    // create the fields and integer conversion bags
    SuccFF = NEW_PLIST( T_PLIST, NUM_SHORT_FINITE_FIELDS );
    SET_LEN_PLIST( SuccFF, NUM_SHORT_FINITE_FIELDS );

    TypeFF = NEW_PLIST( T_PLIST, NUM_SHORT_FINITE_FIELDS );
    SET_LEN_PLIST( TypeFF, NUM_SHORT_FINITE_FIELDS );

    TypeFF0 = NEW_PLIST( T_PLIST, NUM_SHORT_FINITE_FIELDS );
    SET_LEN_PLIST( TypeFF0, NUM_SHORT_FINITE_FIELDS );

    IntFF = NEW_PLIST( T_PLIST, NUM_SHORT_FINITE_FIELDS );
    SET_LEN_PLIST( IntFF, NUM_SHORT_FINITE_FIELDS );

#ifdef HPCGAP
    MakeBagPublic(SuccFF);
    MakeBagPublic(TypeFF);
    MakeBagPublic(TypeFF0);
    MakeBagPublic(IntFF);
#endif

    // init filters and functions
    InitGVarFiltsFromTable( GVarFilts );
    InitGVarFuncsFromTable( GVarFuncs );
    SET_HDLR_FUNC(ValGVar(GVarName("Z")), 2, FuncZ2);

    // expose MAXSIZE_GF_INTERNAL from ffdata.h to the GAP library
    ExportAsConstantGVar(MAXSIZE_GF_INTERNAL);

    return 0;
}


/****************************************************************************
**
*F  InitInfoFinfield()  . . . . . . . . . . . . . . . table of init functions
*/

static StructInitInfo module = {
    // init struct using C99 designated initializers; for a full list of
    // fields, please refer to the definition of StructInitInfo
    .type = MODULE_BUILTIN,
    .name = "finfield",
    .initKernel = InitKernel,
    .initLibrary = InitLibrary,
};

StructInitInfo * InitInfoFinfield ( void )
{
    return &module;
}

96%


¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.15Angebot  Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können  ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.