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.

- Complex
- Operations for complex numbers
- ComplexConjugate
- IsComplex
- evalf
- Rational
- SetDecimalPrecision
- Operations for decimal numbers
- Pi
- Exp
- IsDecimal

`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); I gap> Complex(E(3)); -1/2+ER(3)/2I gap> Complex(E(3)^2); -1/2-ER(3)/2I gap> x:=X(Rationals);;x.name:="x";;Complex(0,x); xI

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.

The arithmetic operations `+`

, `-`

, `*`

, `/`

and `^`

work for complex
numbers. They also have `Print`

and `String`

methods.

gap> Complex(0,1); I gap> last+1; 1+I gap> last^2; 2I gap> last^2; -4 gap> last+last2; -4+2I gap> x:=X(Rationals);;x.name:="x";;Complex(0,x); xI gap> last^2; -x^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); 1/2+1/3I gap> FormatGAP(a); "Complex(1/2,1/3)"

`ComplexConjugate( `

`c`)

This function applies complex conjugation to its argument. It
knows ho to do this for cyclotomic numbers (it then just calls
`GaloisCyc(`

), complex numbers, lists (it conjugates each
element of the list), polynomials (it conjugates each coefficient), and
can be taught to conjugate elements `c`,-1)`x`

of an arbitrary domain by
defining `x.operations.ComplexConjugate`

.

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

`IsComplex( `

`c`)

This function returns `true`

iff its argument is a complex number.

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

`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); 0.3333333333

As one can see, the resulting `decimal numbers`

have an appropriate
Print method (which uses the String method).

gap> evalf(1/3,20); 0.33333333333333333333

`evalf`

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

gap> evalf(E(3)); -0.5+0.8660254038I

`evalf`

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

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

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); 1/2+1/3I gap> evalf(a); 0.5+0.3333333333I

`Rational(`

`d`)

`d` is a `decimal`

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

gap> evalf(1/3); 0.3333333333 gap> Rational(last); 33333333333/100000000000

`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); 0.33333333333333333333 gap> SetDecimalPrecision(10);

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; 1.3333333333 gap> last^3; 2.3703703704 gap> evalf(E(3)); -0.5+0.8660254038I gap> last^3; 1 gap> evalf(ER(2)); 1.4142135624 gap> GetRoot(evalf(2),2); 1.4142135624 gap> evalf(2)^(1/2); 1.4142135624 gap> evalf(1/3,20); 0.33333333333333333333 gap> last+evalf(1); 1.3333333333 gap> last2+1; 1.33333333333333333333

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)); "evalf(33333333333/100000000000,10)"

`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(); 3.1415926536 gap> Pi(34); 3.1415926535897932384626433832795029

`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)); 2.7182818285 gap> Exp(evalf(1,20)); 2.71828182845904523536 gap> Exp(Pi()*E(4)); -1

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 ); fi; z := 0 * x; res := z; p := 1; i := 1; while p <> z do res := p + res; p := 1 / i * p * x; i := i + 1; od; return res; end

`IsDecimal( `

`x`)

returns `true`

iff `x` is a decimal number.

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

gap3-jm

11 Mar 2019