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/2
Implementation Note: {
AI95-00114-01} 
The base range of a signed integer type might be much larger than is 
necessary to satisfy the 
above 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} 
{
AI95-00152-01} 
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/2
 {
AI95-00340-01} 
For every modular subtype S, the following 
attributes 
are attribute is defined: 
 
16.1/2
   S'Mod
{
AI95-00340-01} 
S'Mod denotes a function 
with the following specification: 
16.2/2
function S'Mod (Arg : universal_integer)
  return S'Base
16.3/2
This function returns 
Arg mod S'Modulus, as a value of the type of S.
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} 
{
AI95-00095-01} 
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.1/2
Implementation Advice: 
Long_Integer should be declared in Standard 
if the target supports 32-bit arithmetic. No other named integer subtypes 
should be declared in Standard.
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.1/2
Implementation Advice: 
For a two's complement target, modular 
types with a binary modulus up to System.Max_Int*2+2 should be supported. 
A nonbinary modulus up to Integer'Last should be supported.
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
27  
{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
28  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
29  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. 
Extensions to Ada 95
36.k/2
{
AI95-00340-01} 
{extensions to Ada 95} The 
Mod attribute is new. It eases mixing of signed and unsigned values in 
an expression, which can be difficult as there may be no type which can 
contain all of the values of both of the types involved.  
Wording Changes from Ada 95
36.l/2
{
8652/0003} 
{
AI95-00095-01} 
Corrigendum: Added additional permissions 
for modular types on one's complement machines.