Contents Index Previous Next
3.5.4 Integer Types
1
{integer type} {signed
integer type} {modular
type} An
integer_type_definition
defines an integer type; it defines either a
signed integer type,
or a
modular integer type. The base range of a signed integer
type includes at least the values of the specified range. A modular type
is an integer type with all arithmetic modulo a specified positive
modulus;
such a type corresponds to an unsigned type with wrap-around semantics.
{unsigned type: See modular type}
Syntax
2
integer_type_definition
::= signed_integer_type_definition |
modular_type_definition
3
signed_integer_type_definition
::= range static_simple_expression ..
static_simple_expression
3.a
Discussion: We don't call
this a range_constraint, because
it is rather different -- not only is it required to be static, but the
associated overload resolution rules are different than for normal range
constraints. A similar comment applies to real_range_specification.
This used to be integer_range_specification
but when we added support for modular types, it seemed overkill to have
three levels of syntax rules, and just calling these signed_integer_range_specification
and modular_range_specification
loses the fact that they are defining different classes of types, which
is important for the generic type matching rules.
4
modular_type_definition
::= mod static_expression
Name Resolution Rules
5
{expected type (signed_integer_type_definition
simple_expression) [partial]} Each
simple_expression
in a
signed_integer_type_definition
is expected to be of any integer type; they need not be of the same type.
{expected type (modular_type_definition expression)
[partial]} The
expression
in a
modular_type_definition is
likewise expected to be of any integer type.
Legality Rules
6
The simple_expressions
of a signed_integer_type_definition
shall be static, and their values shall be in the range System.Min_Int
.. System.Max_Int.
7
{modulus (of a modular type)}
{Max_Binary_Modulus}
{Max_Nonbinary_Modulus}
The
expression
of a
modular_type_definition shall
be static, and its value (the
modulus) shall be positive, and
shall be no greater than System.Max_Binary_Modulus if a power of 2, or
no greater than System.Max_Nonbinary_Modulus if not.
7.a
Reason: For a 2's-complement
machine, supporting nonbinary moduli greater than System.Max_Int can
be quite difficult, whereas essentially any binary moduli are straightforward
to support, up to 2*System.Max_Int+2, so this justifies having two separate
limits.
Static Semantics
8
The set of values for a signed integer type is
the (infinite) set of mathematical integers[, though only values of the
base range of the type are fully supported for run-time operations].
The set of values for a modular integer type are the values from 0 to
one less than the modulus, inclusive.
9
{base range (of a signed integer
type) [partial]} A
signed_integer_type_definition
defines an integer type whose base range includes at least the values
of the
simple_expressions and is
symmetric about zero, excepting possibly an extra negative value.
{constrained
(subtype)} {unconstrained
(subtype)} A
signed_integer_type_definition
also defines a constrained first subtype of the type, with a range whose
bounds are given by the values of the
simple_expressions,
converted to the type being defined.
9.a
Implementation Note: The
base range of a signed integer type might be much larger than is necessary
to satisfy the aboved requirements.
9.a.1/1
To be honest: The conversion
mentioned above is not an implicit subtype conversion (which is something
that happens at overload resolution, see 4.6), although
it happens implicitly. Therefore, the freezing rules are not invoked on the
type (which is important so that representation items can be given for the type).
{subtype conversion (bounds of signed integer type) [partial]}
10
{base range (of a modular type)
[partial]} A
modular_type_definition
defines a modular type whose base range is from zero to one less than
the given modulus.
{constrained (subtype)}
{unconstrained (subtype)}
A
modular_type_definition
also defines a constrained first subtype of the type with a range that
is the same as the base range of the type.
11
{Integer} There
is a predefined signed integer subtype named Integer[, declared in the
visible part of package Standard]. It is constrained to the base range
of its type.
11.a
Reason: Integer is a constrained
subtype, rather than an unconstrained subtype. This means that on assignment
to an object of subtype Integer, a range check is required. On the other
hand, an object of subtype Integer'Base is unconstrained, and no range
check (only overflow check) is required on assignment. For example, if
the object is held in an extended-length register, its value might be
outside of Integer'First .. Integer'Last. All parameter and result subtypes
of the predefined integer operators are of such unconstrained subtypes,
allowing extended-length registers to be used as operands or for the
result. In an earlier version of Ada 95, Integer was unconstrained. However,
the fact that certain Constraint_Errors might be omitted or appear elsewhere
was felt to be an undesirable upward inconsistency in this case. Note
that for Float, the opposite conclusion was reached, partly because of
the high cost of performing range checks when not actually necessary.
Objects of subtype Float are unconstrained, and no range checks, only
overflow checks, are performed for them.
12
{Natural}
{Positive} Integer
has two predefined subtypes, [declared in the visible part of package
Standard:]
13
subtype Natural is Integer range 0 .. Integer'Last;
subtype Positive is Integer range 1 .. Integer'Last;
14
{root_integer}
{Min_Int} {Max_Int}
A type defined by an
integer_type_definition
is implicitly derived from
root_integer, an anonymous predefined (specific)
integer type, whose base range is System.Min_Int .. System.Max_Int. However,
the base range of the new type is not inherited from
root_integer, but
is instead determined by the range or modulus specified by the
integer_type_definition.
{universal_integer [partial]} {integer
literals} [Integer literals are all of the type
universal_integer, the universal type (see
3.4.1)
for the class rooted at
root_integer, allowing their use with the operations
of any integer type.]
14.a
Discussion: This implicit
derivation is not considered exactly equivalent to explicit derivation
via a derived_type_definition. In
particular, integer types defined via a derived_type_definition
inherit their base range from their parent type. A type defined by an
integer_type_definition does not
necessarily inherit its base range from root_integer. It is not
specified whether the implicit derivation from root_integer is
direct or indirect, not that it really matters. All we want is for all
integer types to be descendants of root_integer.
14.a.1/1
{8652/0099}
Note that this derivation does not imply any inheritance of subprograms.
Subprograms are inherited only for types derived by a derived_type_definition
(see 3.4), or a private_extension_declaration
(see 7.3, 7.3.1, and 12.5.1).
14.b
Implementation Note: It is the intent
that even nonstandard integer types (see below) will be descendants of root_integer,
even though they might have a base range that exceeds that of root_integer.
This causes no problem for static calculations, which are performed without
range restrictions (see 4.9). However for run-time
calculations, it is possible that Constraint_Error might be raised when using
an operator of root_integer on the result of 'Val applied to a value
of a nonstandard integer type.
15
{position number (of an integer
value) [partial]} The
position number
of an integer value is equal to the value.
16
For every modular
subtype S, the following attribute is defined:
17
- S'Modulus
-
S'Modulus yields the modulus
of the type of S, as a value of the type universal_integer.
Dynamic Semantics
18
{elaboration (integer_type_definition)
[partial]} The elaboration of an
integer_type_definition
creates the integer type and its first subtype.
19
For a modular type, if the result
of the execution of a predefined operator (see
4.5)
is outside the base range of the type, the result is reduced modulo the modulus
of the type to a value that is within the base range of the type.
20
{Overflow_Check [partial]}
{check, language-defined (Overflow_Check)}
{Constraint_Error (raised by failure
of run-time check)} For a signed integer
type, the exception Constraint_Error is raised by the execution of an
operation that cannot deliver the correct result because it is outside
the base range of the type. [
{Division_Check [partial]}
{check, language-defined (Division_Check)}
{Constraint_Error (raised by failure
of run-time check)} For any integer type,
Constraint_Error is raised by the operators "/", "
rem",
and "
mod" if the right operand is zero.]
Implementation Requirements
21
{Integer} In
an implementation, the range of Integer shall include the range -2**15+1
.. +2**15-1.
22
{Long_Integer} If
Long_Integer is predefined for an implementation, then its range shall
include the range -2**31+1 .. +2**31-1.
23
System.Max_Binary_Modulus shall be at least 2**16.
Implementation Permissions
24
For the execution of a predefined operation of
a signed integer type, the implementation need not raise Constraint_Error
if the result is outside the base range of the type, so long as the correct
result is produced.
24.a
Discussion: Constraint_Error
is never raised for operations on modular types, except for divide-by-zero
(and rem/mod-by-zero).
25
{Long_Integer} {Short_Integer}
An implementation may provide additional predefined
signed integer types[, declared in the visible part of Standard], whose
first subtypes have names of the form Short_Integer, Long_Integer, Short_Short_Integer,
Long_Long_Integer, etc. Different predefined integer types are allowed
to have the same base range. However, the range of Integer should be
no wider than that of Long_Integer. Similarly, the range of Short_Integer
(if provided) should be no wider than Integer. Corresponding recommendations
apply to any other predefined integer types. There need not be a named
integer type corresponding to each distinct base range supported by an
implementation. The range of each first subtype should be the base range
of its type.
25.a
Implementation defined: The
predefined integer types declared in Standard.
26
{nonstandard integer
type} An implementation may provide
nonstandard
integer types, descendants of
root_integer that are declared outside
of the specification of package Standard, which need not have all the standard
characteristics of a type defined by an
integer_type_definition.
For example, a nonstandard integer type might have an asymmetric base range
or it might not be allowed as an array or loop index (a very long integer).
Any type descended from a nonstandard integer type is also nonstandard. An implementation
may place arbitrary restrictions on the use of such types; it is implementation
defined whether operators that are predefined for ``any integer type'' are defined
for a particular nonstandard integer type. [In any case, such types are not
permitted as
explicit_generic_actual_parameters
for formal scalar types -- see
12.5.2.]
26.a
Implementation defined: Any
nonstandard integer types and the operators defined for them.
27
{one's complement (modular types)
[partial]} For a one's complement machine,
the high bound of the base range of a modular type whose modulus is one
less than a power of 2 may be equal to the modulus, rather than one less
than the modulus. It is implementation defined for which powers of 2,
if any, this permission is exercised.
27.1/1
{
8652/0003}
For a one's complement machine, implementations may support non-binary modulus
values greater than System.Max_Nonbinary_Modulus. It is implementation defined
which specific values greater than System.Max_Nonbinary_Modulus, if any, are
supported.
27.a.1/1
Reason: On a one's complement
machine, the natural full word type would have a modulus of 2**Word_Size-1.
However, we would want to allow the all-ones bit pattern (which represents
negative zero as a number) in logical operations. These permissions are
intended to allow that and the natural modulus value without burdening
implementations with supporting expensive modulus values.
Implementation Advice
28
{Long_Integer}
An implementation should support Long_Integer in addition
to Integer if the target machine supports 32-bit (or longer) arithmetic. No
other named integer subtypes are recommended for package Standard. Instead,
appropriate named integer subtypes should be provided in the library package
Interfaces (see
B.2).
28.a
Implementation Note: To promote
portability, implementations should explicitly declare the integer (sub)types
Integer and Long_Integer in Standard, and leave other predefined integer types
anonymous. For implementations that already support Byte_Integer, etc., upward
compatibility argues for keeping such declarations in Standard during the transition
period, but perhaps generating a warning on use. A separate package Interfaces
in the predefined environment is available for pre-declaring types such as Integer_8,
Integer_16, etc. See B.2. In any case, if the user
declares a subtype (first or not) whose range fits in, for example, a byte,
the implementation can store variables of the subtype in a single byte, even
if the base range of the type is wider.
29
{two's complement (modular types)
[partial]} An implementation for a two's complement
machine should support modular types with a binary modulus up to System.Max_Int*2+2.
An implementation should support a nonbinary modulus up to Integer'Last.
29.a
Reason: Modular types provide
bit-wise "and", "or", "xor",
and "not" operations. It is important for systems programming
that these be available for all integer types of the target hardware.
29.b
Ramification: Note that
on a one's complement machine, the largest supported modular type would
normally have a nonbinary modulus. On a two's complement machine, the
largest supported modular type would normally have a binary modulus.
29.c
Implementation Note: Supporting
a nonbinary modulus greater than Integer'Last can impose an undesirable
implementation burden on some machines.
30
25 {universal_integer}
{integer literals} Integer
literals are of the anonymous predefined integer type universal_integer.
Other integer types have no literals. However, the overload resolution rules
(see 8.6, ``The Context of Overload
Resolution'') allow expressions of the type universal_integer whenever
an integer type is expected.
31
26 The same arithmetic operators are
predefined for all signed integer types defined by a signed_integer_type_definition
(see 4.5, ``Operators and Expression
Evaluation''). For modular types, these same operators are predefined, plus
bit-wise logical operators (and, or, xor, and not).
In addition, for the unsigned types declared in the language-defined package
Interfaces (see B.2), functions are defined that provide
bit-wise shifting and rotating.
32
27 Modular types match a generic_formal_parameter_declaration
of the form "type T is mod <>;"; signed integer
types match "type T is range <>;" (see 12.5.2).
Examples
33
Examples of
integer types and subtypes:
34
type Page_Num is range 1 .. 2_000;
type Line_Size is range 1 .. Max_Line_Size;
35
subtype Small_Int is Integer range -10 .. 10;
subtype Column_Ptr is Line_Size range 1 .. 10;
subtype Buffer_Size is Integer range 0 .. Max;
36
type Byte is mod 256; -- an unsigned byte
type Hash_Index is mod 97; -- modulus is prime
Extensions to Ada 83
36.a
{extensions to Ada 83}
An implementation is allowed to support any number
of distinct base ranges for integer types, even if fewer integer types
are explicitly declared in Standard.
36.b
Modular (unsigned, wrap-around)
types are new.
Wording Changes from Ada 83
36.c
Ada 83's integer types are now
called "signed" integer types, to contrast them with "modular"
integer types.
36.d
Standard.Integer, Standard.Long_Integer,
etc., denote constrained subtypes of predefined integer types, consistent
with the Ada 95 model that only subtypes have names.
36.e
We now impose minimum requirements
on the base range of Integer and Long_Integer.
36.f
We no longer explain integer type
definition in terms of an equivalence to a normal type derivation, except
to say that all integer types are by definition implicitly derived from
root_integer. This is for various reasons.
36.g
First of all, the equivalence
with a type derivation and a subtype declaration was not perfect, and
was the source of various AIs (for example, is the conversion of the
bounds static? Is a numeric type a derived type with respect to other
rules of the language?)
36.h
Secondly, we don't want to require
that every integer size supported shall have a corresponding named type
in Standard. Adding named types to Standard creates nonportabilities.
36.i
Thirdly, we don't want the set
of types that match a formal derived type "type T is new Integer;"
to depend on the particular underlying integer representation chosen
to implement a given user-defined integer type. Hence, we would have
needed anonymous integer types as parent types for the implicit derivation
anyway. We have simply chosen to identify only one anonymous integer
type -- root_integer, and stated that every integer type is derived
from it.
36.j
Finally, the ``fiction'' that
there were distinct preexisting predefined types for every supported
representation breaks down for fixed point with arbitrary smalls, and
was never exploited for enumeration types, array types, etc. Hence, there
seems little benefit to pushing an explicit equivalence between integer
type definition and normal type derivation.
Contents Index Previous Next Legal