Page images

Underflow, whether for expressions or constants, is only recommended as an exception, but, in any case, zero must be supplied when the magnitude of the result is below the minimum representable by the implementation. Note that this is required in the semantics sections (7.4 and 5.4) of the standard, not the exception sections (7.5 and 5.5).

5.6.3 Errors

These programs try out the effect of various constructions which represent either common programming errors (missing parentheses) or common enhancements ( ** as the involution operator) or a blend of the two (adjacent operators). operators). No special interpretation rules apply to these tests beyond those normally associated with error programs.

[blocks in formation]

Although the standard mandates particular accuracу for expression evaluation, such accuracy is nonetheless an important measure of the quality of language implementation, and is of interest to a large proportion of language users. Accordingly, these tests apply a criterion of accuracy for the arithmetic operations which is suggested by the standard's requirement that individual six significant


numeric values be represented accurate

to decimal digits. Note, however, that these tests are not only because there is no strict accuracy requirement, but also because there is no generally valid way for computer to measure precisely the accuracy of its operations.



Such a measurement involves calculations which must use the very facilities being measured.

The criterion for passing or failing is based on the concept that an implementation should be be at least as accurate as a reasonable hypothetical implementation which uses the least

It is

accurate numeric representation allowed by the standard. best explained by first considering accuracy for functions of a single variable, and then generalizing to operations, which may be thought of as functions of two variables. Given an internal precision of at least d decimal digits, we simply require that the computed value for f(x) (hereinafter denoted by "cf(x)") be some value actually taken on by the function within the domain [x-e, x+e], where

[blocks in formation]

For example, suppose we want to test the value returned by sin(29.1234) and we specify that d=6. Then:

[merged small][ocr errors][merged small][merged small][merged small][ocr errors][merged small][merged small]

and so we we require that csin(x) equal some value taken on by sin(x) in the interval [29.1233, 29.1235]. This then reduces to the test that -.7507297957 <= csin (29.1234) <= -.7505976588.


The motivation for the formula for for e is as follows. According to the rule for accuracy of numbers, the internal representation of the argument must lie within [x - e/2, x + e/2]. Now suppose that the internal representation is near an endpoint of the legal interval, and that the granularity of the machine (i.e., the difference between adjacent internal numeric representations) in that region of the real number line is near e (which would be the coarsest allowed, given accuracy of d digits). Given this worst case, we would still want a value returned for which the actual argument was closer to that internal representation than immediately adjacent representations. This means that we allow for a variation of e/2 when the argument is converted from source to internal form, another variation of e/2 around the internal representation itself. The maximum allowable variation along the x-axis is then simply the sum of the worst-case variations: e/2 + e/2 = e. This is reasonable if we think of a given internal form as representing not only a point on the real number line, but the set of points for which there is no closer internal form. Then, all we know is that the source argument is somewhere within that set and all we require is that the computed value of the function be true for some (probably different) argument within the set. For accuracy d, the maximum width of the set is of course e.


It should be noted that the first allowed variation of e/2 is inherent in the process of decimal (source) to, e.g., binary (internal) conversion. The case for allowing a variation of e/2 around the internal representation itself is somewhat weaker. If one insists on exact results within the internal numerical manipulation, then the function would be allowed to vary only within the domain [x e/2, xe/2], but we did not require this

in the tests.

Note that the above scheme not only allows for the discrete nature of the machine, but also for numeric instability in the function itself. Mathematically, if the value of an argument is known to six places, it does not follow that the value of the function is known to six places; the error may be considerably more or less. For example, a function is often very stable near where its graph crosses the y-axis, but not the x-axis (e.g. COS (1E-22)) and very unstable where it crosses the x-axis but not the y-axis (e.g. SIN (21.99)). By allowing the cf(x) to take on any value in the specified domain, we impose strict accuracy where it can be achieved, and permit low accuracy where appropriate. Thus, the pass/fail criterion is independent of

both the argument and function; it reflects only how well the implementation computed, relative to a worst-case six-digit


Finally, we must recognize that even if the value of a function is computable to high accuracy (as with COS (1E-22)), the graininess of the machine will again limit how accurately the result itself can be represented. For this reason, there is an additional allowance of e/2 around the result. This implies that even if the result is computable to, say, 20 digits, we never require more than 6 digits of accuracy.

Now all the preceding comments generalize quite naturally to functions of many variables. We can then be guided in our treatment of the arithmetic operations by the above remarks on functions, if we recall that the operations may be thought of as functions of two variables, namely their operands. If we think of, say, subtraction as such a function (i.e. subtract (x,y) = x-y), then the same considerations of argument accuracy and mathematical stability pertain. Thus, we allow both operands to vary within their intervals, and simply require the result of the operation to be within the extreme values so generated. Note that such a technique would be necessary for any of the usual functions which take two variables, such as some versions of arctan.

It should be stressed that the resulting accuracy tests represent only a very minimal requirement. The design goal was to permit even the grainiest machine allowed by the standard to pass the tests; all conforming implementations, then, are inherently capable of passing. Many users will wish to impose more stringent criteria. For example, those interested in high accuracy, or implementors whose machines carry more than six digits, should examine closely the computed value and true value to see if the accuracy is what they expect.


The ANSI standard provides a loop capability, along with an associated control-variable, through the use of the FOR statement. The semantic requirements for this construction are particularly well-defined. Specifically, the effect of the FOR is described in terms of more primitive language features (IF, GOTO, LET, and REM), which are themselves not very vulnerable to misinterpretation. The tests accordingly are quite specific and extensive in the behavior they require. The standard tests are completely self-checking, since conformance depends only on the value of the control-variable and number of times through the loop. The general design plan was not only to determine passing or failing, but also to display information allowing the user to examine the progress of execution. This should help you diagnose any problems. Note especially the requirement that the control variable, upon exit from the loop, should have the first unused, not the last used, value.

The FOR statement has no associated exceptions, but it does have a rich variety of errors, many of them context sensitive, and therefore somewhat harder for an implementation to detect. As always, if any error programs are accepted, the documentation must specify what meaning the implementation assigns to them.

[blocks in formation]

The standard provides for storing numeric values in one- or two-dimensional arrays. The tests for standard capabilities are all self-checking and quite straightforward in exercising some feature defined in the standard. the requirement that subscript values be rounded to integers; the program testing this must not cause an exception or the processor fails.


[blocks in formation]

The exception tests ensure that the subscript out of range condition is handled properly. Note that it is here that the real semantic meaning of OPTION and DIM are exercised; they have little effect other than to cause exception for certain subscript values. exception, you must check (since the programs terminate at the right time, as indicated in their


or prevent the subscript Since this is a fatal program cannot) that the

[blocks in formation]

As with the FOR statement, there are a considerable number of syntactic restrictions. The thrust of these restrictions is to assure that OPTION precedes DIM, that DIM precedes references to the arrays that it governs, and that declared subscript bounds are compatible.

Three of the error programs call for INPUT from the user. This is to help you diagnose the actual behavior of the implementation if it accepts the programs. The first of these, #73, lets you try to reference an array with a subscript of 0 or 1 when OPTION BASE 1 and DIM A(0) have been specified, to see when an exception occurs.

The second, #81, allows you to try a subscript of 0 or 1 for an array whose DIM statement precedes the OPTION statement.

The third program using INPUT, #84, is a bit more complex and has to do with double dimensioning. If there are two DIM statements for the same array, the implementation has a choice of

five such

several plausible interpretations. We have noted possibilities and have attempted to distinguish which, if any, seems to apply. Since the only semantic effect of DIM is to cause or prevent an exception for a given array reference, however, it is necessary to run the program three times to see when exceptions occur and when they don't, assuming the processor hasn't simply rejected the program outright. Your input-reply simply tells the program which of the three executions it is currently performing. For each execution, you must note whether an exception occurred or not and then match the results against the table in the program. Suppose, for instance, that you get an exception the first time but not the second or third. That would be incompatible with all five interpretations except number 4, which is that the first DIM statement executed sets the size of the array and it is never changed thereafter. As usual, check the documentation make sure it correctly describes what happens.


5.9 Control Statements

This group fully exploits the properties of some of the control facilities which were tested in a simpler way in group 4. As before, there seemed no good way to provide diagnostics for failure of standard tests, since the behavior of a failing processor is impossible to predict. Passing implementations will cause the !! *** TEST PASSED ***" message to appear, but certain kinds of failures might cause the programs to abort, without producing a failure message. Check Volume 2 for an example of correct output.




Most of the tests in this group are self-explanatory, the one checking address stacking deserves some comment. standard describes the effect of issuing GOSUBS and RETURNS in terms of a stack of return addresses, for which the GOSUB adds a new address to the top, and the RETURN uses the most recently added address. Thus, we get a kind of primitive recursion in the control structure (although without any stacking of data). Note that this description allows complete freedom in the placement of GOSUBS and RETURNS in the source code. There is no static

association of any RETURN with any GOSUB. The test which verifies this specification computes binomial coefficients, using the usual recursive formula. The logic of the program is a bit convoluted, but intentionally so, in order to exercise the stacking mechanism vigorously.

« PreviousContinue »