# 9 Polynomials and Rationals

Many operations in computer algebra are concerned with polynomials and rational functions. In this section, we review some of the switches and operators available for this purpose. These are in addition to those that work on general expressions (such as `df`

and `int`

) described elsewhere. In the case of operators, the arguments are first simplified before the operations are applied. In addition, they operate only on arguments of prescribed types, and produce a type mismatch error if given arguments which cannot be interpreted in the required mode with the current switch settings. For example, if an argument is required to be a kernel and `a/2`

is used (with no other rules for `a`

), an error

` A/2 invalid as kernel`

will result.

With the exception of those that select various parts of a polynomial or rational function, these operations have potentially significant effects on the space and time associated with a given calculation. The user should therefore experiment with their use in a given calculation in order to determine the optimum set for a given problem.

One such operation provided by the system is an operator `length`

which returns the number of top level terms in the numerator of its argument. For example,

`julia> Algebra.length(:((a+b+c)^3/(c+d)))`

has the value 10. To get the number of terms in the denominator, one would first select the denominator by the operator `den`

and then call `length`

, as in

`julia> Algebra.length(Algebra.den(:((a+b+c)^3/(c+d))))`

Other operations currently supported, the relevant switches and operators, and the required argument and value modes of the latter, follow.

- 9 Polynomials and Rationals
- 9.1 Controlling the Expansion of Expressions
- 9.2 Factorization of Polynomials
- 9.3 Cancellation of Common Factors
- 9.4 Working with Least Common Multiples
- 9.5 Controlling Use of Common Denominators
- 9.6 REMAINDER Operator
- 9.7 RESULTANT Operator
- 9.8 DECOMPOSE Operator
- 9.9 INTERPOL operator
- 9.10 Obtaining Parts of Polynomials and Rationals
- 9.11 Polynomial Coefficient Arithmetic
- 9.12 ROOT_VAL Operator

## 9.1 Controlling the Expansion of Expressions

The switch `exp`

controls the expansion of expressions. If it is off, no expansion of powers or products of expressions occurs. Users should note however that in this case results come out in a normal but not necessarily canonical form. This means that zero expressions simplify to zero, but that two equivalent expressions need not necessarily simplify to the same form.

*Example:* With `exp`

on, the two expressions

`(a+b)*(a+2*b)`

and

`a^2+3*a*b+2*b^2`

will both simplify to the latter form. With `exp`

off, they would remain unchanged, unless the complete factoring (`allfac`

) option were in force. `exp`

is normally on.

**Note that in Reduce.jl exp is turned off by default on initialization**

Several operators that expect a polynomial as an argument behave differently when `exp`

is off, since there is often only one term at the top level. For example, with `exp`

off

`julia> Algebra.length(:((a+b+c)^3/(c+d)))`

returns the value 1.

## 9.2 Factorization of Polynomials

REDUCE is capable of factorizing univariate and multivariate polynomials that have integer coefficients, finding all factors that also have integer coefficients. The package for doing this was written by Dr. Arthur C. Norman and Ms. P. Mary Ann Moore at The University of Cambridge. It is described in P. M. A. Moore and A. C. Norman, “Implementing a Polynomial Factorization and GCD Package”, Proc. SYMSAC ’81, ACM (New York) (1981), 109-116.

The easiest way to use this facility is to turn on the switch `factor`

, which causes all expressions to be output in a factored form. For example, with `factor`

on, the expression `a^2-b^2`

is returned as `(a+b)*(a-b)`

.

`LinearAlgebra.factorize`

— Function`factorize(r...)`

It is also possible to factorize a given expression explicitly. The operator `factorize`

that invokes this facility is used with the syntax

`R"factorize(EXPRN:polynomial[,INTEXP:prime integer])"`

the optional argument of which will be described later. Thus to find and display all factors of the cyclotomic polynomial $x^{105} - 1$, one could write:

`julia> Algebra.factorize(:(x^105-1))`

The result is a list of factor,exponent pairs. In the above example, there is no overall numerical factor in the result, so the results will consist only of polynomials in x. The number of such polynomials can be found by using the operator `length`

. If there is a numerical factor, as in factorizing $12x^2 - 12$, that factor will appear as the first member of the result. It will however not be factored further. Prime factors of such numbers can be found, using a probabilistic algorithm, by turning on the switch `ifactor`

. For example,

`julia> Algebra.on(:ifactor); Algebra.factorize(:(12x^2-12))`

would result in the output

`((2, 2), (3, 1), (:(x ^ 2 + 1), 1), (:(x + 1), 1), (:(x - 1), 1))`

If the first argument of `factorize`

is an integer, it will be decomposed into its prime components, whether or not `ifactor`

is on.

Note that the `ifactor`

switch only affects the result of `factorize`

. It has no effect if the `factor`

switch is also on.

The order in which the factors occur in the result (with the exception of a possible overall numerical coefficient which comes first) can be system dependent and should not be relied on. Similarly it should be noted that any pair of individual factors can be negated without altering their product, and that REDUCE may sometimes do that.

The factorizer works by first reducing multivariate problems to univariate ones and then solving the univariate ones modulo small primes. It normally selects both evaluation points and primes using a random number generator that should lead to different detailed behavior each time any particular problem is tackled. If, for some reason, it is known that a certain (probably univariate) factorization can be performed effectively with a known prime, `p`

say, this value of `p`

can be handed to `factorize`

as a second argument. An error will occur if a non-prime is provided to `factorize`

in this manner. It is also an error to specify a prime that divides the discriminant of the polynomial being factored, but users should note that this condition is not checked by the program, so this capability should be used with care.

Factorization can be performed over a number of polynomial coefficient domains in addition to integers. The particular description of the relevant domain should be consulted to see if factorization is supported. For example, the following statements will factorize $x^4 + 1$ modulo 7:

```
Algebra.setmod(7)
Algebra.on(:modular)
Algebra.factorize(:(x^4+1))
```

The factorization module is provided with a trace facility that may be useful as a way of monitoring progress on large problems, and of satisfying curiosity about the internal workings of the package. The most simple use of this is enabled by issuing the REDUCE command `on(:trfac)`

. Following this, all calls to the factorizer will generate informative messages reporting on such things as the reduction of multivariate to univariate cases, the choice of a prime and the reconstruction of full factors from their images. Further levels of detail in the trace are intended mainly for system tuners and for the investigation of suspected bugs. For example, `trallfac`

gives tracing information at all levels of detail. The switch that can be set by `on(:timings)`

makes it possible for one who is familiar with the algorithms used to determine what part of the factorization code is consuming the most resources. `on(:overview)`

reduces the amount of detail presented in other forms of trace. Other forms of trace output are enabled by directives of the form

` symbolic set!-trace!-factor(<number>,<filename>);`

where useful numbers are 1, 2, 3 and 100, 101, ... . This facility is intended to make it possible to discover in fairly great detail what just some small part of the code has been doing — the numbers refer mainly to depths of recursion when the factorizer calls itself, and to the split between its work forming and factorizing images and reconstructing full factors from these. If `nil`

is used in place of a filename the trace output requested is directed to the standard output stream. After use of this trace facility the generated trace files should be closed by calling

` symbolic close!-trace!-files();`

*NOTE:* Using the factorizer with `mcd`

off will result in an error.

## 9.3 Cancellation of Common Factors

Facilities are available in REDUCE for cancelling common factors in the numerators and denominators of expressions, at the option of the user. The system will perform this greatest common divisor computation if the switch `gcd`

is on. (`gcd`

is normally off.)

A check is automatically made, however, for common variable and numerical products in the numerators and denominators of expressions, and the appropriate cancellations made.

When `gcd`

is on, and `exp`

is off, a check is made for square free factors in an expression. This includes separating out and independently checking the content of a given polynomial where appropriate. (For an explanation of these terms, see Anthony C. Hearn, “Non-Modular Computation of Polynomial GCDs Using Trial Division”, Proc. EUROSAM 79, published as Lecture Notes on Comp. Science, Springer-Verlag, Berlin, No 72 (1979) 227-239.)

*Example:* With `exp`

off and `gcd`

on, the polynomial `a*c+a*d+b*c+b*d`

would be returned as `(a+b)*(c+d)`

.

Under normal circumstances, GCDs are computed using an algorithm described in the above paper. It is also possible in REDUCE to compute GCDs using an alternative algorithm, called the EZGCD Algorithm, which uses modular arithmetic. The switch `ezgcd`

, if on in addition to `gcd`

, makes this happen.

In non-trivial cases, the EZGCD algorithm is almost always better than the basic algorithm, often by orders of magnitude. We therefore *strongly* advise users to use the `ezgcd`

switch where they have the resources available for supporting the package.

For a description of the EZGCD algorithm, see J. Moses and D.Y.Y. Yun, “The EZ GCD Algorithm”, Proc. ACM 1973, ACM, New York (1973) 159-166.

*NOTE:* This package shares code with the factorizer, so a certain amount of trace information can be produced using the factorizer trace switches.

An implementation of the heuristic GCD algorithm, first introduced by B.W. Char, K.O. Geddes and G.H. Gonnet, as described in J.H. Davenport and J. Padget, “HEUGCD: How Elementary Upperbounds Generate Cheaper Data”, Proc. of EUROCAL ’85, Vol 2, 18-28, published as Lecture Notes on Comp. Science, No. 204, Springer-Verlag, Berlin, 1985, is also available on an experimental basis. To use this algorithm, the switch `heugcd`

should be on in addition to `gcd`

. Note that if both `ezgcd`

and `heugcd`

are on, the former takes precedence.

### 9.3.1 Determining the GCD of Two Polynomials

This operator, used with the syntax

`R"gcd(EXPRN1:polynomial,EXPRN2:polynomial)"`

returns the greatest common divisor of the two polynomials `EXPRN1`

and `EXPRN2`

. *Examples:*

```
julia> Algebra.gcd(:(x^2+2*x+1),:(x^2+3*x+2))
:(x + 1)
julia> Algebra.gcd(:(2*x^2-2*y^2),:(4*x+4*y))
:(2 * (x + y))
julia> Algebra.gcd(:(x^2+y^2),:(x-y))
1
```

## 9.4 Working with Least Common Multiples

Greatest common divisor calculations can often become expensive if extensive work with large rational expressions is required. However, in many cases, the only significant cancellations arise from the fact that there are often common factors in the various denominators which are combined when two rationals are added. Since these denominators tend to be smaller and more regular in structure than the numerators, considerable savings in both time and space can occur if a full GCD check is made when the denominators are combined and only a partial check when numerators are constructed. In other words, the true least common multiple of the denominators is computed at each step. The switch `lcm`

is available for this purpose, and is normally on.

In addition, the operator `lcm`

, used with the syntax

`R"lcm(EXPRN1:polynomial,EXPRN2:polynomial)"`

returns the least common multiple of the two polynomials `EXPRN1`

and `EXPRN2`

.

*Examples:*

```
julia> Algebra.lcm(:(x^2+2*x+1),:(x^2+3*x+2))
:((x + 2) * (x + 1) ^ 2)
julia> Algebra.lcm(:(2*x^2-2*y^2),:(4*x+4*y))
:(4 * (x ^ 2 - y ^ 2))
```

## 9.5 Controlling Use of Common Denominators

When two rational functions are added, REDUCE normally produces an expression over a common denominator. However, if the user does not want denominators combined, he or she can turn off the switch `mcd`

which controls this process. The latter switch is particularly useful if no greatest common divisor calculations are desired, or excessive differentiation of rational functions is required.

*CAUTION:* With `mcd`

off, results are not guaranteed to come out in either normal or canonical form. In other words, an expression equivalent to zero may in fact not be simplified to zero. This option is therefore most useful for avoiding expression swell during intermediate parts of a calculation.

`mcd`

is normally on.

## 9.6 REMAINDER Operator

`Reduce.Algebra.remainder`

— Function`remainder(a,b)`

This operator is used with the syntax

`R"REMAINDER(EXPRN1:polynomial,EXPRN2:polynomial)"`

It returns the remainder when `EXPRN1`

is divided by `EXPRN2`

. This is the true remainder based on the internal ordering of the variables, and not the pseudo-remainder. The pseudo-remainder and in general pseudo-division of polynomials can be calculated after loading the `polydiv`

package. Please refer to the documentation of this package for details.

*Examples:*

```
julia> Algebra.on(:exp); Algebra.remainder(:((x+y)*(x+2*y)),:(x+3*y))
:(2 * y ^ 2)
julia> Algebra.remainder(:(2*x+y),2)
:y
```

*CAUTION:* In the default case, remainders are calculated over the integers. If you need the remainder with respect to another domain, it must be declared explicitly.

*Example:*

```
remainder(x^2-2,x+sqrt(2)); -> x^2 - 2
load_package arnum;
defpoly sqrt2**2-2;
remainder(x^2-2,x+sqrt2); -> 0
```

## 9.7 RESULTANT Operator

`Reduce.Algebra.resultant`

— Function`resultant(a,b,var)`

This is used with the syntax

`R"resultant(EXPRN1:polynomial,EXPRN2:polynomial,VAR:kernel)"`

It computes the resultant of the two given polynomials with respect to the given variable, the coefficients of the polynomials can be taken from any domain. The result can be identified as the determinant of a Sylvester matrix, but can often also be thought of informally as the result obtained when the given variable is eliminated between the two input polynomials. If the two input polynomials have a non-trivial GCD their resultant vanishes.

The switch `bezout`

controls the computation of the resultants. It is off by default. In this case a subresultant algorithm is used. If the switch Bezout is turned on, the resultant is computed via the Bezout Matrix. However, in the latter case, only polynomial coefficients are permitted.

The sign conventions used by the resultant function follow those in R. Loos, “Computing in Algebraic Extensions” in “Computer Algebra — Symbolic and Algebraic Computation”, Second Ed., Edited by B. Buchberger, G.E. Collins and R. Loos, Springer-Verlag, 1983. Namely, with `a`

and `b`

not dependent on `x`

:

```
deg(p)*deg(q)
resultant(p(x),q(x),x)= (-1) *resultant(q,p,x)
deg(p)
resultant(a,p(x),x) = a
resultant(a,b,x) = 1
```

*Examples:*

```
julia> Algebra.resultant(:(x/r*u+y),:(u*y),:u)
:(-(y ^ 2))
```

calculation in an algebraic extension:

```
load arnum;
defpoly sqrt2**2 - 2;
resultant(x + sqrt2,sqrt2 * x +1,x) -> -1
```

or in a modular domain:

```
julia> Algebra.setmod(17); Algebra.on(:modular);
julia> Algebra.resultant(:(2x+1),:(3x+4),:x)
5
```

## 9.8 DECOMPOSE Operator

`Reduce.Algebra.decompose`

— Function`decompose(p)`

The `decompose`

operator takes a multivariate polynomial as argument, and returns an expression and a list of equations from which the original polynomial can be found by composition. Its syntax is:

`R"decompose(EXPRN:polynomial)"`

For example:

```
julia> Algebra.decompose(:(x^8-88*x^7+2924*x^6-43912*x^5+263431*x^4-218900*x^3+65690*x^2-7700*x+234))
(:(u ^ 2 + 35u + 234), :(u = v ^ 2 + 10v), :(v = x ^ 2 - 22x))
julia> Algebra.decompose(:(u^2+v^2+2u*v+1))
(:(w ^ 2 + 1), :(w = u + v))
```

Users should note however that, unlike factorization, this decomposition is not unique.

## 9.9 INTERPOL operator

`Reduce.Algebra.interpol`

— Function`interpol(val,var,mp)`

Syntax:

`R"interpol(⟨values⟩,⟨variable⟩,metapoints)"`

where `⟨values⟩`

and `⟨points⟩`

are lists of equal length and `<variable>`

is an algebraic expression (preferably a kernel).

`interpol`

generates an interpolation polynomial $f$ in the given variable of degree `length(⟨values⟩)-1`

. The unique polynomial $f$ is defined by the property that for corresponding elements $v$ of `⟨values⟩`

and $p$ of `⟨points⟩`

the relation $f(p) = v$ holds.

The Aitken-Neville interpolation algorithm is used which guarantees a stable result even with rounded numbers and an ill-conditioned problem.

## 9.10 Obtaining Parts of Polynomials and Rationals

These operators select various parts of a polynomial or rational function structure. Except for the cost of rearrangement of the structure, these operations take very little time to perform.

For those operators in this section that take a kernel `VAR`

as their second argument, an error results if the first expression is not a polynomial in `VAR`

, although the coefficients themselves can be rational as long as they do not depend on `VAR`

. However, if the switch `ratarg`

is on, denominators are not checked for dependence on `VAR`

, and are taken to be part of the coefficients.

`Reduce.Algebra.deg`

— Function`deg(p,var)`

This operator is used with the syntax

`R"deg(EXPRN:polynomial,VAR:kernel)"`

It returns the leading degree of the polynomial `EXPRN`

in the variable `VAR`

. If `VAR`

does not occur as a variable in `EXPRN`

, 0 is returned.

*Examples:*

```
julia> Algebra.on(:exp)
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:a)
1
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:d)
2
julia> Algebra.deg(:((a+b)*(c+2*d)^2),:e)
0
```

Note also that if `ratarg`

is on,

` deg((a+b)^3/a,a) -> 3`

since in this case, the denominator `a`

is considered part of the coefficients of the numerator in `a`

. With `ratarg`

off, however, an error would result in this case.

`Reduce.Algebra.den`

— Function`den(r)`

This is used with the syntax:

`R"den(EXPRN:rational)"`

It returns the denominator of the rational expression `EXPRN`

. If `EXPRN`

is a polynomial, 1 is returned.

*Examples:*

```
julia> Algebra.den(:(x/y^2))
:(y ^ 2)
julia> Algebra.den(100//6)
3 [since 100/6 is first simplified to 50/3]
julia> Algebra.den(:(a/4+b/6))
12
julia> Algebra.den(:(a+b))
1
```

`Reduce.Algebra.lcof`

— Function`lcof(expr,var)`

`lcof`

is used with the syntax

`R"lcof(EXPRN:polynomial,VAR:kernel)"`

It returns the leading coefficient of the polynomial `EXPRN`

in the variable `VAR`

. If `VAR`

does not occur as a variable in `EXPRN`

, `EXPRN`

is returned.

*Examples:*

```
julia> Algebra.on(:exp)
julia> Algebra.lcof(:((a+b)*(c+2*d)^2),:a)
:(c ^ 2 + 4 * c * d + 4 * d ^ 2)
julia> Algebra.lcof(:((a+b)*(c+2*d)^2),:d)
:(4 * (a + b))
julia> Algebra.lcof(:((a+b)*(c+2*d)),:e)
:(a * c + 2 * a * d + b * c + 2 * b * d)
```

`Reduce.Algebra.lpower`

— Function`lpower(exprn,var)`

Syntax:

`R"lpower(EXPRN:polynomial,VAR:kernel)"`

`lpower`

returns the leading power of `EXPRN`

with respect to `VAR`

. If `EXPRN`

does not depend on `VAR`

, 1 is returned. *Examples:*

```
julia> Algebra.on(:exp)
julia> Algebra.lpower(:((a+b)*(c+2*d)^2),:a)
:a
julia> Algebra.lpower(:((a+b)*(c+2*d)^2),:d)
:(d ^ 2)
julia> Algebra.lpower(:((a+b)*(c+2*d)),:e)
1
```

`Reduce.Algebra.lterm`

— Function`lterm(exprn,var)`

Syntax:

`R"lterm(EXPRN:polynomial,VAR:kernel)"`

`lterm`

returns the leading term of `EXPRN`

with respect to `VAR`

. If `EXPRN`

does not depend on `VAR`

, `EXPRN`

is returned.

*Examples:*

```
julia> Algebra.on(:exp)
julia> Algebra.lterm(:((a+b)*(c+2*d)^2),:a)
:(a * (c ^ 2 + 4 * c * d + 4 * d ^ 2))
julia> Algebra.lterm(:((a+b)*(c+2*d)^2),:d)
:(4 * d ^ 2 * (a + b))
julia> Algebra.lterm(:((a+b)*(c+2*d)),:e)
:(a * c + 2 * a * d + b * c + 2 * b * d)
```

*Compatibility Note:* In some earlier versions of REDUCE, `lterm`

returned 0 if the `EXPRN`

did not depend on `VAR`

. In the present version, `EXPRN`

is always equal to `lterm(EXPRN,VAR) + reduct(EXPRN,VAR)`

.

`Reduce.Algebra.mainvar`

— Function`mainvar(exprn)`

Syntax:

`R"mainvar(EXPRN:polynomial)"`

Returns the main variable (based on the internal polynomial representation) of `EXPRN`

. If `EXPRN`

is a domain element, 0 is returned.

*Examples:* Assuming `a`

has higher kernel order than `b`

, `c`

, or `d`

:

```
julia> Algebra.on(:exp)
julia> Algebra.mainvar(:((a+b)*(c+2*d)^2))
:a
julia> Algebra.mainvar(2)
0
```

`Reduce.Algebra.num`

— Function`num(exprn)`

Syntax:

`R"num(EXPRN:rational)"`

Returns the numerator of the rational expression `EXPRN`

. If `EXPRN`

is a polynomial, that polynomial is returned.

*Examples:*

```
julia> Algebra.num(:(x/y^2))
:x
julia> Algebra.num(100//6)
50
julia> Algebra.num(:(a/4+b/6))
:(3a + 2b)
julia> Algebra.num(:(a+b))
:(a + b)
```

`Reduce.Algebra.reduct`

— Function`reduct(exprn,var)`

Syntax:

`R"reduct(EXPRN:polynomial,VAR:kernel)"`

Returns the reductum of `EXPRN`

with respect to `VAR`

(i.e., the part of `EXPRN`

left after the leading term is removed). If `EXPRN`

does not depend on the variable `VAR`

, 0 is returned.

*Examples:*

```
julia> Algebra.on(:exp)
julia> Algebra.reduct(:((a+b)*(c+2*d)),:a)
:(b * (c + 2d))
julia> Algebra.reduct(:((a+b)*(c+2*d)),:d)
:(c * (a + b))
julia> Algebra.reduct(:((a+b)*(c+2*d)),:e)
0
```

*Compatibility Note:* In some earlier versions of REDUCE, `reduct`

returned `EXPRN`

if it did not depend on `VAR`

. In the present version, `EXPRN`

is always equal to `lterm(EXPRN,VAR) + reduct(EXPRN,VAR)`

.

`Reduce.Algebra.totaldeg`

— Function`totaldeg(expr,var)`

Syntax:

```
julia> Algebra.totaldeg(:(a*x^2+b*x+c), :x)
2
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:a,:b,:c))
1
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:x, :a))
3
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:x,:b))
2
julia> Algebra.totaldeg(:(a*x^2+b*x+c), (:p,:q,:r))
0
```

`totaldeg(u, kernlist)`

finds the total degree of the polynomial `u`

in the variables in `kernlist`

. If `kernlist`

is not a list it is treated as a simple single variable. The denominator of `u`

is ignored, and "degree" here does not pay attention to fractional powers. Mentions of a kernel within the argument to any operator or function (eg `sin`

, `cos`

, `log`

, `sqrt`

) are ignored. Really `u`

is expected to be just a polynomial.

## 9.11 Polynomial Coefficient Arithmetic

REDUCE allows for a variety of numerical domains for the numerical coefficients of polynomials used in calculations. The default mode is integer arithmetic, although the possibility of using real coefficients has been discussed elsewhere. Rational coefficients have also been available by using integer coefficients in both the numerator and denominator of an expression, using the `on(:div)`

option to print the coefficients as rationals. However, REDUCE includes several other coefficient options in its basic version which we shall describe in this section. All such coefficient modes are supported in a table-driven manner so that it is straightforward to extend the range of possibilities. A description of how to do this is given in R.J. Bradford, A.C. Hearn, J.A. Padget and E. Schrüfer, “Enlarging the REDUCE Domain of Computation,” Proc. of SYMSAC ’86, ACM, New York (1986), 100–106.

### 9.11.1 Rational Coefficients in Polynomials

Instead of treating rational numbers as the numerator and denominator of a rational expression, it is also possible to use them as polynomial coefficients directly. This is accomplished by turning on the switch `rational`

.

*Example:* With `rational`

off, the input expression `a/2`

would be converted into a rational expression, whose numerator was `a`

and denominator `2`

. With `rational`

on, the same input would become a rational expression with numerator `1/2*a`

and denominator `1`

. Thus the latter can be used in operations that require polynomial input whereas the former could not.

### 9.11.2 Real Coefficients in Polynomials

The switch `rounded`

permits the use of arbitrary sized real coefficients in polynomial expressions. The actual precision of these coefficients can be set by the operator `precision`

. For example, `precision(50)`

sets the precision to fifty decimal digits. The default precision is system dependent and can be found by `precision(0)`

. In this mode, denominators are automatically made monic, and an appropriate adjustment is made to the numerator.

*Example:* With `rounded`

on, the input expression `a/2`

would be converted into a rational expression whose numerator is `0.5*a`

and denominator `1`

.

Internally, REDUCE uses floating point numbers up to the precision supported by the underlying machine hardware, and so-called *bigfloats* for higher precision or whenever necessary to represent numbers whose value cannot be represented in floating point. The internal precision is two decimal digits greater than the external precision to guard against roundoff inaccuracies. Bigfloats represent the fraction and exponent parts of a floating-point number by means of (arbitrary precision) integers, which is a more precise representation in many cases than the machine floating point arithmetic, but not as efficient. If a case arises where use of the machine arithmetic leads to problems, a user can force REDUCE to use the bigfloat representation at all precisions by turning on the switch `roundbf`

. In rare cases, this switch is turned on by the system, and the user informed by the message

` ROUNDBF turned on to increase accuracy`

Rounded numbers are normally printed to the specified precision. However, if the user wishes to print such numbers with less precision, the printing precision can be set by the command `print_precision`

. For example, `print_precision(5)`

will cause such numbers to be printed with five digits maximum.

Under normal circumstances when `rounded`

is on, REDUCE converts the number `1.0`

to the integer `1`

. If this is not desired, the switch `noconvert`

can be turned on.

Numbers that are stored internally as bigfloats are normally printed with a space between every five digits to improve readability. If this feature is not required, it can be suppressed by turning off the switch `bfspace`

.

Further information on the bigfloat arithmetic may be found in T. Sasaki, “Manual for Arbitrary Precision Real Arithmetic System in REDUCE”, Department of Computer Science, University of Utah, Technical Note No. TR-8 (1979).

When a real number is input, it is normally truncated to the precision in effect at the time the number is read. If it is desired to keep the full precision of all numbers input, the switch `adjprec`

(for adjust precision) can be turned on. While on, `adjprec`

will automatically increase the precision, when necessary, to match that of any integer or real input, and a message printed to inform the user of the precision increase.

When `rounded`

is on, rational numbers are normally converted to rounded representation. However, if a user wishes to keep such numbers in a rational form until used in an operation that returns a real number, the switch `roundall`

can be turned off. This switch is normally on.

Results from rounded calculations are returned in rounded form with two exceptions: if the result is recognized as `0`

or `1`

to the current precision, the integer result is returned.

### 9.11.3 Modular Number Coefficients in Polynomials

`Reduce.Algebra.setmod`

— Function`setmod(::Integer)`

REDUCE includes facilities for manipulating polynomials whose coefficients are computed modulo a given base. To use this option, two commands must be used; `R"setmod ⟨integer⟩"`

, to set the prime modulus, and `on(:modular)`

to cause the actual modular calculations to occur. For example, with `R"setmod 3"`

and `R"on modular"`

, the polynomial `(a+2*b)^3`

would become `a^3+2*n^3`

.

The argument of `setmod`

is evaluated algebraically, except that non-modular (integer) arithmetic is used. Thus the sequence

`R"setmod 3; on modular; setmod 7"`

will correctly set the modulus to 7.

Modular numbers are by default represented by integers in the interval $[0,p-1]$ where $p$ is the current modulus. Sometimes it is more convenient to use an equivalent symmetric representation in the interval $[-p/2+1,p/2]$, or more precisely $[-floor((p-1)/2), ceiling((p-1)/2)]$, especially if the modular numbers map objects that include negative quantities. The switch `balanced_mod`

allows you to select the symmetric representation for output.

Users should note that the modular calculations are on the polynomial coefficients only. It is not currently possible to reduce the exponents since no check for a prime modulus is made (which would allow $x^p-1$ to be reduced to 1 mod $p$). Note also that any division by a number not co-prime with the modulus will result in the error “Invalid modular division”.

### 9.11.4 Complex Number Coefficients in Polynomials

Although REDUCE routinely treats the square of the variable $i$ as equivalent to -1, this is not sufficient to reduce expressions involving $i$ to lowest terms, or to factor such expressions over the complex numbers. For example, in the default case,

`julia> Algebra.factorize(:(a^2+1))`

gives the result

`(:(a ^ 2 + 1), 1)`

and

` (a^2+b^2)/(a+i*b)`

is not reduced further. However, if the switch `complex`

is turned on, full complex arithmetic is then carried out. In other words, the above factorization will give the result

`(:(a + im, 1), (a - im, 1))`

and the quotient will be reduced to `a-I*b`

.

The switch `complex`

may be combined with `rounded`

to give complex real numbers; the appropriate arithmetic is performed in this case.

Complex conjugation is used to remove complex numbers from denominators of expressions. To do this if `complex`

is off, you must turn the switch `rationalize`

on.

## 9.12 ROOT_VAL Operator

`Reduce.Algebra.root_val`

— Function`root_val(exprn)`

The `root_val`

operator takes a single univariate polynomial as argument, and returns a list of root values at system precision (or greater if required to separate roots). It is used with the syntax

`R"root_val(EXPRN:univariate polynomial)"`

For example, the sequence

`reduce> on rounded; root_val(x^3-x-1);`

gives the result

```
{0.562279512062*I - 0.662358978622, - 0.562279512062*I
- 0.662358978622,1.32471795724}
```