Unsigned integer types can be provided AI00597/03 1
900707 BI WI
 !standard 03.05.04 (07) 900707 AI00597/03
!class binding interpretation 881010
!edited by Bardin (provisional classification)
!status workitem 881010
!references AI00402, AI00387
!topic Unsigned integer types can be provided
!summary 881010 (DRAFT)
Although an unsigned integer type cannot be a predefined integer type and so
cannot be declared in package STANDARD, an implementation is allowed to
provide such a type in packages other than STANDARD.
!question 881010 (DRAFT)
Can an implementation provide an unsigned integer type in package SYSTEM or
in some implementationdefined library package?
!recommendation 900515 (DRAFT)
Implementationdefined integer base types having nonsymmetric ranges can be
declared in packages other than STANDARD. Such types are not considered to
be predefined integer types, i.e., SYSTEM.MIN_INT and SYSTEM.MAX_INT are
defined without considering such types, nor do such types serve as base types
for integer type definitions. Such types must otherwise conform to the
properties required of integer types in general.
!discussion 900515 (DRAFT)
3.5.4(7) says:
The predefined integer types include the type INTEGER. An
implementation may also have predefined types such as SHORT_
INTEGER and LONG_INTEGER, which have (substantially) shorter and
longer ranges, respectively, than INTEGER. The range of each of
these types must be symmetric about zero, excepting an extra
negative value which may exist in some implementations.
The phrase "each of these types" refers to the predefined integer types (as
explained in AI00402). However, unsigned integer types are of considerable
use in some applications. If the largest predefined integer type has N bits
(including sign), it is not possible for a user to declare an integer type
N
that has the range 0..2  1, since the upper bound would exceed the range of
the largest predefined integer type, and 3.5.4(6) requires that there exist a
predefined integer type that contains the bounds given in an integer type
definition. 3.5.4(7) should not be understood to forbid the declaration of
an implementationdefined unsigned integer type in some implementation
defined package.
In particular, note that 3.5.5(15) says:
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 2
900707 BI WI
For integer types, operations include the predefined ARITHMETIC
operators: these are the binary and unary adding operators  and
+, all multiplying operators, the unary operator ABS, and the
exponentiating operator.
and that 4.5.2(1) says, in part:
The equality and inequality operators are predefined for any type
that is not limited. ... The ordering operators are predefined
for any scalar type, ...
and that 4.5.2(10) says:
The membership tests IN and NOT IN are predefined for all types.
These definitions of what operators are defined for an integer type are not
restricted to PREDEFINED integer types, so such operators are also defined
for an implementationdefined unsigned integer type.
For the unary and binary adding operators, 4.5.3(1) and 4.5.4(1) say that
these operators "are predefined for any numeric type and have their
conventional meaning."
4.5.5(1) says:
The operators * and / are predefined for any integer and any
floating point type and have their conventional meaning; the
operators MOD and REM are predefined for any integer type. For
each of these operators, the operands and the result have the
same base type.
4.5.6(1) says:
The highest precedence unary operator ABS is predefined for any
numeric type.
4.5.6(1) means to say that ABS has its conventional meaning.
4.5.6(4) says:
The highest precedence EXPONENTIATING operator ** is predefined
for each integer type.
3.5.5(1) defines the basic operations of integer types, which includes
implementationdefined unsigned integer types. Therefore the basic
operations of an unsigned type include assignment, membership tests,
qualification, explicit conversion of values of other numeric types to the
unsigned type, and the implicit conversion of values of the type universal_
integer to the type, and certain attributes. The descriptions of the WIDTH,
POS, VAL, IMAGE, and VALUE attributes apply without change. The SUCC and
PRED attributes need additional explanation, and are discussed further below.
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 3
900707 BI WI
13.7.2(23) defines the representation attribute, ADDRESS, which applies to
all objects, including objects of implementationdefined unsigned integer
types. Similarly, 13.7.2(45) defines the representation attribute SIZE,
which applies to any implementationdefined unsigned integer type or subtype.
Since unsigned types are numeric types, 4.6(57) define explicit conversion
of values of any numeric type to any implementationdefined unsigned integer
type. Since unsigned types are integer types, 4.6(15) allows implicit
conversion of a value of the type universal_integer into any unsigned integer
type and of an operand of type universal_integer into any unsigned integer
type, if the implicit conversion is applied to "either a numeric literal, a
named number, or an attribute."
In short, the operators predefined for a userdefined integer type can also
be considered to be predefined for an implementationdefined unsigned integer
type, but they can have the "conventional meaning" for an unsigned type.
Therefore, it is possible to define the conventional meaning of these
operators in such a manner as to provide the semantics of modular arithmetic
for such types.
Finally, the abovementioned definitions do not preclude the declaration of
additional operations on implementationdefined integer types which are not
predefined for the predefined integer types. For example, an implementation
may define bitwise logical operations on unsigned integer types if they are
desired.
If an implementation chooses to provide an implementationdefined unsigned
integer type, it must also support the use of that type as a generic actual
parameter, i.e., an unsigned type matches either a generic formal type
defined by (<>) or one defined by RANGE <>, as required by 12.3.3. In
particular it must support instantiations of TEXT_IO for such a type.
Since unsigned integer types are allowed, a more detailed discussion of
support for the properties of implementationdefined unsigned integer types
which are requested by UI00012 is appropriate.
UI0012 states that an "implementationdefined unsigned integer type
definition defines an integer type whose set of values include exactly the
specified range, where the lower bound is zero and the upper bound is either
N N
2  1 or 2  2 for some positive integer N, which corresponds to the size
in bits of the underlying hardware type which will be used to represent it.
The base type of such a type is the type itself."
3.5(79) says:
For any scalar type T or for any subtype T of a scalar type, the
following attributes are defined:
T'FIRST Yields the lower bound of T. The value of this attribute
has the same type as T.
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 4
900707 BI WI
T'LAST Yields the upper bound of T. The value of this attribute
has the same type as T.
Unsigned types therefore have the FIRST and LAST attributes.
4.1.4(4) says:
In addition, an implementation may provide implementationdefined
attributes; their description must be given in Appendix F. The
attribute designator of any implementationdefined attribute must
not be the same as that of any languagedefined attribute.
Thus, it is possible to define implementationdefined attributes of unsigned
types. For instance one can have:
For every unsigned integer type or subtype T, the following
(implementationdefined) attribute is defined:
T'MODULUS Yields the modulus of the base type of T. The value of this
attribute is of the type universal_integer.
The value of T'MODULUS can be given by:
T'MODULUS = 2**T'BASE'SIZE (for 2's complement architectures)
or
T'MODULUS = 2**T'BASE'SIZE  1 (for 1's complement architectures)
The definitions of other attributes of unsigned types which are consistent
with the desired modular behavior can then be given:
For every implementationdefined unsigned integer type T:
T'BASE'FIRST = T'FIRST = 0
T'BASE'LAST = T'LAST = T'MODULUS  1
The conventional meaning of the binary adding operators + and  may be
defined by the following identities:
For any two values X and Y of an unsigned integer type T:
X + Y = (T'POS(X) + T'POS(Y)) mod T'MODULUS
X  Y = (T'POS(X)  T'POS(Y)) mod T'MODULUS (1)
Consistent with these equations, the expressions
T'SUCC(X) = X + 1
T'PRED(X) = X  1
must both evaluate to TRUE for any value X of an unsigned integer type
T. Then the definitions of the SUCC and PRED attributes in 3.5.5(89) must be
extended for unsigned integer types so that the following identities hold:
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 5
900707 BI WI
For any value X of an unsigned integer type T:
T'SUCC(X) = (T'POS(X) + 1) mod T'MODULUS
T'PRED(X) = (T'POS(X)  1) mod T'MODULUS
3.5.5(8) means to say:
The result is the value whose position number is one greater than
that of X (computed modulo T'MODULUS if T is an unsigned integer
type).
3.5.5(9) means to say:
The result is the value whose position number is one less than
that of X (computed modulo T'MODULUS if T is an unsigned integer
type).
The conventional meaning of the unary  operator may be defined in a manner
which is consistent with identity 1:
For any value X of an unsigned type T:
 X = ( T'POS(X)) mod T'MODULUS
The identity of 4.5.5(4) for integer division:
(A)/B = (A/B) = A/(B)
is not satisfied by implementationdefined unsigned integer types because the
unary minus operator for such types has a different meaning than that for
signed integer types.
3.5.5(16) says:
The operations of a subtype are the corresponding operations of
its base type except for the following: assignment, membership
tests, qualification, explicit type conversions, and the
attributes of the first group; the effects of each of these
operations depends on the subtype (assignments, membership tests,
qualifications, and conversions involve a subtype check;
attributes of the first group yield a characteristic of the
subtype).
This rule applies to subtypes of implementationdefined unsigned types as
well as to other integer types.
The note of 3.5.5(17) says:
For a subtype of a discrete type, the results delivered by the
attributes SUCC, PRED, VAL, and VALUE need not belong to the
subtype; similarly, the actual parameters of the attributes POS,
SUCC, PRED, and IMAGE need not belong to the subtype.
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 6
900707 BI WI
As a consequence, for any value X in subtype S of an unsigned integer type T,
although the values of S'SUCC(X) and S'PRED(X) are always in T, they are not
necessarily in S. In particular, although T'SUCC(T'LAST) = T'FIRST and T'
PRED(T'FIRST) = T'LAST, i.e., T'SUCC and T'PRED are cyclic in nature, S'
SUCC(S'LAST) is not identical to S'FIRST and S'PRED(S'FIRST) is not identical
to S'LAST, so that S'SUCC and S'PRED are not in general cyclic.
In addition, the first two identities given in the note apply only to the
predefined integer types or types implicitly derived from such types. For
unsigned types, due to their modular arithmetic properties, these identities
must be modified as follows:
For any value X of an unsigned integer type T:
T'POS(T'SUCC(X)) = (T'POS(X) + 1) mod T'MODULUS
T'POS(T'PRED(X)) = (T'POS(X)  1) mod T'MODULUS
Note that for a subtype S of an implementationdefined unsigned integer type
T, although T'LAST equals T'MODULUS  1, S'LAST is not, in general equal to
S'MODULUS  1, because S'LAST may be less than T'LAST.
The rules of 3.4 on derived types apply to implementationdefined unsigned
types without change.
In accordance with the recommendation of AI00387, operations on unsigned
integer types which cannot deliver a correct value may raise CONSTRAINT_
ERROR, rather than NUMERIC_ERROR.
4.10(5) says:
For the evaluation of an operation of a nonstatic universal
expression, an implementation is allowed to raise the exception
NUMERIC_ERROR only if the result of the operation is ... an
integer value greater than SYSTEM.MAX_INT or less than
SYSTEM.MIN_INT.
This means that evaluation of some nonstatic universal expressions may raise
NUMERIC_ERROR (rather than CONSTRAINT_ERROR (see AI00387)) at runtime even
though the result is within the range of an implementationdefined unsigned
integer type and could be implicitly converted to that type, because the
result is greater than SYSTEM.MAX_INT and the implementation does not support
the runtime computation of such values.
[On the other hand, since this AI is a binding interpretation and since it
would appear to be desirable in Ada 9X, it could require that implementations
provide broader support for the computation of nonstatic universal
expressions, as follows:
If an implementation chooses to provide any implementationdefined unsigned
integer types, it must also support the evaluation of operations of nonstatic
universal expressions as long as the result of each operation is not greater
than the maximum of the values of T'BASE'LAST and not less than the minimum
of the values of T'BASE'FIRST for all implemented integer types.]
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 7
900707 BI WI
 !appendix 900619
*****************************************************************************
!section 3.5.4(7) Robert Dewar/Paul Hilfinger 870216
!version 1983
!topic Unsigned arithmetic
!reference AI00402
There have been a number of requests regarding Ada's ability to support
unsigned arithmetic. A number of existing compilers have provided some kind
of facility for such support, but the various features provided are
significantly incompatible.
It has not been clear in the past that Ada satisfactorily permits the addition
of unsigned integer types (the primary problem being the requirement for
symmetric ranges). The intent of the current proposal is to clear the way for
the provision of satisfactory facilities in this area, with minimal
perturbation of the language.
PROPOSAL
3.5.4(7) sentence 3 shall be construed to allow the introduction of additional
implementation defined integer types in packages other than STANDARD. Such
types shall not be considered predefined integer types.
Note: As a consequence, such types are unavailable for the derivations of
3.5.4(46), are not constrained to have symmetric ranges, and can have values
outside the range SYSTEM.MIN_INT .. SYSTEM.MAX_INT.
DISCUSSION
As soon as asymmetrical types can be introduced, then unsigned integer types
can be defined and used without difficulty. There was discussion of the
desirability of such types during the language design, but there was
insufficient time to address a number of last minute objections. In
particular, if such types are permitted in STANDARD, then there can be
confusion as to which of several possible types are chosen for an anonymous
derivation, since the types are no longer strictly ordered. By specifying
that such types are not to be considered predefined, we believe that these
objections are overcome.
It is still desirable to attempt some suggested standardization of the exact
manner in which unsigned facilities are to be added to an implementation.
Issues to be addressed include:
Should arithmetic be modular or range checked?
Should logical operations such as AND/OR be permitted?
Should the operations be in SYSTEM or a separate package?
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 8
900707 BI WI
*****************************************************************************
!section 03.05.04 (07) Bryce Bardin 870615 8300974
!version 1983
!topic Unsigned arithmetic
!reference AI00402
[Draft] Implementation of Unsigned Integers in Ada
INTRODUCTION
It is suggested that the minimal goals for unsigned integers should include at
least:
1) providing an extended maximum nonnegative integer range which fully
exploits the available hardware (and which allows full range address
arithmetic when appropriate),
2) providing straightforward and efficientlyimplementable logical operations
(including shifts, rotates, and masks) on all bits of unsigned types,
3) providing numeric literals in arbitrary bases (so that representations
appropriate to a given architecture may be chosen for bitlevel
operations), and
4) providing efficient support for modular arithmetic of arbitrary range
(which allows checksums, hash functions, and pseudorandom number
generators which generate all possible bit patterns in closed cycles
to be cleanly written in Ada).
Note that the goals stated above imply that both rangechecked and modular
arithmetic ought to be supported for unsigned integers.
Exemption of the unsigned integer types from the requirement to have symmetric
ranges solves the main problem with the functionality of the language. As
suggested by Robert Dewar and Paul Hilfinger, sentence 3 of LRM section
3.5.4(7) may be interpreted to allow the introduction of implementationdefined
integer types in package SYSTEM or elsewhere. Such types are not predefined
integer types and thus may not be used by the implementation in the derivations
of 3.5.4(46), although other types may be derived from them and subtypes may
be defined based on them.
The view taken here is that unsigned integer types are integer types in every
other respect than not participating in implicit derivations. In particular,
they have as a subset of their predefined operations the same operations
provided for the predefined integer types, although the meaning of those
operations are different. A primary of a nonstatic universal expression can
be implicitly converted to an unsigned integer type. In addition, they match
generic formal discrete and integer types. (E.g., TEXT_IO.INTEGER_IO can be
instantiated for these types.) Finally, it is proposed that the declaration
of subtypes of unsigned types and types derived from unsigned types will
behave the same as for predefined and userdefined integer types. In
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 9
900707 BI WI
particular, it is intended that LRM 3.5.5(12) apply after modification by
replacing "predefined" by "implementationdefined" at its second occurence:
"..., the predefined operators of an integer type deliver results whose
range is defined by the parent [implementationdefined] type; such a result
need not belong to the declared subtype, in which case an attempt to assign
the result to a variable of the integer subtype raises the exception
CONSTRAINT_ERROR."
The additional operations on these types include bitwise logical operators.
The following is a strawman proposal (draft of a draft) to meet the goals
stated above. Note that the choice between UNSIGNED and CARDINAL in the names
below is arbitrary, although there is some precedent from Modula2 for the
choice made here. Alternative names which might be considered as a substitute
for CARDINAL are MODULAR and CYCLIC.
In what follows, asides and comments are enclosed in square brackets ([]).
[PROPOSAL DELETED SINCE IT HAS BEEN REPLACE BY A LATER VERSION]
*****************************************************************************
!section 03.05.04 (07) 880928 Dave Emery/Mitre 8301021
!version 1983
!topic Unsigned Arithmetic
!reference AI0597, 8300974
Bryce lists the following goals for unsigned numbers in Ada: (my summary)
1. Nonnegative integer range that exploits available hardware
(and that supports full range address arithmetic)
2. Numeric literals in arbitrary bases, to the full range of
the unsigned type.
3. Provide efficient support for modular arithmetic.
4. Provide straightforward and efficient logical operators
(including shifts, rotates and masks) on bits of unsigned types.
I fully support the first three goals, but I cannot support the
fourth. Unsigned integers are integers, and there is no arithmetic
definition of shifts, rotates and masks on integers (signed or
unsigned). On the other hand, I think it is probably necessary to
support conversion between integers (unsigned and signed) and some
representation of bit arrays on which shifts, rotates and masks can be
supported. (this conversion should be more than Unchecked_Conversion,
because there is no guarantee that U.C. does what you want.) I guess
there needs to be a function that converts between integer types and
appropriately sized bitmaps, something like:
type bitmap is array (positive range <>) of boolean;
pragma pack (bitmap);  NOTE: this should work (i.e
 bitmap(1..32)'size should be 32)
function to_bitmap (i : some_integer_type)
return bitmap;  raises constraint_error if i'size >
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 10
900707 BI WI
 bitmap'size. does something TBD
 (maybe zero fill) if i'size < bitmap'size
function to_integer (bitmap_32)
return some_integer_type;  can raise constraint_error if
 conversion would result in a
 value out of the range of
 some_integer
 define appropriate shift, rotate and mask operations on
 the bitmap type
There is no reason to restrict this conversion to unsigned integers.
I think I like Bryce's distinction between UNSIGNED_INTEGER and
CARDINAL_INTEGER. My feeling is that these should be added to
Standard, and that implementations should provide types like
UNSIGNED_32 and CARDINAL_32, with efficient implementations of
appropriate operations, in package SYSTEM. Such types are clearly
systemdependent.
I guess the goals I'd set for unsigneds include the first 3 goals
provided by Bryce, plus a fourth goal:
4. (emery's goal) Types derived from unsigned types
behave correctly and reasonably.
Here's a place where this would be important: Steve Litvintchouk has
been looking at the Joint Frequency Hopping Specification. It has
lots of bitpacked fields, like X is a 3 bit integer range 0..7. So
I'd like to be able to do the following:
type X is new unsigned_integer range 0..7;
for X'size use 3;
and get all appropriate operations, including (in this case) modular
arithmetic.
dave emery
emery@mitrebedford.arpa
*****************************************************************************
!section 03.05.04 (07) Bryce Bardin 900410
!version 1983
!topic Unsigned Arithmetic
!reference AI00402
The Uniformity Rapporteur Group of ISO WG9 has approved a Uniformity Issue,
designated UI0012, which addresses the issue of the uniform implementation
of unsigned arithmetic in Ada. The ARG is hereby requested to complete
AI00597 in support of the implementation of unsigned integers in accordance
with the recommendation of UI0012. The current text of UI0012 follows:
UI  0012 Unsigned Arithmetic 0012/5
Editor : Bryce Bardin
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 11
900707 BI WI
Status : Agreed URG  February 1990
Agreed in principle  October 1989
Await revision  October 1988
Section : RM 3.5.4(7)
AI references : AI00387, AI00402, AI00597
Issue :
The RM does not provide for implementation of unsigned integer types.
Although many machines have unsigned arithmetic instructions available, the
semantics of Ada currently prevent the efficient calculation of checksums,
hash codes, pseudorandom numbers, and full range address arithmetic using
those instructions.
Recommendation
The URG finds that uniform implementation of unsigned integer types in Ada
is both useful and necessary. All implementations of Ada should provide
support for every unsigned type for which natural architectural support is
(directly) available in the hardware, in accord with the definition which is
given in the discussion below. In particular, it is strongly recommended
that implementations for machines which can do so efficiently should support
8, 16, and 32bit unsigned types.
The Ada Rapporteur Group is requested to complete AI00597 in support of
the implementation of the package given here below.
Discussion
The need for unsigned integers in Ada is clear; many users have applications
(which are trivial to implement in many other languages) that cannot presently
be written directly in Ada. In response to their customers' expressed
desires, a number of vendors have provided some form of support for unsigned
integers which conforms to the current standard, but they are only partially
successful in providing the desired functionality and their approaches are
quite diverse. As a consequence, a uniform approach which addresses the major
uses of unsigned numbers should be recommended by the URG.
The language issues raised by the recommended approach should be resolved
by the ARG.
The goals for unsigned integer types include:
1. providing an extended maximum nonnegative integer range which fully
exploits the available hardware (and which allows full range address
arithmetic when appropriate),
2. providing straightforward and efficientlyimplementable logical
operations (including shifts, rotates, and masks) on all bits of
unsigned types,
3. providing numeric literals in arbitrary bases (so that representations
appropriate to a given architecture may be chosen for bitlevel
operations), and
4. providing efficient support for modular arithmetic of arbitrary range
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 12
900707 BI WI
(which allows checksums, hash functions, and pseudorandom number
generators which generate all possible bit patterns in closed cycles
to be cleanly written in Ada).
The principal language issue is how unsigned types can be provided.
Currently, there are two relevant AI's: AI00402 and AI00597. AI00402
simply affirms (as a ramification) that unsigned integer types are not
predefined. AI00597 is a work item that will directly address how unsigned
integers can be provided. The ARG has decided to take no action on this AI
until the URG has determined that AI00597 is needed to provide an
appropriate interpretation of the standard, i.e., one that is required to
support a "useful and necessary" implementation of unsigned integers.
Technically, the main problem is RM 3.5.4(7), which says in part:
The range of each of these [predefined integer] types must be symmetric
about zero, excepting an extra negative value which may exist in some
implementations.
It has been suggested that this sentence might be interpreted to allow the
introduction of implementationdefined integer types. Such types would not
be predefined integer types and thus would not be used by the implementation
in the derivations of 3.5.4(46), although other types might be derived from
them and subtypes might be defined based on them. The standard package for
unsigned integer types which is defined here takes advantage of this
interpretation.
** DEFINITION OF THE UNSIGNED INTEGER TYPES PACKAGE **
Overview
The unsigned integer package defined here takes the view that unsigned integer
types are similar to predefined integer types in every other respect than not
participating in implicit derivations and in that their predefined operations
have different semantics in some cases because their arithmetic is modular.
In particular, they have as a subset of their predefined operations the same
operations provided for the predefined integer types. A primary of a
universal expression can be implicitly converted to an unsigned integer type,
even if it is not static. In addition, unsigned integer types match generic
formal discrete and integer types. (E.g., TEXT_IO.INTEGER_IO can be
instantiated for these types.)
Finally, the declaration of subtypes of unsigned types and types derived from
unsigned types behave the same as for predefined and userdefined integer
types. In particular, the note in 3.5.4(12) applies after modification by
replacing the word "predefined" by "implementationdefined" at its second
occurence:
"..., the predefined operators of an integer type deliver results whose
range is defined by the parent [implementationdefined] type; such a
result need not belong to the declared subtype, in which case an attempt
to assign the result to a variable of the integer subtype raises the
exception CONSTRAINT_ERROR."
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 13
900707 BI WI
In accordance with the recommendation of AI00387, the operations on unsigned
types always raise CONSTRAINT_ERROR, rather than NUMERIC_ERROR when they
cannot deliver the correct result.
In what follows, interpolated comments are enclosed in square brackets ([ ]).
In this document, italics are indicated using braces ({ }). The balance of
the definition is given in the style of RM sections 3.5.4, 3.5.5, and Annex C.
General Requirements
An implementationdefined unsigned integer type definition defines an integer
type whose set of values include exactly the specified range, where the lower
bound is zero and the upper bound is either 2**n  1 or 2**n  2 for some
positive integer n, which corresponds to the size in bits of the underlying
hardware type which will be used to represent it. The base type of such a
type is the type itself.
Operations on implementationdefined unsigned integer types include all of the
operations on integer types plus the predefined logical operators and the
highest precedence operator "not", both arithmetic and logical shifts, and
rotate. The arithmetic operators have their conventional meaning, but the
arithmetic is modular rather than rangechecked as it is for the predefined
integer types. The logical operators have their conventional meaning as
applied bit by bit to unsigned integers viewed as arrays of 1bit numeric
values which represent boolean values (with 0 corresponding to FALSE and 1
corresponding to TRUE). Based integer literals are available for defining
values in conventional formats, e.g., hexadecimal.
Every implementation of Ada should provide at least one unsigned integer type
with modular arithmetic named UNSIGNED_n, where n represents an integer value
equal to both UNSIGNED_n'SIZE and INTEGER'SIZE. An implementation may also
have other implementationdefined unsigned integer types using modular
arithmetic with names of the same form which have different sizes. The
arithmetic operations on all unsigned integer types are performed modulo 2**n
(for 2's complement machines) or modulo 2**n  1 (for 1's complement
machines).
Attributes of Unsigned Types
[These attributes facilitate the usage of unsigned types in generic units.]
In addition to the attributes of discrete types described in RM 3.5.5, two
(implementationdefined) attributes are needed to support unsigned types:
For every unsigned integer type or subtype T, the following
(implementationdefined) attribute is defined:
T'MODULUS Yields the modulus of the base type of T. The value of
this attribute is of the type {universal_integer}.
For every discrete type or subtype T, the following
(implementationdefined) attribute is defined:
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 14
900707 BI WI
T'UNSIGNED Yields the value TRUE if T is an unsigned integer type;
yields the value FALSE otherwise. The value of this
attribute is of the predefined type BOOLEAN.
Properties of Unsigned Types
For every unsigned integer type T certain identities hold.
Since the type T is unsigned and its base type is the type itself and its
arithmetic is modular:
T'UNSIGNED = TRUE
T'BASE'SIZE = T'SIZE
T'MODULUS = 2**T'SIZE (for 2's complement architectures)
or
T'MODULUS = 2**T'SIZE  1 (for 1's complement architectures)
T'BASE'FIRST = T'FIRST = 0
T'BASE'LAST = T'LAST = T'MODULUS  1
and
T'MODULUS = T'POS(T'LAST) + 1
T'PRED(T'FIRST) = T'LAST
T'SUCC(T'LAST) = T'FIRST
Then for any two values X and Y of type T:
X  Y = (T'POS(X)  T'POS(Y)) mod T'MODULUS
X + Y = (T'POS(X) + T'POS(Y)) mod T'MODULUS
T'PRED(X) = (T'POS(X)  1) mod T'MODULUS
T'SUCC(X) = (T'POS(X) + 1) mod T'MODULUS
so that
T'PRED(X) = X  1
and
T'SUCC(X) = X + 1
In contrast to symmetric integer types, for unsigned types
T'POS(T'PRED(X)) = (T'POS(X)  1) mod T'MODULUS
and
T'POS(T'SUCC(X)) = (T'POS(X) + 1) mod T'MODULUS
As with symmetric integer types, for unsigned types
T'VAL(T'POS(X)) = X
and
T'POS(T'VAL(N)) = N
(in the absence of an exception)
The multiplying operators "rem" and "mod" are functionally equivalent
when applied to unsigned integers; they return identical values for
identical arguments.
The logical operators "and", "or", and "xor", plus the highest precedence
operator "not" never raise CONSTRAINT_ERROR, since all possible nbit
patterns are valid values of an nbit implementationdefined unsigned type.
(This is not, in general, true for subtypes of such types and types derived
from such types which impose range constraints.)
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 15
900707 BI WI
Package Specification
[The explicit declaration of unsigned types cannot be given in Ada because
their base types are not implicitly derived from predefined integer types as
required by 3.5.4(46). Because of that, their declarations are given here
in the style of package STANDARD (see Annex C).]
The following outlines the specification of the package UNSIGNED_NUMBERS,
containing all implementationdefined unsigned integer type declarations.
The corresponding package body is implementationdefined and is not shown.
The operators that are predefined for the types declared in the package
UNSIGNED_NUMBERS are given in comments since they are implicitly declared.
Italics are used for pseudonames of anonymous types (such as
{universal_integer}) and for undefined information (such as
{implementation_defined} and {any_fixed_point_type}).
Note: When reading the description of ARITHMETIC_SHIFT, remember that the
unsigned types are nonnegative (i.e., have no sign bit), which leads to zero
filling of the most significant bit during a right shift.
package UNSIGNED_NUMBERS is
 An implementation may provide several implementationdefined unsigned
 integer types. It is recommended that the names of such types start
 with UNSIGNED and end in an integer value representing the size of the
 type as in UNSIGNED_8, UNSIGNED_16, or UNSIGNED_32.
 The following illustrates the form of the declarations for each such
 type:
type UNSIGNED_n is {implementation_defined};
for UNSIGNED_n'SIZE use n;
 The predefined operators for this type are as follows:
 function "=" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function "/=" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function "<" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function "<=" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function ">" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function ">=" (LEFT, RIGHT : UNSIGNED_n) return BOOLEAN;
 function "+" (RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "" (RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "abs" (RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "+" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "*" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "/" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "rem" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 16
900707 BI WI
 function "mod" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "**" (LEFT : UNSIGNED_n;
 RIGHT : INTEGER) return UNSIGNED_n;
 function "and" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "or" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "xor" (LEFT, RIGHT : UNSIGNED_n) return UNSIGNED_n;
 function "not" (LEFT : UNSIGNED_n) return UNSIGNED_n;
[Note: The following three functions, ARITHMETIC_SHIFT, LOGICAL_SHIFT, and
ROTATE, are valid for every possible value of BITS.]
 function ARITHMETIC_SHIFT (ITEM : UNSIGNED_n;
BITS : INTEGER) return UNSIGNED_n;
 If BITS >= 0 or BITS < 0, returns ITEM left or right arithmetically
 shifted (with zero fill) by abs(BITS) bits, respectively.
 Raises CONSTRAINT_ERROR if a bit would be shifted off the left end.
 function LOGICAL_SHIFT (ITEM : UNSIGNED_n;
BITS : INTEGER) return UNSIGNED_n;
 If BITS >= 0 or BITS < 0, returns ITEM left or right logically shifted
 (end off) by abs(BITS) bits, respectively.
 function ROTATE (ITEM : UNSIGNED_n; BITS : INTEGER) return UNSIGNED_n;
 If BITS >= 0 or BITS < 0, returns ITEM left or right rotated (end
 around) by abs(BITS) mod UNSIGNED'SIZE bits, respectively.
[The following procedure, ADD_AND_CARRY, is needed to perform checksums which
add the carry bit into the sum.]
 procedure ADD_AND_CARRY (SUM : in out UNSIGNED_n;
AUGEND : in UNSIGNED_n;
CARRY : in out BOOLEAN);
 Adds AUGEND to SUM and then increments SUM by one if CARRY is TRUE on
 input. Sets CARRY to TRUE on output if the sum overflowed in either
 of the additions, else FALSE.
[The following two functions, REM_OF_SUM and REM_OF_PRODUCT, are needed to
allow the construction of types derived from UNSIGNED_n, but with smaller
ranges, having the desired semantics. One possible package for this purpose
is discussed below.]
 function REM_OF_SUM (ADDEND,
 AUGEND,
 DIVISOR : UNSIGNED_n) return UNSIGNED_n;
 Returns (UNSIGNED_n'POS(ADDEND) + UNSIGNED_n'POS(AUGEND)) rem
 UNSIGNED_n'POS(DIVISOR)
 function REM_OF_PRODUCT (MULTIPLIER,
 MULTIPLICAND,
 DIVISOR : UNSIGNED_n) return UNSIGNED_n;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 17
900707 BI WI
 Returns (UNSIGNED_n'POS(MULTIPLIER) * UNSIGNED_n'POS(MULTIPLICAND)) rem
 UNSIGNED_n'POS(DIVISOR)
[The following pragma is included to emphasize the intent that implementations
of unsigned integer types should be implemented efficiently using the
underlying support for unsigned types provided by the architecture.]
 The following pragma Inline should be obeyed by all implementations
 except when an outofline call would be more efficient:
 pragma Inline ("=", "/=", "<", "<=", ">", ">=", "+", "", "*", "/",
 "**", "abs", "rem", "mod", "and", "or", "xor", "not",
 ARITHMETIC_SHIFT, LOGICAL_SHIFT, ROTATE,
 ADD_AND_CARRY, REM_OF_SUM, REM_OF_PRODUCT);
 The following type facilitates the declaration of unsigned types of
 maximum range:
type LARGEST_UNSIGNED_TYPE is
new {implementation_defined_unsigned_type};
[In analogy with:
type T is range SYSTEM.MIN_INT .. SYSTEM.MAX_INT;
for symmetric integer types, unsigned integer types of maximum range can be
declared (in portable syntax) by:
type T is new LARGEST_UNSIGNED_TYPE;]
end UNSIGNED_NUMBERS;
Operational Semantics
The following example package demonstrates the semantics desired for the
implementationdependent unsigned types defined in the package
UNSIGNED_NUMBERS.
 Unsigned_Numbers demonstrates (most of) the desired properties of
 implementationdefined unsigned numbers having modular arithmetic.
 In particular, it shows the behavior required for the arithmetic,
 relational, and logical operations on type Unsigned. In addition,
 it provides analogs for the 'Pred and 'Succ attributes.
 It was considered unnecessary to simulate the other attributes and
 the Shift and Rotate operations since they are expected to reflect the
 usual properties of the underlying hardware operations.
 N. B.: This simulation is also not realistic with regard to the
 representation of the type Unsigned.
generic
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 18
900707 BI WI
type Basis is range <>;  Any predefined or userdefined integer
 type or subtype
Modulus : in Basis;  Any positive value less than
 Basis'Last/2
type Extended is range <>;  Any integer type with a range such that
 Extended'Last >= (Modulus  1)**2
type Logical is range <>;  Any integer type with a range at least
 0 .. Modulus  1 for which bitlevel
 logical operations are available.
with function "and" (Left, Right : Logical) return Logical is <>;
with function "or" (Left, Right : Logical) return Logical is <>;
with function "xor" (Left, Right : Logical) return Logical is <>;
with function "not" (Right : Logical) return Logical is <>;
package Unsigned_Numbers is
type Unsigned is new Basis range 0 .. Modulus  1;
 Note:
 Unsigned'First = 0
 Unsigned'Last = Modulus  1
 Unsigned'Base'First = Unsigned'First = 0
 (Not true in this simulation)
 Unsigned'Base'Last = Unsigned'Last
 (Not true in this simulation)
 Unsigned'Pred(Unsigned'First) = Unsigned'Last
 (Not true in this simulation)
 Unsigned'Succ(Unsigned'Last) = Unsigned'First
 (Not true in this simulation)
 The predefined operators for this type are as follows:
 function "=" (Left, Right : Unsigned) return Boolean;
 function "/=" (Left, Right : Unsigned) return Boolean;
 function "<" (Left, Right : Unsigned) return Boolean;
 function "<=" (Left, Right : Unsigned) return Boolean;
 function ">" (Left, Right : Unsigned) return Boolean;
 function ">=" (Left, Right : Unsigned) return Boolean;
 function "+" (Right : Unsigned) return Unsigned;
function "" (Right : Unsigned) return Unsigned;
 function "abs" (Right : Unsigned) return Unsigned;
function "+" (Left, Right : Unsigned) return Unsigned;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 19
900707 BI WI
function "" (Left, Right : Unsigned) return Unsigned;
function "*" (Left, Right : Unsigned) return Unsigned;
 function "/" (Left, Right : Unsigned) return Unsigned;
 function "rem" (Left, Right : Unsigned) return Unsigned;
 function "mod" (Left, Right : Unsigned) return Unsigned;
function "**" (Left : Unsigned; Right : Integer)
return Unsigned;
function "and" (Left, Right : Unsigned) return Unsigned;
function "or" (Left, Right : Unsigned) return Unsigned;
function "xor" (Left, Right : Unsigned) return Unsigned;
function "not" (Right : Unsigned) return Unsigned;
 The following functions are cyclic substitutes for the
 attributes Unsigned'Pred and Unsigned'Succ, respectively.
function Pred (Right : Unsigned) return Unsigned;
function Succ (Right : Unsigned) return Unsigned;
 The following functions are not implemented:
 function Arithmetic_Shift (Item : Unsigned;
 Bits : Integer) return Unsigned;
 function Logical_Shift (Item : Unsigned;
 Bits : Integer) return Unsigned;
 function Rotate (Item : Unsigned;
 Bits : Integer) return Unsigned;
function Rem_of_Sum (Addend,
Augend,
Divisor : Unsigned) return Unsigned;
function Rem_of_Product (Multiplier,
Multiplicand,
Divisor : Unsigned) return Unsigned;
end Unsigned_Numbers;
package body Unsigned_Numbers is
function "" (Right : Unsigned) return Unsigned is
begin
if Modulus = 1 then
return 0;
else
return (Unsigned'Last  Right) + 1;
end if;
end "";
function "+" (Left, Right : Unsigned) return Unsigned is
begin
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 20
900707 BI WI
return Unsigned((Extended(Left) + Extended(Right))
mod Extended(Modulus));
end "+";
function "" (Left, Right : Unsigned) return Unsigned is
begin
if Right > Left then
return ((Unsigned'Last  Right) + Left) + 1;
else
return Unsigned(Basis(Left)  Basis(Right));
end if;
end "";
function "*" (Left, Right : Unsigned) return Unsigned is
Product : Unsigned;
begin
return Unsigned((Extended(Left) * Extended(Right))
mod Extended(Modulus));
end "*";
function "**" (Left : Unsigned;
Right : Integer) return Unsigned is
T : Unsigned;
begin
if Modulus = 1 then
return 0;
else
T := 1;
for N in 1 .. Right loop
T := T * Left;
end loop;
return T;
end if;
end "**";
function "and" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Logical(Left) and Logical(Right));
end "and";
function "or" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Logical(Left) or Logical(Right));
end "or";
function "xor" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Logical(Left) xor Logical(Right));
end "xor";
package Make is
function Mask return Logical;  Mask should be a static value for
 efficiency, but make it a function in
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 21
900707 BI WI
 the simulation for generality.
end Make;
package body Make is
Mask_Constant : Logical;
function Mask return Logical is
begin
return Mask_Constant;
end Mask;
begin
Mask_Constant := 0;
for C in Unsigned loop
Mask_Constant := Mask_Constant or Logical(C);
end loop;
end Make;
function "not" (Right : Unsigned) return Unsigned is
begin
return Unsigned(not Logical(Right) and Make.Mask);
end "not";
function Pred (Right : Unsigned) return Unsigned is
begin
if Right = 0 then
return Unsigned(Modulus  1);
else
return Unsigned(Basis'Pred(Basis(Right)));
end if;
end Pred;
function Succ (Right : Unsigned) return Unsigned is
begin
if Right = Unsigned(Modulus  1) then
return 0;
else
return Unsigned(Basis'Succ(Basis(Right)));
end if;
end Succ;
function Rem_of_Sum (Addend, Augend, Divisor : Unsigned)
return Unsigned is
begin
return Unsigned(
(Extended(Addend) + Extended(Augend))rem Extended(Divisor));
end Rem_of_Sum;
function Rem_of_Product (Multiplier,
Multiplicand,
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 22
900707 BI WI
Divisor : Unsigned) return Unsigned is
begin
return Unsigned(
(Extended(Multiplier) * Extended(Multiplicand)) rem
Extended(Divisor));
end Rem_of_Product;
begin
if Extended'Last < Extended(Basis'Last) ** 2 then
raise Program_Error;
end if;
end Unsigned_Numbers;
Unsigned Types of Arbitrary Range
The following package can be used to provide modular unsigned types of
arbitrary range by derivation from the unsigned types in package
UNSIGNED_NUMBERS. It is directly implementable by any user.
generic
type Basis is range <>;
Modulus : in Basis;
with function Rem_of_Sum (Addend, Augend, Divisor : Basis)
return Basis is <>;
with function Rem_of_Product (Multiplier,
Multiplicand,
Divisor : Basis) return Basis is <>;
with function "and" (Left, Right : Basis) return Basis is <>;
with function "or" (Left, Right : Basis) return Basis is <>;
with function "xor" (Left, Right : Basis) return Basis is <>;
with function "not" (Right : Basis) return Basis is <>;
with function Pred (Item : Basis) return Basis is Basis'Pred;
with function Succ (Item : Basis) return Basis is Basis'Succ;
package Derived_Unsigned is
type Unsigned is new Basis range 0 .. Modulus  1;
 function "<" (Left, Right : Unsigned) return Boolean;
 function "<=" (Left, Right : Unsigned) return Boolean;
 function ">" (Left, Right : Unsigned) return Boolean;
 function ">=" (Left, Right : Unsigned) return Boolean;
 function "+" (Right : Unsigned) return Unsigned;
function "" (Right : Unsigned) return Unsigned;
 function "abs" (Right : Unsigned) return Unsigned;
function "+" (Left, Right : Unsigned) return Unsigned;
function "" (Left, Right : Unsigned) return Unsigned;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 23
900707 BI WI
function "*" (Left, Right : Unsigned) return Unsigned;
 function "/" (Left, Right : Unsigned) return Unsigned;
 function "rem" (Left, Right : Unsigned) return Unsigned;
 function "mod" (Left, Right : Unsigned) return Unsigned;
function "**" (Left : Unsigned; Right : Integer)
return Unsigned;
function "and" (Left, Right : Unsigned) return Unsigned;
function "or" (Left, Right : Unsigned) return Unsigned;
function "xor" (Left, Right : Unsigned) return Unsigned;
function "not" (Right : Unsigned) return Unsigned;
function Pred (Item : Unsigned) return Unsigned;
function Succ (Item : Unsigned) return Unsigned;
end Derived_Unsigned;
package body Derived_Unsigned is
function "" (Right : Unsigned) return Unsigned is
begin
if Modulus = 1 then
return 0;
else
return (Unsigned'Last  Right) + 1;
end if;
end "";
function "+" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Rem_of_Sum(Basis(Left), Basis(Right), Modulus));
end "+";
function "" (Left, Right : Unsigned) return Unsigned is
begin
if Right > Left then
return ((Unsigned'Last  Right) + Left) + 1;
else
return Unsigned(Basis(Left)  Basis(Right));
end if;
end "";
function "*" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Rem_of_Product(Basis(Left), Basis(Right), Modulus));
end "*";
function "**" (Left : Unsigned; Right : Integer) return Unsigned is
Temp : Unsigned;
begin
if Modulus = 1 then
return 0;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 24
900707 BI WI
else
Temp := 1;
for N in 1 .. Right loop
Temp := Temp * Left;
end loop;
return Temp;
end if;
end "**";
function "and" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Basis(Left) and Basis(Right));
end "and";
function "or" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Basis(Left) or Basis(Right));
end "or";
function "xor" (Left, Right : Unsigned) return Unsigned is
begin
return Unsigned(Basis(Left) xor Basis(Right));
end "xor";
package Make is
function Mask return Basis;
end Make;
package body Make is
Mask_Constant : Basis;
function Mask return Basis is
begin
return Mask_Constant;
end Mask;
begin
Mask_Constant := 0;
for C in Unsigned loop
Mask_Constant := Mask_Constant or Basis(C);
end loop;
end Make;
function "not" (Right : Unsigned) return Unsigned is
begin
return Unsigned(not Basis(Right) and Make.Mask);
end "not";
function Pred (Item : Unsigned) return Unsigned is
begin
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 25
900707 BI WI
if Item = 0 then
return Unsigned'Last;
else
return Unsigned(Pred(Basis(Item)));
end if;
end Pred;
function Succ (Item : Unsigned) return Unsigned is
begin
if Item = Unsigned'Last then
return 0;
else
return Unsigned(Succ(Basis(Item)));
end if;
end Succ;
end Derived_Unsigned;
Examples of the Behavior of Unsigned Types
The following are examples of the desired behavior of modular unsigned types
(the base 2 values assume 2's complement representation):

The modulus is 3
+ 0 = 0 (+ 2#0# = 2#0#)
+ 1 = 1 (+ 2#1# = 2#1#)
+ 2 = 2 (+ 2#10# = 2#10#)
 0 = 0 ( 2#0# = 2#0#)
 1 = 2 ( 2#1# = 2#10#)
 2 = 1 ( 2#10# = 2#1#)
0 + 0 = 0 (2#0# + 2#0# = 2#0#)
. . .
2 + 2 = 1 (2#10# + 2#10# = 2#1#)
0  0 = 0 (2#0#  2#0# = 2#0#)
. . .
2  2 = 0 (2#10#  2#10# = 2#0#)
0 * 0 = 0 (2#0# * 2#0# = 2#0#)
. . .
2 * 2 = 1 (2#10# * 2#10# = 2#1#)
0 / 0 = Constraint_Error
0 / 1 = 0 (2#0# / 2#1# = 2#0#)
0 / 2 = 0 (2#0# / 2#10# = 2#0#)
1 / 0 = Constraint_Error
1 / 1 = 1 (2#1# / 2#1# = 2#1#)
1 / 2 = 0 (2#1# / 2#10# = 2#0#)
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 26
900707 BI WI
2 / 0 = Constraint_Error
2 / 1 = 2 (2#10# / 2#1# = 2#10#)
2 / 2 = 1 (2#10# / 2#10# = 2#1#)
0 rem 0 = Constraint_Error
0 rem 1 = 0 (2#0# rem 2#1# = 2#0#)
0 rem 2 = 0 (2#0# rem 2#10# = 2#0#)
1 rem 0 = Constraint_Error
1 rem 1 = 0 (2#1# rem 2#1# = 2#0#)
1 rem 2 = 1 (2#1# rem 2#10# = 2#1#)
2 rem 0 = Constraint_Error
2 rem 1 = 0 (2#10# rem 2#1# = 2#0#)
2 rem 2 = 0 (2#10# rem 2#10# = 2#0#)
0 mod 0 = Constraint_Error
0 mod 1 = 0 (2#0# mod 2#1# = 2#0#)
0 mod 2 = 0 (2#0# mod 2#10# = 2#0#)
1 mod 0 = Constraint_Error
1 mod 1 = 0 (2#1# mod 2#1# = 2#0#)
1 mod 2 = 1 (2#1# mod 2#10# = 2#1#)
2 mod 0 = Constraint_Error
2 mod 1 = 0 (2#10# mod 2#1# = 2#0#)
2 mod 2 = 0 (2#10# mod 2#10# = 2#0#)
0 ** 0 = 1 (2#0# ** 2#0# = 2#1#)
. . .
2 ** 2 = 1 (2#10# ** 2#10# = 2#1#)
0 and 0 = 0 (2#0# and 2#0# = 2#0#)
. . .
2 and 2 = 2 (2#10# and 2#10# = 2#10#)
0 or 0 = 0 (2#0# or 2#0# = 2#0#)
. . .
1 or 1 = 1 (2#1# or 2#1# = 2#1#)
1 or 2 = Constraint_Error
2 or 0 = 2 (2#10# or 2#0# = 2#10#)
2 or 1 = Constraint_Error
2 or 2 = 2 (2#10# or 2#10# = 2#10#)
0 xor 0 = 0 (2#0# xor 2#0# = 2#0#)
. . .
1 xor 1 = 0 (2#1# xor 2#1# = 2#0#)
1 xor 2 = Constraint_Error
2 xor 0 = 2 (2#10# xor 2#0# = 2#10#)
2 xor 1 = Constraint_Error
2 xor 2 = 0 (2#10# xor 2#10# = 2#0#)
not 0 = Constraint_Error
not 1 = 2 (not 2#1# = 2#10#)
not 2 = 1 (not 2#10# = 2#1#)
Pred(0) = 2 (Pred(2#0#) = 2#10#)
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 27
900707 BI WI
Pred(1) = 0 (Pred(2#1#) = 2#0#)
Pred(2) = 1 (Pred(2#10#) = 2#1#)
Succ(0) = 1 (Succ(2#0#) = 2#1#)
Succ(1) = 2 (Succ(2#1#) = 2#10#)
Succ(2) = 0 (Succ(2#10#) = 2#0#)

The modulus is 4
+ 0 = 0 (+ 2#0# = 2#0#)
+ 1 = 1 (+ 2#1# = 2#1#)
+ 2 = 2 (+ 2#10# = 2#10#)
+ 3 = 3 (+ 2#11# = 2#11#)
 0 = 0 ( 2#0# = 2#0#)
 1 = 3 ( 2#1# = 2#11#)
 2 = 2 ( 2#10# = 2#10#)
 3 = 1 ( 2#11# = 2#1#)
0 + 0 = 0 (2#0# + 2#0# = 2#0#)
. . .
3 + 3 = 2 (2#11# + 2#11# = 2#10#)
0  0 = 0 (2#0#  2#0# = 2#0#)
. . .
3  3 = 0 (2#11#  2#11# = 2#0#)
0 * 0 = 0 (2#0# * 2#0# = 2#0#)
. . .
3 * 3 = 1 (2#11# * 2#11# = 2#1#)
0 / 0 = Constraint_Error
0 / 1 = 0 (2#0# / 2#1# = 2#0#)
0 / 2 = 0 (2#0# / 2#10# = 2#0#)
0 / 3 = 0 (2#0# / 2#11# = 2#0#)
1 / 0 = Constraint_Error
1 / 1 = 1 (2#1# / 2#1# = 2#1#)
1 / 2 = 0 (2#1# / 2#10# = 2#0#)
1 / 3 = 0 (2#1# / 2#11# = 2#0#)
2 / 0 = Constraint_Error
2 / 1 = 2 (2#10# / 2#1# = 2#10#)
2 / 2 = 1 (2#10# / 2#10# = 2#1#)
2 / 3 = 0 (2#10# / 2#11# = 2#0#)
3 / 0 = Constraint_Error
3 / 1 = 3 (2#11# / 2#1# = 2#11#)
3 / 2 = 1 (2#11# / 2#10# = 2#1#)
3 / 3 = 1 (2#11# / 2#11# = 2#1#)
0 rem 0 = Constraint_Error
0 rem 1 = 0 (2#0# rem 2#1# = 2#0#)
0 rem 2 = 0 (2#0# rem 2#10# = 2#0#)
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 28
900707 BI WI
0 rem 3 = 0 (2#0# rem 2#11# = 2#0#)
1 rem 0 = Constraint_Error
1 rem 1 = 0 (2#1# rem 2#1# = 2#0#)
1 rem 2 = 1 (2#1# rem 2#10# = 2#1#)
1 rem 3 = 1 (2#1# rem 2#11# = 2#1#)
2 rem 0 = Constraint_Error
2 rem 1 = 0 (2#10# rem 2#1# = 2#0#)
2 rem 2 = 0 (2#10# rem 2#10# = 2#0#)
2 rem 3 = 2 (2#10# rem 2#11# = 2#10#)
3 rem 0 = Constraint_Error
3 rem 1 = 0 (2#11# rem 2#1# = 2#0#)
3 rem 2 = 1 (2#11# rem 2#10# = 2#1#)
3 rem 3 = 0 (2#11# rem 2#11# = 2#0#)
0 mod 0 = Constraint_Error
0 mod 1 = 0 (2#0# mod 2#1# = 2#0#)
0 mod 2 = 0 (2#0# mod 2#10# = 2#0#)
0 mod 3 = 0 (2#0# mod 2#11# = 2#0#)
1 mod 0 = Constraint_Error
1 mod 1 = 0 (2#1# mod 2#1# = 2#0#)
1 mod 2 = 1 (2#1# mod 2#10# = 2#1#)
1 mod 3 = 1 (2#1# mod 2#11# = 2#1#)
2 mod 0 = Constraint_Error
2 mod 1 = 0 (2#10# mod 2#1# = 2#0#)
2 mod 2 = 0 (2#10# mod 2#10# = 2#0#)
2 mod 3 = 2 (2#10# mod 2#11# = 2#10#)
3 mod 0 = Constraint_Error
3 mod 1 = 0 (2#11# mod 2#1# = 2#0#)
3 mod 2 = 1 (2#11# mod 2#10# = 2#1#)
3 mod 3 = 0 (2#11# mod 2#11# = 2#0#)
0 ** 0 = 1 (2#0# ** 2#0# = 2#1#)
. . .
3 ** 3 = 3 (2#11# ** 2#11# = 2#11#)
0 and 0 = 0 (2#0# and 2#0# = 2#0#)
. . .
3 and 3 = 3 (2#11# and 2#11# = 2#11#)
0 or 0 = 0 (2#0# or 2#0# = 2#0#)
. . .
3 or 3 = 3 (2#11# or 2#11# = 2#11#)
0 xor 0 = 0 (2#0# xor 2#0# = 2#0#)
. . .
3 xor 3 = 0 (2#11# xor 2#11# = 2#0#)
not 0 = 3 (not 2#0# = 2#11#)
not 1 = 2 (not 2#1# = 2#10#)
not 2 = 1 (not 2#10# = 2#1#)
not 3 = 0 (not 2#11# = 2#0#)
Pred(0) = 3 (Pred(2#0#) = 2#11#)
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 29
900707 BI WI
Pred(1) = 0 (Pred(2#1#) = 2#0#)
Pred(2) = 1 (Pred(2#10#) = 2#1#)
Pred(3) = 2 (Pred(2#11#) = 2#10#)
Succ(0) = 1 (Succ(2#0#) = 2#1#)
Succ(1) = 2 (Succ(2#1#) = 2#10#)
Succ(2) = 3 (Succ(2#10#) = 2#11#)
Succ(3) = 0 (Succ(2#11#) = 2#0#)
** END OF DEFINITION OF THE UNSIGNED INTEGER TYPES PACKAGE **
The provision of unsigned integers as an integral part of the language in
Ada9X is discussed in the Appendix.
Practice
DEC defines its unsigned types in package SYSTEM. There are two "genuine"
unsigned integer types called UNSIGNED_BYTE and UNSIGNED_WORD plus a signed
integer type called UNSIGNED_LONGWORD and a record type called
UNSIGNED_QUADWORD which has two components of type UNSIGNED_LONGWORD.
Static subtypes of the (signed) type UNSIGNED_LONGWORD are provided.
No discussion of further derivability of these types is provided. By the
absence of explicit statements, it may be inferred that the arithmetic on
these unsigned types is not modular.
For each unsigned integer type, the DEC implementation provides logical
operators and a corresponding constrained subtype of a common unconstrained
packed BOOLEAN array type and conversions to and from that subtype and the
unsigned types. For example:
type BIT_ARRAY is array (INTEGER range <>) of BOOLEAN;
pragma PACK (BIT_ARRAY);  There must be exactly 1 bit for each BOOLEAN
 component, which DEC kindly provides for
 packed unconstrained arrays of BOOLEANs.
Question: What is the weight of bit i? Is it 2**i or 2**(n  1  i)?
Answer: It is implementationdependent.
BIT_ARRAY should probably not be a standard part of the definition of
unsigned types, because the added functionality (indexing and catenation) is
of marginal value, the order of bits is implementationdependent, and users
can implement it themselves if they so desire (using UNCHECKED_CONVERSION).
Implementers may decide to provide it anyway, of course. The functional
capabilities of BIT_ARRAY, other than catenation, are available for the
unsigned types proposed above, and the literals are much nicer. For instance
(taking a "littleendian" view):
if (Logical_Shift(Unsigned_Value, 4) and 1) = 1 then ...  bit 4 is on
or, perhaps more efficiently and more clearly:
Bit_4 : constant := 2#10000#;
if (Unsigned_Value and Bit_4) = Bit_4 then ...  bit 4 is on.
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 30
900707 BI WI
Alsys defines its unsigned types in package UNSIGNED (available
only for the PC compiler). It defines two unsigned integer types,
type BYTE (range 0 .. 255) and type WORD (range 0 .. 65535).
Their representations in memory are context dependent. As record and array
components, they occupy 8 and 16 bits, respectively; as scalar objects, they
both occupy 16 bits.
Their arithmetic is modular and their subtypes have rangechecking, but they
are not "properly" derivable, that is to say, types derived from them will be
ordinary integer types, because it is asserted that their base types are
predefined integer types, rather than the types themselves.
Instantiations of UNCHECKED_CONVERSION are provided to and from
other integer types, although one would expect explicit conversions to
be sufficient. Unchecked conversion from CHARACTER to BYTE
is provided, but (curiously) no function is provided to convert
BYTE to CHARACTER (which ought to raise CONSTRAINT_ERROR
if the high bit is on). A user could (apparently) instantiate
UNCHECKED_CONVERSION on these types himself to remedy the oversight.
Functions LSB, MSB, and MAKE_WORD which extract the
least or most significant byte of a word and construct a
word from two bytes are provided; they could have been
written in Ada.
Verdix provides a package called Unsigned_Types defining true 8, 16, and
32bit unsigned integers without logical operations. (They say to use it
at your own risk, since it is not valid Ada). They also provide a separate
package called Iface_Bits for bitwise logical operations on type Integer.
Contrary to what might be expected, they are named Bit_And, Bit_Or, Bit_Xor,
and Bit_Neg, rather than the usual operator symbols.
Appendix
Ada9X Issues
The revision of the language needs to address the syntax and semantics for
declaring unsigned integer types in a more general fashion, similar to the
current model for signed integer types. The changes ought to be upward
compatible since the types would be declared in STANDARD. It is important to
discuss the potential revisions here in order to see the interactions that may
occur. The following illustrates some of the possibilities when no new
reserved words are used (THIS IS *NOT* A PART OF THE PROPOSAL):
In STANDARD, the (minimal) required declarations are:
type UNSIGNED_n is {implementation_defined};
Other optional types could be supplied by the implementation.
A userdefined unsigned integer with modular arithmetic might be declared by:
type MY_UNSIGNED is mod M;
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 31
900707 BI WI
where M is the modulus of the arithmetic and MY_UNSIGNED'LAST
is M  1. Whether M should be contrained in some fashion is an issue which
must be resolved.
A portable syntax for declaring the largest possible distinct unsigned types
would be available if the following are declared:
type LARGEST_UNSIGNED is new {implementation_defined_unsigned_type};
(These could be defined more directly if true type renaming were allowed in
the revision:
type LARGEST_UNSIGNED_TYPE renames {implementation_defined_unsigned_type};
Then the following declaration may be made:
type MY_UNSIGNED is new LARGEST_UNSIGNED_TYPE;)
As an alternative, if SYSTEM contains:
MAX_MODULUS : constant {implementation_defined};
then the following declaration is possible:
type UNSIGNED is mod SYSTEM.MAX_MODULUS;
On the other hand, Ada9X could simply require the implementation of the
UNSIGNED_NUMBERS package proposed here as a predefined library package
similar to CALENDAR and TEXT_IO.
*****************************************************************************
!section 03.05.04 (07) Ron Brender 900604 8301372
!version 1983
!topic Unsigned integer
!references AI00597/02 etc
On page 3, insert something like "entities within" before "TEXT_IO for
such a file", which ends the first full paragraph on page 3. TEXT_IO
itself is not a generic unit.
The second full paragraph is much too vague and weak. It reads like:
just for the fun of it, the ARG has stuck in some random thoughts on
how an unsigned integer type might be defined. Instead, the tone
should be much more of a strong recommendation that if an
implementation does provide unsigned integer type, it's properties
should be precisely what follows. (I know this is "merely" a
permisive AI and can't force these and only these properties  but
there should be no doubt that that is what is intended.)
The paragraph beginning "3.5(79) says" and ending "have the FIRST and
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 32
900707 BI WI
LAST attributes" belongs somewhere near the middle of page 2.
On page 4 (line 7 et al) , it probably is overkill, but if you want to
be really fussy, the correct statement is
T'POS(X+Y) = ...
T'POS(XY) = ...
For the final paragraph (on page 5), the alternative suggesting
nonstatic universal expressions must be supported even in the unsigned
integer range seems definitely a mistake. This would seem to require
some kind of runtime bookkeeping as to whether a value is signed or
unsigned in order to correctly range check the inevitable consuming
use (and type conversion). Such runtime type variability has no
precedent in Ada  and no obvious important benefit either.
Finally, if you are going to provide modular types (which I do not
oppose), it is unfortunate that the base types are limited to powers
of two (or their ones complement equivalent). For example, a 60
second cyclic counter cannot be conveniently declared. This at least
desires to be made explicit.
 *****************************************************************************

 !section 01.01.02 (06) D. Eilers 900619 8301376
 !version 1983
 !topic Must implementationdefined packages be compilable?

 !reference AI00597/02

 AI00597/02 states that "3.5.4(7) should not be understood to forbid
 the declaration of an implementationdefined unsigned integer type in some
 implementationdefined package." If implementationdefined unsigned integer
 types are allowed, simply because they are not explicitly forbidden, then by
 extension, one would assume that an implementation is free to provide just
 about any implementationdefined type which a user might want, but is
 otherwise forbidden to declare.

 Such types might include infiniteprecision integers (with integer
 literals), rational numbers (with real literals), nullterminated strings
 (with string literals), ragged or triangular or expandable arrays (with array
 aggregates), etc. While such types might provide highly desirable capability,
 any program which made use of them would be nonportable, except to the degree
 that such usage was standardized by secondary standards.

 The question could be asked: "What language are these implementation
 defined packages written in?" It cannot be Ada, because Ada does not allow
 the declaration of unsigned types. But it cannot be some other language,
 because Ada provides no mechanism for importing types from other languages.
 Noncompilable implementationdefined packages would seem to violate the
 declaration of conformance, which allows "no deliberate extensions", even
 if they are not explicitly prohibited by the standard.
DRAFT DRAFT DRAFT
Unsigned integer types can be provided AI00597/03 33
900707 BI WI
 Package Standard is an interesting case. Apparently the Ada rules
 do not apply to Standard because it is not part of an Ada program. Library
 units only "act" as if they were declared within Standard (RM 10.1.4).
 However, Ada rules presumably do apply to System and all other implementation
 defined packages.

 If the provision of unsigned integer types is to be legitimized,
 (and I believe it should be), it would seem preferable to allow them in
 Standard, with the other undefinable types. This would also make their
 operator visibility more consistent with the predefined integer types.
 It might also be more consistent with what Ada9X would allow.

 Dan Eilers
DRAFT DRAFT DRAFT