# Chapter 9 THE CLASS "ENVIRONMENT"

The purpose of the environmental class is to encapsulate all constants, procedures and classes which are accessible to all source modules. It contains procedures for mathematical functions, text generation, random drawing, etc.

The general structure of ENVIRONMENT is

```  class ENVIRONMENT;
begin character CURRENTLOWTEN, CURRENTDECIMALMARK;

Basic operations ........................................ 9.1
Procedures mod, rem, abs, sign, entier,
Text utilities .......................................... 9.2
Procedures copy, blanks, char, isochar, rank, isorank,
digit, letter, lowten, decimalmark, upcase, lowcase.
Scheduling .............................................. 9.3
Procedures call (7.3.2), resume (7.3.3).
Mathematical functions .................................. 9.4
Procedures sqrt, sin, cos, tan, cotan, arcsin, arccos,
arctan, arctan2, sinh, cosh, tanh, ln, log10, exp.
Extremum functions ...................................... 9.5
Procedures max, min.
Environmental enquiries ................................. 9.6
Procedure sourceline.
Constants  maxrank, maxint, minint, maxreal, minreal,
maxlongreal, minlongreal, simulaid.
Error control ........................................... 9.7
Procedure error.
Array quantities ........................................ 9.8
Procedures upperbound, lowerbound.
Random drawing .......................................... 9.9
Procedures draw, randint, uniform, normal, negexp,
Poisson, Erlang, discrete, linear, histd.
Calendar and timing utilities ........................... 9.10
Procedures datetime, cputime, clocktime.
Miscellaneous utilities ................................. 9.11
Procedure histo.
Standard system classes ................................. 9.12
Classes simset (ch. 11), simulation (ch. 12).

CURRENTDECIMALMARK := '.';
CURRENTLOWTEN      := '&'

end ENVIRONMENT;
```

## Basic operations

```  MOD          integer procedure mod(i,j);   integer i,j;
begin integer res;
res := i - (i//j)*j;
mod := if res = 0 then 0
else if sign(res) <> sign(j) then res+j
else res
end mod;

The result is the mathematical modulo value of the parameters.

REM          integer procedure rem(i,j);   integer i,j;
rem := i - (i//j)*j;

The result is the remainder of an integer division.

ABS          <type of e> procedure abs(e);    e;
abs := if e >= 0 then e else -e;

The result is the absolute value of the parameter.

SIGN         integer procedure sign(e);    e;
sign := if      e > 0 then  1
else if e < 0 then -1 else 0;

The result is zero if the parameter is zero, one if the
parameter is positive, and minus one otherwise.

ENTIER       integer procedure entier(r); <real-type> r;
begin integer j;
j := r;             ! implied conversion of "r" to integer ;
entier:= if j > r   ! implied conversion of "j" to real ;
then j-1 else j
end entier;

The result is the integer "floor" of a real type item, the value
always being less than or equal to the parameter. Thus,
entier(1.8) returns the value 1, while entier(-1.8) returns -2.

ADDEPSILON   <type of e> procedure addepsilon(e);   <real-type> e;
addepsilon := e + ... ; ! see below;

SUBEPSILON   <type of e> procedure subepsilon(e);   <real-type> e;
subepsilon := e - ... ; ! see below;

The result type is that of the parameter. The result is the
value of the parameter incremented (addepsilon) or decremented
(subepsilon) by the smallest positive value, such that the
result is not equal to the parameter within the precision of
the implementation. Thus, for all positive values of "eps",

E-eps <= subepsilon(E) < E < addepsilon(E) <= E+eps
```

## Text utilities

```  COPY         See 8.3.
BLANKS       See 8.3.

CHAR         character procedure char(i);  integer i;
char := ... ;

The result is the character obtained by converting the parameter
according to the implementation-defined coding of characters.
The parameter must be in the range 0..maxrank.

ISOCHAR      character procedure isochar(i);  integer i;
isochar := ... ;

The result is the character obtained by converting the parameter
according to the ISO 2022 standard character code.
The parameter must be in the range 0..255.

RANK         integer procedure rank(c);  character c;
rank := ... ;

The result is the integer obtained by converting the parameter
according to the implementation-defined character code.

ISORANK      integer procedure isorank(c);  character c;
isorank := ... ;

The result is the integer obtained by converting the parameter
according to the ISO 2022 standard character code.

DIGIT        Boolean procedure digit(c);  character c;
digit := ... ;

The result is true if the parameter is a decimal digit.

LETTER       Boolean procedure letter(c);  character c;
letter := ... ;

The result is true if the parameter is a letter of the English
alphabet ('a' ... 'z', 'A' ... 'Z').

LOWTEN       character procedure lowten(c);  character c;
if ... ! c is illegal as lowten;
then  error("..." ! Lowten error ;)
else begin
lowten:= CURRENTLOWTEN; CURRENTLOWTEN:= c
end lowten;

Changes the value of the current lowten character to that of the
parameter. The previous value is returned. Illegal parameters are

digits, plus ("+"), minus ("-"), dot ("."), comma (","),
control characters (i.e. ISO code<32), DEL (ISO code 127),
and all characters with ISO code greater than 127.

DECIMALMARK  character procedure decimalmark(c);   character c;
if c <> '.' and then c <> ','
then error("..." ! Decimalmark error ;)
else begin
decimalmark:= CURRENTDECIMALMARK; CURRENTDECIMALMARK:= c
end decimalmark;

Changes the value of the decimal point character used by the text
(de)editing procedures (cf. 8.7 and 8.8). The previous value is
returned. The only legal parameter values are dot and comma.

UPCASE       text procedure upcase(t);   text t;
begin  t.setpos(1); upcase:- t;  ... end;

Convert the letters in the text parameter to their upper case
representation. Only letters of the English alphabet are
converted. The result is a reference to the parameter.

LOWCASE      text procedure lowcase(t); text t;
begin  t.setpos(1); lowcase:- t; ... end;

Convert the letters in the text parameter to their lower case
representation. Only letters of the English alphabet are
converted. The result is a reference to the parameter.
```

## Scheduling

```  CALL         See 7.3.2.
RESUME       See 7.3.3.
```

In addition the procedure "detach" (7.3.1) is an attribute of any class.

## Mathematical functions

These procedures return long real results whenever a parameter is of this type. Otherwise a real type result is returned (cf. 3.3.1).

All procedures return real type approximations to the associated mathematical functions. Their exact definitions (concerning precision, allowed parameter values etc.) are implementation-defined. The procedures return best possible approximations to the exact mathematical results.

The trigonometric functions deal with angles expressed in radians.

```  SQRT     <real-type> procedure sqrt(r);      <real-type> r;

SIN      <real-type> procedure sin(r);       <real-type> r;

COS      <real-type> procedure cos(r);       <real-type> r;

TAN      <real-type> procedure tan(r);       <real-type> r;

COTAN    <real-type> procedure cotan(r);     <real-type> r;

ARCSIN   <real-type> procedure arcsin(r);    <real-type> r;

ARCCOS   <real-type> procedure arccos(r);    <real-type> r;

ARCTAN   <real-type> procedure arctan(r);    <real-type> r;

The result is in the range (0,pi/2) for non-negative parameters and
in the range (-pi/2,0) for negative parameters.

ARCTAN2  <real-type> procedure arctan2(y,x); <real-type> y,x;

The result is in the range(-pi,pi) and a negative value is returned
whenever y is negative. Positive y values always result in a
positive result, while a zero value returns zero if x is positive
and pi if x is negative. If both y and x are zero, a runtime error
occurs.

SINH     <real-type> procedure sinh(r);      <real-type> r;

COSH     <real-type> procedure cosh(r);      <real-type> r;

TANH     <real-type> procedure tanh(r);      <real-type> r;

LN       <real-type> procedure ln(r);        <real-type> r;

LOG10    <real-type> procedure log10(r);     <real-type> r;

EXP      <real-type> procedure exp(r);       <real-type> r;
```

## Extremum functions

MAX <type> procedure max(i1,i2); <type> i1; <type> i2; MIN <type> procedure min(i1,i2); <type> i1; <type> i2; The value is the greater (MAX) or lesser (MIN) of the two parameter values. Legal parameter types are text, character, real type and integer type. The type of the result conforms to the rules of 3.3.1.

## Environmental enquiries

```  SOURCELINE   integer procedure sourceline;

The value indicates the line on which the procedure call occurs.
The interpretation of this number is implementation-defined.

MAXLONGREAL  long real maxlongreal = ... ,
MINLONGREAL            minlongreal = ... ;

MAXREAL      real maxreal = ... ,
MINREAL           minreal = ... ;

MAXRANK      integer maxrank = ... ,  !the largest legal argument to char;
MAXINT               maxint  = ... ,
MININT               minint  = ... ;

These constants define some of the implementation
characteristics. The "max..." ("min...") constants have the
largest (smallest) values possible for their type.

SIMULAID     text simulaid = ... ; ! See below ;
```

The value of "simulaid" is an implementation defined string of the following general format:

```    <simid>!!!<siteid>!!!<OS>!!!<CPU>!!!<user>!!!<job>!!!<acc>!!!<prog>

<simid>:   Identification of the SIMULA system (name, version etc.)
<siteid>:  Identification of the installation (e.g. organisation name)
<OS>:      Operating system identification (name, version, etc.)
<CPU>:     Host system identification (manufacturer, name, number, etc.)
<user>:    User identification
<job>:     Job identification (session number)
<acc>:     Account identification
<prog>:    Identification of the executing task or program
```

## Error control

```  ERROR        procedure error(t);   text t;
begin ... display text "t" and stop program...
end error;
```

The procedure "error" stops the execution of the program as if a runtime error has occurred and presents the contents of the text parameter on the diagnostic channel (normally the controlling terminal).

## Array quantities

```  LOWERBOUND   integer procedure lowerbound(a,i);
<type> array a; integer i;

UPPERBOUND   integer procedure upperbound(a,i);
<type> array a; integer i;
```

The procedure "lowerbound" ("upperbound") returns the lower (upper) bound of the dimension of the given array corresponding to the given index. The first dimension has index one, the next two, etc. An index less than one or greater than the number of dimensions of the given array constitutes a run time error.

## Random drawing

All random drawing procedures of SIMULA are based on the technique of obtaining "basic drawings" from the uniform distribution in the interval <0,1>.

### Pseudo-random number streams

A basic drawing replaces the value of a specified integer variable, say U, by a new value according to an implementation-defined algorithm.

As an example, the following algorithm may be suitable for binary computers:

```                   U(i+1) = remainder ((U(i) * 5**(2*p+1)) // 2**n)
```

where U(i) is the i'th value of U, n is an integer related to the size of a computer word and p is a positive integer. It can be proved that, if U(0) is a positive odd integer, the same is true for all U(i) and the sequence U(0), U(1), U(2), ... is cyclic with period 2**n-2. (The last two bits of U remain constant, while the other n-2 take on all possible combinations). Thus there are two sequences - one in the range (1:2**n-3) and the other in (3:2**n-1).

It is a property of this algorithm that any successor to a stream number U(i), e.g. U(i+m), can be computed using modular arithmetic in log2(m) steps.

The real numbers u(i) = U(i) * 2**(-n) are fractions in the range <0,1>. The sequence u(1), u(2), ... is called a "stream" of pseudo- random numbers, and u(i) (i = l,2, ...) is the result of the i'th basic drawing in the stream U. A stream is completely determined by the initial value U(0) of the corresponding integer variable. Nevertheless, it is a "good approximation" to a sequence of truly random drawings.

By reversing the sign of the non-zero initial value U(0) of a stream variable, the antithetic drawings 1-u(1), 1-u(2), ... should be obtained. In certain situations it can be proved that means obtained from samples based on antithetic drawings have a smaller variance than those obtained from uncorrelated streams. This can be used to reduce the sample size required to obtain reliable estimates.

### Random drawing procedures

The following procedures all perform a random drawing of some kind. "Normal", "draw", "randint", "uniform", "negexp", "discrete", "linear" and "histd" always perform the operation by means of one single basic drawing, i.e. the procedure has the side effect of advancing the specified stream by one step. The necessary type conversions are effected for the actual parameters, with the exception of the last one. The latter must always be an integer variable specifying a pseudo-random number stream. Note, that it must not be a procedure parameter transferred by name.

```  DRAW         Boolean procedure draw (a,U);
name U; long real a; integer U;

The value is true with the probability a, false with the
probability 1 - a. It is always true if a >= 1 and always
false if a <= 0.

RANDINT      integer procedure randint (a,b,U);
name U; integer a,b,U;

The value is one of the integers a, a+1, ..., b-1, b with equal
probability. If b < a, the call constitutes an error.

UNIFORM      long real procedure uniform (a,b,U);
name U; long real a,b; integer U;

The value is uniformly distributed in the interval a <= u < b.
If b < a, the call constitutes an error.

NORMAL       long real procedure normal (a,b,U);
name U; long real a,b; integer U;

The value is normally distributed with mean a and standard
deviation b. An approximation formula may be used for the normal
distribution function.

NEGEXP       long real procedure negexp (a,U);
name U; long real a; integer U;

The value is a drawing from the negative exponential distribution
with mean 1/a, defined by -ln(u)/a, where u is a basic drawing.
This is the same as a random "waiting time" in a Poisson
distributed arrival pattern with expected number of arrivals per
time unit equal to a. If a is non-positive, a runtime error
occurs.

POISSON      integer procedure Poisson (a,U);
name U; long real a; integer U;

The value is a drawing from the Poisson distribution with
parameter a. It is obtained by n+1 basic drawings, u(i), where n
is the function value. n is defined as the smallest non-negative
integer for which
u(0) * u(1) * ... * u(n)  <  e**(-a)

The validity of the formula follows from the equivalent condition
-ln(u(0)) - ln(u(1)) - ... - ln(u(n))  >  1
where the left hand side is seen to be a sum of "waiting times"
drawn from the corresponding negative exponential distribution.

When the parameter a is greater than some implementation-defined
value, for instance 20.0, the value may be approximated by
entier(normal(a,sqrt(a),U) + 0.5) or, when this is negative, by
zero.

ERLANG       long real procedure Erlang (a,b,U);
name U; long real a,b; integer U;

The value is a drawing from the Erlang distribution with mean 1/a
and standard deviation 1/(a*sqrt(b)). It is defined by b basic
drawings u(i), if b is an integer value,

- ( ln(u(1)) + ln(u(2)) + ... + ln(u(b)) )  /  (a*b)

and by c+1 basic drawings u(i) otherwise, where c is equal to
entier(b),

- ( ln(u(1)) + ... + ln(u(c)) + (b-c)*ln(u(c+1)) ) / (a*b)

Both a and b must be greater than zero.

The last formula represents an approximation.

DISCRETE     integer procedure discrete (A,U);
name U; <real-type> array A; integer U;

The one-dimensional array A, augmented by the element 1 to the
right, is interpreted as a step function of the subscript,
defining a discrete (cumulative) distribution function.

The function value satisfies
lowerbound(A,1) <= discrete(A,U) <= upperbound(A,1)+1.

It is defined as the smallest i such that A(i) > u, where u is a
basic drawing and A(upperbound(A,1)+1) = 1.

LINEAR       long real procedure linear (A,B,U);
name U; <real-type> array A,B; integer U;

The value is a drawing from a (cumulative) distribution function
F, which is obtained by linear interpolation in a non-equidistant
table defined by A and B, such that A(i) = F(B(i)).

It is assumed that A and B are one-dimensional arrays of the
same length, that the first and last elements of A are equal
to 0 and 1 respectively and that A(i) >= A(j) and B(i) > B(j)
for i>j. If any of these conditions are not satisfied, the effect
is implementation-defined.

The steps in the function evaluation are:

l. draw a uniform <0,1> random number, u.

2. determine the lowest value of i, for which

A(i-1) <= u <= A(i)

3. compute D = A(i) - A(i-1)

4. if D = 0:  linear = B(i-1)
if D <> 0: linear = B(i-1) + (B(i) - B(i-1))*(u-A(i-1))/D

HISTD        integer procedure histd (A,U);
name U; <real-type> array A; integer U;

The value is an integer in the range (lsb,usb), where lsb and
usb are the lower and upper subscript bounds of the
one-dimensional array A. The latter is interpreted as a
histogram defining the relative frequencies of the values.
```

## Calendar and timing utilities

```  DATETIME:    text procedure datetime;   datetime :- Copy("...");

The value is a text frame containing the current date and time
in the form    YYYY-MM-DD HH:MM:SS.sss.... The number of
decimals in the field for seconds is implementation-defined.

CPUTIME:     long real procedure cputime;

The value is the number of processor seconds spent by the
calling program.

CLOCKTIME:   long real procedure clocktime;

The value is the number of seconds since midnight.
```

## Miscellaneous utilities

``` HISTO:       procedure histo(A,B,c,d);
real array A,B; real c,d;
```

Procedure statement "histo(A,B,c,d)" updates a histogram defined by the one-dimensional arrays A and B according to the observation c with the weight d. A(lba+i) is increased by d, where i is the smallest integer such that c <= B(lbb+i) and lba and lbb are the lower bounds of A and B respectively. If the length of A is not one greater than that of B the effect is implementation-defined. The last element of A corresponds to those observations which are greater than all elements of B.

## Standard system classes

The standard system classes are "simset", "simulation" and the I/O classes. They are available at any block level of a program (cfr. 5.5.1).

Class "simset" contains facilities for list (set) manipulation, see chapter 11.

Simset class "simulation" contains facilities for discrete event simulation, see chapter 12.

The I/O classes ("file" and its subclasses) are defined in class BASICIO, see chapter 10.