1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . A R I T H _ D O U B L E --
9 -- Copyright (C) 1992-2023, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- This package provides software routines for doing arithmetic on "double"
33 -- signed integer values in cases where either overflow checking is required,
34 -- or intermediate results are longer than the result type.
36 with Ada
.Numerics
.Big_Numbers
.Big_Integers_Ghost
;
40 type Double_Int
is range <>;
42 type Double_Uns
is mod <>;
44 type Single_Uns
is mod <>;
46 with function Shift_Left
(A
: Double_Uns
; B
: Natural) return Double_Uns
49 with function Shift_Right
(A
: Double_Uns
; B
: Natural) return Double_Uns
52 with function Shift_Left
(A
: Single_Uns
; B
: Natural) return Single_Uns
55 package System
.Arith_Double
58 -- Preconditions in this unit are meant for analysis only, not for run-time
59 -- checking, so that the expected exceptions are raised. This is enforced
60 -- by setting the corresponding assertion policy to Ignore. Postconditions
61 -- and contract cases should not be executed at runtime as well, in order
62 -- not to slow down the execution of these functions.
64 pragma Assertion_Policy
(Pre
=> Ignore
,
66 Contract_Cases
=> Ignore
,
69 package BI_Ghost
renames Ada
.Numerics
.Big_Numbers
.Big_Integers_Ghost
;
70 subtype Big_Integer
is BI_Ghost
.Big_Integer
with Ghost
;
71 subtype Big_Natural
is BI_Ghost
.Big_Natural
with Ghost
;
72 subtype Big_Positive
is BI_Ghost
.Big_Positive
with Ghost
;
73 use type BI_Ghost
.Big_Integer
;
75 package Signed_Conversion
is
76 new BI_Ghost
.Signed_Conversions
(Int
=> Double_Int
);
78 function Big
(Arg
: Double_Int
) return Big_Integer
is
79 (Signed_Conversion
.To_Big_Integer
(Arg
))
82 Annotate
=> (GNATprove
, Inline_For_Proof
);
84 package Unsigned_Conversion
is
85 new BI_Ghost
.Unsigned_Conversions
(Int
=> Double_Uns
);
87 function Big
(Arg
: Double_Uns
) return Big_Integer
is
88 (Unsigned_Conversion
.To_Big_Integer
(Arg
))
91 Annotate
=> (GNATprove
, Inline_For_Proof
);
93 function In_Double_Int_Range
(Arg
: Big_Integer
) return Boolean is
94 (BI_Ghost
.In_Range
(Arg
, Big
(Double_Int
'First), Big
(Double_Int
'Last)))
97 Annotate
=> (GNATprove
, Inline_For_Proof
);
99 function Add_With_Ovflo_Check
(X
, Y
: Double_Int
) return Double_Int
101 Pre
=> In_Double_Int_Range
(Big
(X
) + Big
(Y
)),
102 Post
=> Add_With_Ovflo_Check
'Result = X
+ Y
;
103 -- Raises Constraint_Error if sum of operands overflows Double_Int,
104 -- otherwise returns the signed integer sum.
106 function Subtract_With_Ovflo_Check
(X
, Y
: Double_Int
) return Double_Int
108 Pre
=> In_Double_Int_Range
(Big
(X
) - Big
(Y
)),
109 Post
=> Subtract_With_Ovflo_Check
'Result = X
- Y
;
110 -- Raises Constraint_Error if difference of operands overflows Double_Int,
111 -- otherwise returns the signed integer difference.
113 function Multiply_With_Ovflo_Check
(X
, Y
: Double_Int
) return Double_Int
115 Pre
=> In_Double_Int_Range
(Big
(X
) * Big
(Y
)),
116 Post
=> Multiply_With_Ovflo_Check
'Result = X
* Y
;
117 pragma Convention
(C
, Multiply_With_Ovflo_Check
);
118 -- Raises Constraint_Error if product of operands overflows Double_Int,
119 -- otherwise returns the signed integer product. Gigi may also call this
122 function Same_Sign
(X
, Y
: Big_Integer
) return Boolean is
123 (X
= Big
(Double_Int
'(0))
124 or else Y = Big (Double_Int'(0))
125 or else (X
< Big
(Double_Int
'(0))) = (Y < Big (Double_Int'(0))))
128 function Round_Quotient
(X
, Y
, Q
, R
: Big_Integer
) return Big_Integer
is
129 (if abs R
> (abs Y
- Big
(Double_Int
'(1))) / Big (Double_Int'(2)) then
130 (if Same_Sign
(X
, Y
) then Q
+ Big
(Double_Int
'(1))
131 else Q - Big (Double_Int'(1)))
136 Pre
=> Y
/= 0 and then Q
= X
/ Y
and then R
= X
rem Y
;
138 procedure Scaled_Divide
139 (X
, Y
, Z
: Double_Int
;
140 Q
, R
: out Double_Int
;
144 and then In_Double_Int_Range
145 (if Round
then Round_Quotient
(Big
(X
) * Big
(Y
), Big
(Z
),
146 Big
(X
) * Big
(Y
) / Big
(Z
),
147 Big
(X
) * Big
(Y
) rem Big
(Z
))
148 else Big
(X
) * Big
(Y
) / Big
(Z
)),
149 Post
=> Big
(R
) = Big
(X
) * Big
(Y
) rem Big
(Z
)
152 Big
(Q
) = Round_Quotient
(Big
(X
) * Big
(Y
), Big
(Z
),
153 Big
(X
) * Big
(Y
) / Big
(Z
), Big
(R
))
155 Big
(Q
) = Big
(X
) * Big
(Y
) / Big
(Z
));
156 -- Performs the division of (X * Y) / Z, storing the quotient in Q
157 -- and the remainder in R. Constraint_Error is raised if Z is zero,
158 -- or if the quotient does not fit in Double_Int. Round indicates if
159 -- the result should be rounded. If Round is False, then Q, R are
160 -- the normal quotient and remainder from a truncating division.
161 -- If Round is True, then Q is the rounded quotient. The remainder
162 -- R is not affected by the setting of the Round flag.
164 procedure Double_Divide
165 (X
, Y
, Z
: Double_Int
;
166 Q
, R
: out Double_Int
;
171 and then In_Double_Int_Range
172 (if Round
then Round_Quotient
(Big
(X
), Big
(Y
) * Big
(Z
),
173 Big
(X
) / (Big
(Y
) * Big
(Z
)),
174 Big
(X
) rem (Big
(Y
) * Big
(Z
)))
175 else Big
(X
) / (Big
(Y
) * Big
(Z
))),
176 Post
=> Big
(R
) = Big
(X
) rem (Big
(Y
) * Big
(Z
))
179 Big
(Q
) = Round_Quotient
(Big
(X
), Big
(Y
) * Big
(Z
),
180 Big
(X
) / (Big
(Y
) * Big
(Z
)), Big
(R
))
182 Big
(Q
) = Big
(X
) / (Big
(Y
) * Big
(Z
)));
183 -- Performs the division X / (Y * Z), storing the quotient in Q and
184 -- the remainder in R. Constraint_Error is raised if Y or Z is zero,
185 -- or if the quotient does not fit in Double_Int. Round indicates if the
186 -- result should be rounded. If Round is False, then Q, R are the normal
187 -- quotient and remainder from a truncating division. If Round is True,
188 -- then Q is the rounded quotient. The remainder R is not affected by the
189 -- setting of the Round flag.
191 end System
.Arith_Double
;