109 CHEVIE utility functions -- Decimal and complex numbers

The original incentive for the functions described in this file was to get the ability to decide if a cyclotomic number which happens to be real is positive or negative (this is needed to tell if a root of an arbitrary Coxeter group is negative or positive). Of course, there are other uses for fixed-precision real and complex numbers, which the functions described here provide. A special feature of the present implementation is that to make evaluation of cyclotomics relatively fast, a cache of primitive roots of unity is maintained (the cached values are kept for the largest precision ever used to compute them).

We first describe a general facility to build complex numbers as pairs of real numbers. The real numbers in the pairs can be of any type that GAP3 knows about: integers, rationals, cyclotomics, or elements of any ring actually.


  1. Complex
  2. Operations for complex numbers
  3. ComplexConjugate
  4. IsComplex
  5. evalf
  6. Rational
  7. SetDecimalPrecision
  8. Operations for decimal numbers
  9. Pi
  10. Exp
  11. IsDecimal

109.1 Complex

Complex( r[, i] )

In the first form, defines a complex number whose real part is r and imaginary part is i. If omitted, i is taken to be 0. There are two special cases when there is only one argument: if r is already a complex, it is returned; and if r is a cyclotomic number, it is converted to the pair of its real and imaginary part and returned as a complex.

    gap> Complex(0,1);
    gap> Complex(E(3));
    gap> Complex(E(3)^2);
    gap> x:=X(Rationals);;x.name:="x";;Complex(0,x);

The last line shows that the arguments to Complex can be of any ring. Complex numbers are represented as a record with two fields, .r and .i holding the real and imaginary part respectively.

109.2 Operations for complex numbers

The arithmetic operations +, -, *, / and ^ work for complex numbers. They also have Print and String methods.

    gap> Complex(0,1);
    gap> last+1;
    gap> last^2;
    gap> last^2;
    gap> last+last2;
    gap> x:=X(Rationals);;x.name:="x";;Complex(0,x);
    gap> last^2;

Finally we should mention the FormatGAP method, which allows to print complex numbers in a way such that they can be read back in GAP3:

    gap> a:=Complex(1/2,1/3);
    gap> FormatGAP(a);

109.3 ComplexConjugate

ComplexConjugate( c)

This function applies complex conjugation to its argument. It knows ho to do this for cyclotomic numbers (it then just calls GaloisCyc(c,-1)), complex numbers, lists (it conjugates each element of the list), polynomials (it conjugates each coefficient), and can be taught to conjugate elements x of an arbitrary domain by defining x.operations.ComplexConjugate.

    gap> ComplexConjugate(Complex(0,1));
    gap> ComplexConjugate(E(3));
    gap> x:=X(Cyclotomics);;x.name:="x";;ComplexConjugate(x+E(3));
    x + (E(3)^2)

109.4 IsComplex

IsComplex( c)

This function returns true iff its argument is a complex number.

    gap> IsComplex(Complex(1,0));
    gap> IsComplex(E(4));

109.5 evalf

evalf( c [, prec] )

The name of this function intentionally mimics that of a Maple function. It computes a fixed-precision decimal number with prec digits after the decimal point approximating its argument; if not given, prec is taken to be 10 (this can be changed via the function SetDecimalPrecision, see below). Trailing zeroes are not shown on output, so the actual precision may be more than the number of digits shown.

    gap> evalf(1/3);

As one can see, the resulting decimal numbers have an appropriate Print method (which uses the String method).

    gap> evalf(1/3,20);

evalf can also be applied to cyclotomic or complex numbers, yielding a complex which is a pair of decimal numbers.

    gap> evalf(E(3));

evalf works also for strings (the result is truncated if too precise)

    gap> evalf(".3450000000000000000001"); # precision is 10

and for lists (it is applied recursively to each element).

    gap> evalf([E(5),1/7]);
    [ 0.3090169944+0.9510565163I, 0.1428571429 ]

Finally, an evalf method can be defined for elements of any domain. One has been defined in CHEVIE for complex numbers:

    gap> a:=Complex(1/2,1/3);
    gap> evalf(a);

109.6 Rational


d is a decimal number. The function returns the rational number which is actually represented by d

    gap> evalf(1/3);
    gap> Rational(last);

109.7 SetDecimalPrecision

SetDecimalPrecision( prec )

This function sets the default precision to be used when converting numbers to decimal numbers without giving a second argument to evalf.

    gap> SetDecimalPrecision(20);
    gap> evalf(1/3);
    gap> SetDecimalPrecision(10);

109.8 Operations for decimal numbers

The arithmetic operations +, -, *, / and ^ work for decimal numbers, as well as the function GetRoot and the comparison functions <, >, etc... The precision of the result of an operation is that of the least precise number used. They can be raised to a fractional power: GetRoot(d,n) is equivalent to d^(1/n). Decimal numbers also have Print and String methods.

    gap> evalf(1/3)+1;
    gap> last^3;
    gap> evalf(E(3));
    gap> last^3;
    gap> evalf(ER(2));
    gap> GetRoot(evalf(2),2);
    gap> evalf(2)^(1/2);
    gap> evalf(1/3,20);
    gap> last+evalf(1);
    gap> last2+1;

Finally we should mention the FormatGAP method, which, given option GAP, allows to print decimal numbers in a way such that they can be read back in GAP3:

    gap> FormatGAP(evalf(1/3));

109.9 Pi

Pi( [prec])

This function returns a decimal approximation to π, with prec digits (or if prec is omitted with the default umber of digits defined by SetDecimalPrecision, initially 10).

    gap> Pi();
    gap> Pi(34);

109.10 Exp

Exp( x)

This function returns the complex exponential of x. The argument should be a decimal or a decimal complex. The result has as many digits of precision as the argument.

    gap> Exp(evalf(1));
    gap> Exp(evalf(1,20));
    gap> Exp(Pi()*E(4));

The code of Exp shows how easy it is to use decimal numbers.

    gap> Print(Exp,"\n");
    function ( x )
        local  res, i, p, z;
        if IsCyc( x )  then
            x := evalf( x );
        z := 0 * x;
        res := z;
        p := 1;
        i := 1;
        while p <> z  do
            res := p + res;
            p := 1 / i * p * x;
            i := i + 1;
        return res;

109.11 IsDecimal

IsDecimal( x)

returns true iff x is a decimal number.

    gap> IsDecimal(evalf(1));
    gap> IsDecimal(evalf(E(3)));

Previous Up Next

24 Apr 2021