4.5.5 Multiplying Operators
Static Semantics
1
{multiplying
operator} {operator
(multiplying)} {*
operator} {operator
(*)} {multiply
operator} {operator
(multiply)} {times
operator} {operator
(times)} {/
operator} {operator
(/)} {divide
operator} {operator
(divide)} {mod
operator} {operator
(mod)} {rem
operator} {operator
(rem)} The multiplying operators * (multiplication),
/ (division),
mod (modulus), and
rem (remainder) are predefined
for every specific integer type
T:
2
function "*" (Left, Right : T) return T
function "/" (Left, Right : T) return T
function "mod"(Left, Right : T) return T
function "rem"(Left, Right : T) return T
3
Signed integer multiplication has its conventional
meaning.
4
Signed integer division
and remainder are defined by the relation:
5
A = (A/B)*B + (A rem B)
6
where (A rem
B) has the sign of A and an absolute value less than the absolute value
of B. Signed integer division satisfies the identity:
7
(-A)/B = -(A/B) = A/(-B)
8
The signed integer modulus
operator is defined such that the result of A mod B has the sign
of B and an absolute value less than the absolute value of B; in addition,
for some signed integer value N, this result satisfies the relation:
9
A = B*N + (A mod B)
10
The multiplying operators on modular types are defined
in terms of the corresponding signed integer operators[, followed by
a reduction modulo the modulus if the result is outside the base range
of the type] [(which is only possible for the "*" operator)].
10.a
Ramification: The above identity satisfied
by signed integer division is not satisfied by modular division because
of the difference in effect of negation.
11
Multiplication and
division operators are predefined for every specific floating point type
T:
12
function "*"(Left, Right : T) return T
function "/"(Left, Right : T) return T
13
The following multiplication
and division operators, with an operand of the predefined type Integer,
are predefined for every specific fixed point type T:
14
function "*"(Left : T; Right : Integer) return T
function "*"(Left : Integer; Right : T) return T
function "/"(Left : T; Right : Integer) return T
15
[All of the above multiplying
operators are usable with an operand of an appropriate universal numeric
type.] The following additional multiplying operators for root_real
are predefined[, and are usable when both operands are of an appropriate
universal or root numeric type, and the result is allowed to be of type
root_real, as in a number_declaration]:
15.a
Ramification: These operators are analogous
to the multiplying operators involving fixed or floating point types
where root_real substitutes for the fixed or floating point type,
and root_integer substitutes for Integer. Only values of the corresponding
universal numeric types are implicitly convertible to these root numeric
types, so these operators are really restricted to use with operands
of a universal type, or the specified root numeric types.
16
function "*"(Left, Right : root_real) return root_real
function "/"(Left, Right : root_real) return root_real
17
function "*"(Left : root_real; Right : root_integer) return root_real
function "*"(Left : root_integer; Right : root_real) return root_real
function "/"(Left : root_real; Right : root_integer) return root_real
18
Multiplication and
division between any two fixed point types are provided by the following
two predefined operators:
18.a
Ramification: Universal_fixed
is the universal type for the class of fixed point types, meaning that
these operators take operands of any fixed point types (not necessarily
the same) and return a result that is implicitly (or explicitly) convertible
to any fixed point type.
19
function "*"(Left, Right : universal_fixed) return universal_fixed
function "/"(Left, Right : universal_fixed) return universal_fixed
Name Resolution Rules
19.1/2
{
AI95-00364-01}
{
AI95-00420-01}
The above two fixed-fixed multiplying operators
shall not be used in a context where the expected type for the result
is itself universal_fixed [— the context has to identify
some other numeric type to which the result is to be converted, either
explicitly or implicitly]. Unless the predefined universal operator is
identified using an expanded name with prefix
denoting the package Standard, an explicit conversion is required on
the result when using the above fixed-fixed multiplication operator if
either operand is of a type having a user-defined primitive multiplication
operator such that:
19.2/2
- it is declared
immediately within the same declaration list as the type; and
19.3/2
- both of its
formal parameters are of a fixed-point type.
19.4/2
19.a/2
Discussion: The
small of universal_fixed is infinitesimal; no loss of precision
is permitted. However, fixed-fixed division is impractical to implement
when an exact result is required, and multiplication will sometimes result
in unanticipated overflows in such circumstances, so we require an explicit
conversion to be inserted in expressions like A * B * C if A, B, and
C are each of some fixed point type.
19.b/2
On the other hand, X :=
A * B; is permitted by this rule, even if X, A, and B are all of different
fixed point types, since the expected type for the result of the multiplication
is the type of X, which is necessarily not universal_fixed.
19.c/2
{
AI95-00364-01}
{
AI95-00420-01}
We have made these into Name Resolution rules to
ensure that user-defined primitive fixed-fixed operators are not made
unusable due to the presence of these universal fixed-fixed operators.
But we do allow these operators to be used if prefixed by package Standard,
so that they can be used in the definitions of user-defined operators.
Legality Rules
20/2
This paragraph was
deleted.{
AI95-00364-01}
The above two fixed-fixed multiplying operators
shall not be used in a context where the expected type for the result
is itself universal_fixed — [the context has to identify
some other numeric type to which the result is to be converted, either
explicitly or implicitly].
20.a/2
This paragraph
was deleted.Discussion: The small
of universal_fixed is infinitesimal; no loss of precision is permitted.
However, fixed-fixed division is impractical to implement when an exact
result is required, and multiplication will sometimes result in unanticipated
overflows in such circumstances, so we require an explicit conversion
to be inserted in expressions like A * B * C if A, B, and C are each
of some fixed point type.
20.b/2
This paragraph
was deleted.On the other hand, X :=
A * B; is permitted by this rule, even if X, A, and B are all of different
fixed point types, since the expected type for the result of the multiplication
is the type of X, which is necessarily not universal_fixed.
Dynamic Semantics
21
The multiplication and division operators for real
types have their conventional meaning. [For floating point types, the
accuracy of the result is determined by the precision of the result type.
For decimal fixed point types, the result is truncated toward zero if
the mathematical result is between two multiples of the
small
of the specific result type (possibly determined by context); for ordinary
fixed point types, if the mathematical result is between two multiples
of the
small, it is unspecified which of the two is the result.
{unspecified [partial]} ]
22
{Division_Check
[partial]} {check,
language-defined (Division_Check)} {Constraint_Error
(raised by failure of run-time check)} The
exception Constraint_Error is raised by integer division,
rem,
and
mod if the right operand is zero. [Similarly, for a real type
T with
T'Machine_Overflows True, division by zero raises
Constraint_Error.]
23
17 For positive
A and B, A/B is the quotient and A rem B is the remainder when
A is divided by B. The following relations are satisfied by the rem operator:
24
A rem (-B) = A rem B
(-A) rem B = -(A rem B)
25
18 For any
signed integer K, the following identity holds:
26
A mod B = (A + K*B) mod B
27
The relations between
signed integer division, remainder, and modulus are illustrated by the
following table:
28
A B A/B A rem B A mod B A B A/B A rem B A mod B
29
10 5 2 0 0 -10 5 -2 0 0
11 5 2 1 1 -11 5 -2 -1 4
12 5 2 2 2 -12 5 -2 -2 3
13 5 2 3 3 -13 5 -2 -3 2
14 5 2 4 4 -14 5 -2 -4 1
30
A B A/B A rem B A mod B A B A/B A rem B A mod B
10 -5 -2 0 0 -10 -5 2 0 0
11 -5 -2 1 -4 -11 -5 2 -1 -1
12 -5 -2 2 -3 -12 -5 2 -2 -2
13 -5 -2 3 -2 -13 -5 2 -3 -3
14 -5 -2 4 -1 -14 -5 2 -4 -4
Examples
31
Examples of expressions
involving multiplying operators:
32
I : Integer := 1;
J : Integer := 2;
K : Integer := 3;
33
X : Real := 1.0; --
see 3.5.7
Y : Real := 2.0;
34
F : Fraction := 0.25; --
see 3.5.9
G : Fraction := 0.5;
35
Expression Value Result Type
I*J 2 same as I and J, that is, Integer
K/J 1 same as K and J, that is, Integer
K mod J 1 same as K and J, that is, Integer
X/Y 0.5 same as X and Y, that is, Real
F/2 0.125 same as F, that is, Fraction
3*F 0.75 same as F, that is, Fraction
0.75*G 0.375 universal_fixed, implicitly convertible
to any fixed point type
Fraction(F*G) 0.125 Fraction, as stated by the conversion
Real(J)*Y 4.0 Real, the type of both operands after
conversion of J
Incompatibilities With Ada 83
35.a.1/2
{
AI95-00364-01}
{
AI95-00420-01}
{incompatibilities with Ada 83} The
universal fixed-fixed multiplying operators are now directly available
(see below). Any attempt to use user-defined fixed-fixed multiplying
operators will be ambiguous with the universal ones. The only way to
use the user-defined operators is to fully qualify them in a prefix call.
This problem was not documented during the design of Ada 95, and has
been mitigated by Ada 2005.
Extensions to Ada 83
35.a
{
extensions to Ada 83}
Explicit
conversion of the result of multiplying or dividing two fixed point numbers
is no longer required, provided the context uniquely determines some
specific fixed point result type. This is to improve support for decimal
fixed point, where requiring explicit conversion on every fixed-fixed
multiply or divide was felt to be inappropriate.
35.b
The type universal_fixed is covered by
universal_real, so real literals and fixed point operands may
be multiplied or divided directly, without any explicit conversions required.
Wording Changes from Ada 83
35.c
We have used the normal syntax for function
definition rather than a tabular format.
Incompatibilities With Ada 95
35.d/2
{
AI95-00364-01}
{incompatibilities with Ada 95} We
have changed the resolution rules for the universal fixed-fixed multiplying
operators to remove the incompatibility with Ada 83 discussed above.
The solution is to hide the universal operators in some circumstances.
As a result, some legal Ada 95 programs will require the insertion of
an explicit conversion around a fixed-fixed multiply operator. This change
is likely to catch as many bugs as it causes, since it is unlikely that
the user wanted to use predefined operators when they had defined user-defined
versions.