[comp.lang.ada] Alsys compiler bugs???

chuck@WOOGLIN.SCC.COM (Charles Williams) (06/08/88)

Has anyone using the Alsys compiler V3.2 seen any problems as below:

15    type Fix is delta 0.01 range -1.0 .. 1.0;
16    My_Fixed : Fix := Fix'Last;
                        ^______^
                        1      1
1 :   *EXP Value outside the range of the target type. NUMERIC_ERROR will be
            raised if executed.

This error is very confusing to me as the syntax appears perfectly legal and
the operation also looks fine.

Other compilers (Rational, DEC) compile it and execute it just fine. Who's right
and who's wrong? and more importantly, why?

Chuck Williams
Contel Federal Systems

NCOHEN@IBM.COM (Norman Cohen) (06/09/88)

Ref: INFO-ADA Volume 88 Issue 141 (Thu, Jun 9, 1988) Item #1

The Alsys, DEC, and Rational compilers may all be right.  This is
possible because of RM paragraphs 3.5.9(8..10):

 8     A fixed point type declaration of the form:

          type T is delta D range L .. R;

 9     is, by definition, equivalent to the following declarations:

          type ~fixed_point_type~ is new predefined_fixed_point_type;
          subtype T is ~fixed_point_type~
             range ~fixed_point_type~(L) .. ~fixed_point_type~(R);

10     In these declarations, ~fixed_point_type~ is an anonymous type,
       and the predefined fixed point type is implicitly selected by the
       implementation so that its model numbers include the model numbers
       defined by the fixed point constraint (that is, by D, L, and R,
       and possibly by a length clause specifying ~small~).

The behavior described by Chuck Williams could result if the predefined
fixed point types implicitly selected by DEC and Rational are one byte
long and the predefined fixed point type implicitly selected by Alsys is
longer.

Given the declaration

      type Fix is delta 0.01 range -1.0 .. 1.0;

~small~ is chosen (by 3.5.9(5)) to be the largest power of two not
greater than 0.01, so ~small~ = 1/128.  By 3.5.9(4), all model numbers of
Fix can be expressed in the canonical form

      ~sign~ * ~mantissa~ * ~small~,

where ~sign~ is +1 or -1.  By 3.5.9(6), the model numbers of Fix include
"zero and all multiples of ~small~ whose ~mantissa~ can be expressed
using exactly B binary digits, where the value of B is chosen as the
smallest integer number for which each bound of the specified range is
either a model number or lies at most ~small~ distant from a model
number."  If we choose B=7, ~mantissa~ ranges from 0 to 127, resulting in
the following model numbers:

      -127/128, -126/128, ..., 0/128, ..., 126/128, 127/128

The lower bound of the specified range, -1.0, is within ~small~ (i.e.,
within 1/128) of the model number -127/128.  Similarly, the upper bound
1.0 is within ~small~ of the model number 127/128.

Thus -1.0 and 1.0 are not within the range of the model numbers of Fix.
But what is the value of Fix'Last?

By 3.5(9), the attribute T'LAST "Yields the upper bound of T.  The value
of this attribute has the same type as T."  The same TYPE, but not
necessarily the same SUBTYPE!  Fix'Last is of type Fix'Base--the
predefined fixed-point type chosen by the implementation--but does not
necessarily belong to the first named subtype of that type, Fix.

If the implementation-chosen base type is one byte long--one bit for a
sign and seven bits for a mantissa--then the model numbers of Fix'Base
include only the model numbers of Fix. 127/128 will be the only
acceptable representation of Fix'Last, and the initialization

      My_Fixed : Fix := Fix'Last;

will succeed.  If the implementation-chosen base type is more than one
byte long, the base type will have either a wider range than Fix,
more precision than required by the model numbers of Fix, or both.  If
the base type has a wider range, Fix'Last will be represented exactly as
128/128; if the base type has more precision, there will be numbers like
255/256 that are greater than 127/128 and better representations than
127/128 for Fix'Last.  In either case, the value of Fix'Last will be
outside any model interval of Fix, so an exception will be raised.

One might argue that the exception raised should be CONSTRAINT_ERROR, not
NUMERIC_ERROR, since the range check in the assignment operation fails.
(AI-00387, a nonbinding interpretation, allows CONSTRAINT_ERROR to be
raised in place of NUMERIC_ERROR, but not vice versa.)  The choice of
NUMERIC_ERROR can be justified legally (but not morally) as follows:

Suppose Alsys chooses a 16-bit representation for Fix'Base and uses the
extra bits to provide greater precision rather than greater range. Though
it seems most reasonable to regard all exactly represented values of the
base type as model numbers of that type (and thus as safe numbers of Fix
--see 3.5.9(11)), nothing in the RM requires this.  Alsys could assert
that the model numbers of Fix'Base are precisely those of Fix, and that
there are exactly represented numbers, e.g. 16383/16384, that are higher
than the highest safe number of the type.  If such a number is chosen
as the representation of Fix'Last, then the result interval is undefined
in the sense of 4.5.7(7), and NUMERIC_ERROR may be raised by the 'Last
operation before the range check that would raise CONSTRAINT_ERROR ever
takes place.

Norman H. Cohen
IBM Research

djs@actnyc.UUCP (Dave Seward) (06/11/88)

In article <8806081155.AA02381@wooglin.scc.com> chuck@WOOGLIN.SCC.COM (Charles Williams) writes:
>15    type Fix is delta 0.01 range -1.0 .. 1.0;
>16    My_Fixed : Fix := Fix'Last;
>                        ^______^
>                        1      1
>1 :   *EXP Value outside the range of the target type. NUMERIC_ERROR will be
>            raised if executed.
>
>This error is very confusing to me as the syntax appears perfectly legal and
>the operation also looks fine.
>...and who's wrong? and more importantly, why?

Fixed point has several tricky points like this. In the simplest terms, the
delta implies a "small" value, usu. a power of 2, in this case 2.0**(-7).
The representable values of the type are integral multiples of the small value.
The specified bounds, ie -1.0 and +1.0, don't have to be representable, as
long as they are within small of being representable. In this case, the largest
representable number is (1.0 - 2.0**(-7)). The logic for this is discussed
in 3.5.9(6). This is a vast simplification, but might get you started toward
understanding it.

BTW, I'm posting as opposed to Emailing as I think a fair number of people
are confused by the same issues, and if so a discussion will ensue.

Dave Seward
uunet!actnyc!djs