1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- S Y S T E M . E X P O N T --
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 package body System
.Expont
36 -- Preconditions, postconditions, ghost code, loop invariants and
37 -- assertions in this unit are meant for analysis only, not for run-time
38 -- checking, as it would be too costly otherwise. This is enforced by
39 -- setting the assertion policy to Ignore.
41 pragma Assertion_Policy
(Pre
=> Ignore
,
44 Loop_Invariant
=> Ignore
,
49 procedure Lemma_Exp_Expand
(A
: Big_Integer
; Exp
: Natural)
54 (if Exp
rem 2 = 0 then
55 A
** Exp
= A
** (Exp
/ 2) * A
** (Exp
/ 2)
57 A
** Exp
= A
** (Exp
/ 2) * A
** (Exp
/ 2) * A
);
59 procedure Lemma_Exp_In_Range
(A
: Big_Integer
; Exp
: Positive)
62 Pre
=> In_Int_Range
(A
** Exp
* A
** Exp
),
63 Post
=> In_Int_Range
(A
* A
);
65 procedure Lemma_Exp_Not_Zero
(A
: Big_Integer
; Exp
: Natural)
69 Post
=> A
** Exp
/= 0;
71 procedure Lemma_Exp_Positive
(A
: Big_Integer
; Exp
: Natural)
75 and then Exp
rem 2 = 0,
78 procedure Lemma_Mult_In_Range
(X
, Y
, Z
: Big_Integer
)
82 and then not (X
= -Big
(Int
'First) and Y
= -1)
84 and then In_Int_Range
(Z
),
85 Post
=> In_Int_Range
(X
);
87 -----------------------------
88 -- Local lemma null bodies --
89 -----------------------------
91 procedure Lemma_Exp_Not_Zero
(A
: Big_Integer
; Exp
: Natural) is null;
92 procedure Lemma_Mult_In_Range
(X
, Y
, Z
: Big_Integer
) is null;
98 function Expon
(Left
: Int
; Right
: Natural) return Int
is
100 -- Note that negative exponents get a constraint error because the
101 -- subtype of the Right argument (the exponent) is Natural.
104 Factor
: Int
:= Left
;
105 Exp
: Natural := Right
;
107 Rest
: Big_Integer
with Ghost
;
108 -- Ghost variable to hold Factor**Exp between Exp and Factor updates
111 pragma Annotate
(Gnatcheck
, Exempt_On
, "Improper_Returns",
112 "early returns for performance");
114 -- We use the standard logarithmic approach, Exp gets shifted right
115 -- testing successive low order bits and Factor is the value of the
116 -- base raised to the next power of 2.
118 -- Note: for compilation only, it is not worth special casing base
119 -- values -1, 0, +1 since the expander does this when the base is a
120 -- literal, and other cases will be extremely rare. But for proof,
121 -- special casing zero in both positions makes ghost code and lemmas
122 -- simpler, so we do it.
131 pragma Loop_Invariant
(Exp
> 0);
132 pragma Loop_Invariant
(Factor
/= 0);
133 pragma Loop_Invariant
134 (Big
(Result
) * Big
(Factor
) ** Exp
= Big
(Left
) ** Right
);
135 pragma Loop_Variant
(Decreases
=> Exp
);
137 if Exp
rem 2 /= 0 then
139 pragma Unsuppress
(Overflow_Check
);
143 = Big
(Factor
) * Big
(Factor
) ** (Exp
- 1));
144 Lemma_Exp_Positive
(Big
(Factor
), Exp
- 1);
145 Lemma_Mult_In_Range
(Big
(Result
) * Big
(Factor
),
146 Big
(Factor
) ** (Exp
- 1),
147 Big
(Left
) ** Right
);
149 Result
:= Result
* Factor
;
153 Lemma_Exp_Expand
(Big
(Factor
), Exp
);
158 Rest
:= Big
(Factor
) ** Exp
;
160 (Big
(Result
) * (Rest
* Rest
) = Big
(Left
) ** Right
);
163 pragma Unsuppress
(Overflow_Check
);
165 Lemma_Mult_In_Range
(Rest
* Rest
,
167 Big
(Left
) ** Right
);
168 Lemma_Exp_In_Range
(Big
(Factor
), Exp
);
170 Factor
:= Factor
* Factor
;
173 pragma Assert
(Big
(Factor
) ** Exp
= Rest
* Rest
);
176 pragma Assert
(Big
(Result
) = Big
(Left
) ** Right
);
180 pragma Annotate
(Gnatcheck
, Exempt_Off
, "Improper_Returns");
183 ----------------------
184 -- Lemma_Exp_Expand --
185 ----------------------
187 procedure Lemma_Exp_Expand
(A
: Big_Integer
; Exp
: Natural) is
189 if Exp
rem 2 = 0 then
190 pragma Assert
(Exp
= Exp
/ 2 + Exp
/ 2);
192 pragma Assert
(Exp
= Exp
/ 2 + Exp
/ 2 + 1);
193 pragma Assert
(A
** Exp
= A
** (Exp
/ 2) * A
** (Exp
/ 2 + 1));
194 pragma Assert
(A
** (Exp
/ 2 + 1) = A
** (Exp
/ 2) * A
);
195 pragma Assert
(A
** Exp
= A
** (Exp
/ 2) * A
** (Exp
/ 2) * A
);
197 end Lemma_Exp_Expand
;
199 ------------------------
200 -- Lemma_Exp_In_Range --
201 ------------------------
203 procedure Lemma_Exp_In_Range
(A
: Big_Integer
; Exp
: Positive) is
205 if A
/= 0 and Exp
/= 1 then
206 pragma Assert
(A
** Exp
= A
* A
** (Exp
- 1));
208 (A
* A
, A
** (Exp
- 1) * A
** (Exp
- 1), A
** Exp
* A
** Exp
);
210 end Lemma_Exp_In_Range
;
212 ------------------------
213 -- Lemma_Exp_Positive --
214 ------------------------
216 procedure Lemma_Exp_Positive
(A
: Big_Integer
; Exp
: Natural) is
219 pragma Assert
(A
** Exp
= 1);
221 pragma Assert
(Exp
= 2 * (Exp
/ 2));
222 pragma Assert
(A
** Exp
= A
** (Exp
/ 2) * A
** (Exp
/ 2));
223 pragma Assert
(A
** Exp
= (A
** (Exp
/ 2)) ** 2);
224 Lemma_Exp_Not_Zero
(A
, Exp
/ 2);
226 end Lemma_Exp_Positive
;