annotate gcc/ada/eval_fat.adb @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 ------------------------------------------------------------------------------
kono
parents:
diff changeset
2 -- --
kono
parents:
diff changeset
3 -- GNAT COMPILER COMPONENTS --
kono
parents:
diff changeset
4 -- --
kono
parents:
diff changeset
5 -- E V A L _ F A T --
kono
parents:
diff changeset
6 -- --
kono
parents:
diff changeset
7 -- B o d y --
kono
parents:
diff changeset
8 -- --
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
9 -- Copyright (C) 1992-2018, Free Software Foundation, Inc. --
111
kono
parents:
diff changeset
10 -- --
kono
parents:
diff changeset
11 -- GNAT is free software; you can redistribute it and/or modify it under --
kono
parents:
diff changeset
12 -- terms of the GNU General Public License as published by the Free Soft- --
kono
parents:
diff changeset
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
kono
parents:
diff changeset
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
kono
parents:
diff changeset
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
kono
parents:
diff changeset
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
kono
parents:
diff changeset
17 -- for more details. You should have received a copy of the GNU General --
kono
parents:
diff changeset
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
kono
parents:
diff changeset
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
kono
parents:
diff changeset
20 -- --
kono
parents:
diff changeset
21 -- GNAT was originally developed by the GNAT team at New York University. --
kono
parents:
diff changeset
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
kono
parents:
diff changeset
23 -- --
kono
parents:
diff changeset
24 ------------------------------------------------------------------------------
kono
parents:
diff changeset
25
kono
parents:
diff changeset
26 with Einfo; use Einfo;
kono
parents:
diff changeset
27 with Errout; use Errout;
kono
parents:
diff changeset
28 with Opt; use Opt;
kono
parents:
diff changeset
29 with Sem_Util; use Sem_Util;
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 package body Eval_Fat is
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 Radix : constant Int := 2;
kono
parents:
diff changeset
34 -- This code is currently only correct for the radix 2 case. We use the
kono
parents:
diff changeset
35 -- symbolic value Radix where possible to help in the unlikely case of
kono
parents:
diff changeset
36 -- anyone ever having to adjust this code for another value, and for
kono
parents:
diff changeset
37 -- documentation purposes.
kono
parents:
diff changeset
38
kono
parents:
diff changeset
39 -- Another assumption is that the range of the floating-point type is
kono
parents:
diff changeset
40 -- symmetric around zero.
kono
parents:
diff changeset
41
kono
parents:
diff changeset
42 type Radix_Power_Table is array (Int range 1 .. 4) of Int;
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 Radix_Powers : constant Radix_Power_Table :=
kono
parents:
diff changeset
45 (Radix ** 1, Radix ** 2, Radix ** 3, Radix ** 4);
kono
parents:
diff changeset
46
kono
parents:
diff changeset
47 -----------------------
kono
parents:
diff changeset
48 -- Local Subprograms --
kono
parents:
diff changeset
49 -----------------------
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 procedure Decompose
kono
parents:
diff changeset
52 (RT : R;
kono
parents:
diff changeset
53 X : T;
kono
parents:
diff changeset
54 Fraction : out T;
kono
parents:
diff changeset
55 Exponent : out UI;
kono
parents:
diff changeset
56 Mode : Rounding_Mode := Round);
kono
parents:
diff changeset
57 -- Decomposes a non-zero floating-point number into fraction and exponent
kono
parents:
diff changeset
58 -- parts. The fraction is in the interval 1.0 / Radix .. T'Pred (1.0) and
kono
parents:
diff changeset
59 -- uses Rbase = Radix. The result is rounded to a nearest machine number.
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 --------------
kono
parents:
diff changeset
62 -- Adjacent --
kono
parents:
diff changeset
63 --------------
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 function Adjacent (RT : R; X, Towards : T) return T is
kono
parents:
diff changeset
66 begin
kono
parents:
diff changeset
67 if Towards = X then
kono
parents:
diff changeset
68 return X;
kono
parents:
diff changeset
69 elsif Towards > X then
kono
parents:
diff changeset
70 return Succ (RT, X);
kono
parents:
diff changeset
71 else
kono
parents:
diff changeset
72 return Pred (RT, X);
kono
parents:
diff changeset
73 end if;
kono
parents:
diff changeset
74 end Adjacent;
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 -------------
kono
parents:
diff changeset
77 -- Ceiling --
kono
parents:
diff changeset
78 -------------
kono
parents:
diff changeset
79
kono
parents:
diff changeset
80 function Ceiling (RT : R; X : T) return T is
kono
parents:
diff changeset
81 XT : constant T := Truncation (RT, X);
kono
parents:
diff changeset
82 begin
kono
parents:
diff changeset
83 if UR_Is_Negative (X) then
kono
parents:
diff changeset
84 return XT;
kono
parents:
diff changeset
85 elsif X = XT then
kono
parents:
diff changeset
86 return X;
kono
parents:
diff changeset
87 else
kono
parents:
diff changeset
88 return XT + Ureal_1;
kono
parents:
diff changeset
89 end if;
kono
parents:
diff changeset
90 end Ceiling;
kono
parents:
diff changeset
91
kono
parents:
diff changeset
92 -------------
kono
parents:
diff changeset
93 -- Compose --
kono
parents:
diff changeset
94 -------------
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 function Compose (RT : R; Fraction : T; Exponent : UI) return T is
kono
parents:
diff changeset
97 Arg_Frac : T;
kono
parents:
diff changeset
98 Arg_Exp : UI;
kono
parents:
diff changeset
99 pragma Warnings (Off, Arg_Exp);
kono
parents:
diff changeset
100 begin
kono
parents:
diff changeset
101 Decompose (RT, Fraction, Arg_Frac, Arg_Exp);
kono
parents:
diff changeset
102 return Scaling (RT, Arg_Frac, Exponent);
kono
parents:
diff changeset
103 end Compose;
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 ---------------
kono
parents:
diff changeset
106 -- Copy_Sign --
kono
parents:
diff changeset
107 ---------------
kono
parents:
diff changeset
108
kono
parents:
diff changeset
109 function Copy_Sign (RT : R; Value, Sign : T) return T is
kono
parents:
diff changeset
110 pragma Warnings (Off, RT);
kono
parents:
diff changeset
111 Result : T;
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 begin
kono
parents:
diff changeset
114 Result := abs Value;
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 if UR_Is_Negative (Sign) then
kono
parents:
diff changeset
117 return -Result;
kono
parents:
diff changeset
118 else
kono
parents:
diff changeset
119 return Result;
kono
parents:
diff changeset
120 end if;
kono
parents:
diff changeset
121 end Copy_Sign;
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 ---------------
kono
parents:
diff changeset
124 -- Decompose --
kono
parents:
diff changeset
125 ---------------
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 procedure Decompose
kono
parents:
diff changeset
128 (RT : R;
kono
parents:
diff changeset
129 X : T;
kono
parents:
diff changeset
130 Fraction : out T;
kono
parents:
diff changeset
131 Exponent : out UI;
kono
parents:
diff changeset
132 Mode : Rounding_Mode := Round)
kono
parents:
diff changeset
133 is
kono
parents:
diff changeset
134 Int_F : UI;
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 begin
kono
parents:
diff changeset
137 Decompose_Int (RT, abs X, Int_F, Exponent, Mode);
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 Fraction := UR_From_Components
kono
parents:
diff changeset
140 (Num => Int_F,
kono
parents:
diff changeset
141 Den => Machine_Mantissa_Value (RT),
kono
parents:
diff changeset
142 Rbase => Radix,
kono
parents:
diff changeset
143 Negative => False);
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 if UR_Is_Negative (X) then
kono
parents:
diff changeset
146 Fraction := -Fraction;
kono
parents:
diff changeset
147 end if;
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 return;
kono
parents:
diff changeset
150 end Decompose;
kono
parents:
diff changeset
151
kono
parents:
diff changeset
152 -------------------
kono
parents:
diff changeset
153 -- Decompose_Int --
kono
parents:
diff changeset
154 -------------------
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 -- This procedure should be modified with care, as there are many non-
kono
parents:
diff changeset
157 -- obvious details that may cause problems that are hard to detect. For
kono
parents:
diff changeset
158 -- zero arguments, Fraction and Exponent are set to zero. Note that sign
kono
parents:
diff changeset
159 -- of zero cannot be preserved.
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 procedure Decompose_Int
kono
parents:
diff changeset
162 (RT : R;
kono
parents:
diff changeset
163 X : T;
kono
parents:
diff changeset
164 Fraction : out UI;
kono
parents:
diff changeset
165 Exponent : out UI;
kono
parents:
diff changeset
166 Mode : Rounding_Mode)
kono
parents:
diff changeset
167 is
kono
parents:
diff changeset
168 Base : Int := Rbase (X);
kono
parents:
diff changeset
169 N : UI := abs Numerator (X);
kono
parents:
diff changeset
170 D : UI := Denominator (X);
kono
parents:
diff changeset
171
kono
parents:
diff changeset
172 N_Times_Radix : UI;
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 Even : Boolean;
kono
parents:
diff changeset
175 -- True iff Fraction is even
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 Most_Significant_Digit : constant UI :=
kono
parents:
diff changeset
178 Radix ** (Machine_Mantissa_Value (RT) - 1);
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 Uintp_Mark : Uintp.Save_Mark;
kono
parents:
diff changeset
181 -- The code is divided into blocks that systematically release
kono
parents:
diff changeset
182 -- intermediate values (this routine generates lots of junk).
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 begin
kono
parents:
diff changeset
185 if N = Uint_0 then
kono
parents:
diff changeset
186 Fraction := Uint_0;
kono
parents:
diff changeset
187 Exponent := Uint_0;
kono
parents:
diff changeset
188 return;
kono
parents:
diff changeset
189 end if;
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 Calculate_D_And_Exponent_1 : begin
kono
parents:
diff changeset
192 Uintp_Mark := Mark;
kono
parents:
diff changeset
193 Exponent := Uint_0;
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 -- In cases where Base > 1, the actual denominator is Base**D. For
kono
parents:
diff changeset
196 -- cases where Base is a power of Radix, use the value 1 for the
kono
parents:
diff changeset
197 -- Denominator and adjust the exponent.
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 -- Note: Exponent has different sign from D, because D is a divisor
kono
parents:
diff changeset
200
kono
parents:
diff changeset
201 for Power in 1 .. Radix_Powers'Last loop
kono
parents:
diff changeset
202 if Base = Radix_Powers (Power) then
kono
parents:
diff changeset
203 Exponent := -D * Power;
kono
parents:
diff changeset
204 Base := 0;
kono
parents:
diff changeset
205 D := Uint_1;
kono
parents:
diff changeset
206 exit;
kono
parents:
diff changeset
207 end if;
kono
parents:
diff changeset
208 end loop;
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 Release_And_Save (Uintp_Mark, D, Exponent);
kono
parents:
diff changeset
211 end Calculate_D_And_Exponent_1;
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 if Base > 0 then
kono
parents:
diff changeset
214 Calculate_Exponent : begin
kono
parents:
diff changeset
215 Uintp_Mark := Mark;
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 -- For bases that are a multiple of the Radix, divide the base by
kono
parents:
diff changeset
218 -- Radix and adjust the Exponent. This will help because D will be
kono
parents:
diff changeset
219 -- much smaller and faster to process.
kono
parents:
diff changeset
220
kono
parents:
diff changeset
221 -- This occurs for decimal bases on machines with binary floating-
kono
parents:
diff changeset
222 -- point for example. When calculating 1E40, with Radix = 2, N
kono
parents:
diff changeset
223 -- will be 93 bits instead of 133.
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 -- N E
kono
parents:
diff changeset
226 -- ------ * Radix
kono
parents:
diff changeset
227 -- D
kono
parents:
diff changeset
228 -- Base
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 -- N E
kono
parents:
diff changeset
231 -- = -------------------------- * Radix
kono
parents:
diff changeset
232 -- D D
kono
parents:
diff changeset
233 -- (Base/Radix) * Radix
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235 -- N E-D
kono
parents:
diff changeset
236 -- = --------------- * Radix
kono
parents:
diff changeset
237 -- D
kono
parents:
diff changeset
238 -- (Base/Radix)
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 -- This code is commented out, because it causes numerous
kono
parents:
diff changeset
241 -- failures in the regression suite. To be studied ???
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 while False and then Base > 0 and then Base mod Radix = 0 loop
kono
parents:
diff changeset
244 Base := Base / Radix;
kono
parents:
diff changeset
245 Exponent := Exponent + D;
kono
parents:
diff changeset
246 end loop;
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 Release_And_Save (Uintp_Mark, Exponent);
kono
parents:
diff changeset
249 end Calculate_Exponent;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 -- For remaining bases we must actually compute the exponentiation
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 -- Because the exponentiation can be negative, and D must be integer,
kono
parents:
diff changeset
254 -- the numerator is corrected instead.
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 Calculate_N_And_D : begin
kono
parents:
diff changeset
257 Uintp_Mark := Mark;
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 if D < 0 then
kono
parents:
diff changeset
260 N := N * Base ** (-D);
kono
parents:
diff changeset
261 D := Uint_1;
kono
parents:
diff changeset
262 else
kono
parents:
diff changeset
263 D := Base ** D;
kono
parents:
diff changeset
264 end if;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 Release_And_Save (Uintp_Mark, N, D);
kono
parents:
diff changeset
267 end Calculate_N_And_D;
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 Base := 0;
kono
parents:
diff changeset
270 end if;
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 -- Now scale N and D so that N / D is a value in the interval [1.0 /
kono
parents:
diff changeset
273 -- Radix, 1.0) and adjust Exponent accordingly, so the value N / D *
kono
parents:
diff changeset
274 -- Radix ** Exponent remains unchanged.
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 -- Step 1 - Adjust N so N / D >= 1 / Radix, or N = 0
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 -- N and D are positive, so N / D >= 1 / Radix implies N * Radix >= D.
kono
parents:
diff changeset
279 -- As this scaling is not possible for N is Uint_0, zero is handled
kono
parents:
diff changeset
280 -- explicitly at the start of this subprogram.
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 Calculate_N_And_Exponent : begin
kono
parents:
diff changeset
283 Uintp_Mark := Mark;
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 N_Times_Radix := N * Radix;
kono
parents:
diff changeset
286 while not (N_Times_Radix >= D) loop
kono
parents:
diff changeset
287 N := N_Times_Radix;
kono
parents:
diff changeset
288 Exponent := Exponent - 1;
kono
parents:
diff changeset
289 N_Times_Radix := N * Radix;
kono
parents:
diff changeset
290 end loop;
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 Release_And_Save (Uintp_Mark, N, Exponent);
kono
parents:
diff changeset
293 end Calculate_N_And_Exponent;
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 -- Step 2 - Adjust D so N / D < 1
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 -- Scale up D so N / D < 1, so N < D
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 Calculate_D_And_Exponent_2 : begin
kono
parents:
diff changeset
300 Uintp_Mark := Mark;
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 while not (N < D) loop
kono
parents:
diff changeset
303
kono
parents:
diff changeset
304 -- As N / D >= 1, N / (D * Radix) will be at least 1 / Radix, so
kono
parents:
diff changeset
305 -- the result of Step 1 stays valid
kono
parents:
diff changeset
306
kono
parents:
diff changeset
307 D := D * Radix;
kono
parents:
diff changeset
308 Exponent := Exponent + 1;
kono
parents:
diff changeset
309 end loop;
kono
parents:
diff changeset
310
kono
parents:
diff changeset
311 Release_And_Save (Uintp_Mark, D, Exponent);
kono
parents:
diff changeset
312 end Calculate_D_And_Exponent_2;
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 -- Here the value N / D is in the range [1.0 / Radix .. 1.0)
kono
parents:
diff changeset
315
kono
parents:
diff changeset
316 -- Now find the fraction by doing a very simple-minded division until
kono
parents:
diff changeset
317 -- enough digits have been computed.
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 -- This division works for all radices, but is only efficient for a
kono
parents:
diff changeset
320 -- binary radix. It is just like a manual division algorithm, but
kono
parents:
diff changeset
321 -- instead of moving the denominator one digit right, we move the
kono
parents:
diff changeset
322 -- numerator one digit left so the numerator and denominator remain
kono
parents:
diff changeset
323 -- integral.
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 Fraction := Uint_0;
kono
parents:
diff changeset
326 Even := True;
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 Calculate_Fraction_And_N : begin
kono
parents:
diff changeset
329 Uintp_Mark := Mark;
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 loop
kono
parents:
diff changeset
332 while N >= D loop
kono
parents:
diff changeset
333 N := N - D;
kono
parents:
diff changeset
334 Fraction := Fraction + 1;
kono
parents:
diff changeset
335 Even := not Even;
kono
parents:
diff changeset
336 end loop;
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 -- Stop when the result is in [1.0 / Radix, 1.0)
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 exit when Fraction >= Most_Significant_Digit;
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 N := N * Radix;
kono
parents:
diff changeset
343 Fraction := Fraction * Radix;
kono
parents:
diff changeset
344 Even := True;
kono
parents:
diff changeset
345 end loop;
kono
parents:
diff changeset
346
kono
parents:
diff changeset
347 Release_And_Save (Uintp_Mark, Fraction, N);
kono
parents:
diff changeset
348 end Calculate_Fraction_And_N;
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 Calculate_Fraction_And_Exponent : begin
kono
parents:
diff changeset
351 Uintp_Mark := Mark;
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 -- Determine correct rounding based on the remainder which is in
kono
parents:
diff changeset
354 -- N and the divisor D. The rounding is performed on the absolute
kono
parents:
diff changeset
355 -- value of X, so Ceiling and Floor need to check for the sign of
kono
parents:
diff changeset
356 -- X explicitly.
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 case Mode is
kono
parents:
diff changeset
359 when Round_Even =>
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 -- This rounding mode corresponds to the unbiased rounding
kono
parents:
diff changeset
362 -- method that is used at run time. When the real value is
kono
parents:
diff changeset
363 -- exactly between two machine numbers, choose the machine
kono
parents:
diff changeset
364 -- number with its least significant bit equal to zero.
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 -- The recommendation advice in RM 4.9(38) is that static
kono
parents:
diff changeset
367 -- expressions are rounded to machine numbers in the same
kono
parents:
diff changeset
368 -- way as the target machine does.
kono
parents:
diff changeset
369
kono
parents:
diff changeset
370 if (Even and then N * 2 > D)
kono
parents:
diff changeset
371 or else
kono
parents:
diff changeset
372 (not Even and then N * 2 >= D)
kono
parents:
diff changeset
373 then
kono
parents:
diff changeset
374 Fraction := Fraction + 1;
kono
parents:
diff changeset
375 end if;
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 when Round =>
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 -- Do not round to even as is done with IEEE arithmetic, but
kono
parents:
diff changeset
380 -- instead round away from zero when the result is exactly
kono
parents:
diff changeset
381 -- between two machine numbers. This biased rounding method
kono
parents:
diff changeset
382 -- should not be used to convert static expressions to
kono
parents:
diff changeset
383 -- machine numbers, see AI95-268.
kono
parents:
diff changeset
384
kono
parents:
diff changeset
385 if N * 2 >= D then
kono
parents:
diff changeset
386 Fraction := Fraction + 1;
kono
parents:
diff changeset
387 end if;
kono
parents:
diff changeset
388
kono
parents:
diff changeset
389 when Ceiling =>
kono
parents:
diff changeset
390 if N > Uint_0 and then not UR_Is_Negative (X) then
kono
parents:
diff changeset
391 Fraction := Fraction + 1;
kono
parents:
diff changeset
392 end if;
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 when Floor =>
kono
parents:
diff changeset
395 if N > Uint_0 and then UR_Is_Negative (X) then
kono
parents:
diff changeset
396 Fraction := Fraction + 1;
kono
parents:
diff changeset
397 end if;
kono
parents:
diff changeset
398 end case;
kono
parents:
diff changeset
399
kono
parents:
diff changeset
400 -- The result must be normalized to [1.0/Radix, 1.0), so adjust if
kono
parents:
diff changeset
401 -- the result is 1.0 because of rounding.
kono
parents:
diff changeset
402
kono
parents:
diff changeset
403 if Fraction = Most_Significant_Digit * Radix then
kono
parents:
diff changeset
404 Fraction := Most_Significant_Digit;
kono
parents:
diff changeset
405 Exponent := Exponent + 1;
kono
parents:
diff changeset
406 end if;
kono
parents:
diff changeset
407
kono
parents:
diff changeset
408 -- Put back sign after applying the rounding
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 if UR_Is_Negative (X) then
kono
parents:
diff changeset
411 Fraction := -Fraction;
kono
parents:
diff changeset
412 end if;
kono
parents:
diff changeset
413
kono
parents:
diff changeset
414 Release_And_Save (Uintp_Mark, Fraction, Exponent);
kono
parents:
diff changeset
415 end Calculate_Fraction_And_Exponent;
kono
parents:
diff changeset
416 end Decompose_Int;
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 --------------
kono
parents:
diff changeset
419 -- Exponent --
kono
parents:
diff changeset
420 --------------
kono
parents:
diff changeset
421
kono
parents:
diff changeset
422 function Exponent (RT : R; X : T) return UI is
kono
parents:
diff changeset
423 X_Frac : UI;
kono
parents:
diff changeset
424 X_Exp : UI;
kono
parents:
diff changeset
425 pragma Warnings (Off, X_Frac);
kono
parents:
diff changeset
426 begin
kono
parents:
diff changeset
427 Decompose_Int (RT, X, X_Frac, X_Exp, Round_Even);
kono
parents:
diff changeset
428 return X_Exp;
kono
parents:
diff changeset
429 end Exponent;
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 -----------
kono
parents:
diff changeset
432 -- Floor --
kono
parents:
diff changeset
433 -----------
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 function Floor (RT : R; X : T) return T is
kono
parents:
diff changeset
436 XT : constant T := Truncation (RT, X);
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 begin
kono
parents:
diff changeset
439 if UR_Is_Positive (X) then
kono
parents:
diff changeset
440 return XT;
kono
parents:
diff changeset
441
kono
parents:
diff changeset
442 elsif XT = X then
kono
parents:
diff changeset
443 return X;
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 else
kono
parents:
diff changeset
446 return XT - Ureal_1;
kono
parents:
diff changeset
447 end if;
kono
parents:
diff changeset
448 end Floor;
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 --------------
kono
parents:
diff changeset
451 -- Fraction --
kono
parents:
diff changeset
452 --------------
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 function Fraction (RT : R; X : T) return T is
kono
parents:
diff changeset
455 X_Frac : T;
kono
parents:
diff changeset
456 X_Exp : UI;
kono
parents:
diff changeset
457 pragma Warnings (Off, X_Exp);
kono
parents:
diff changeset
458 begin
kono
parents:
diff changeset
459 Decompose (RT, X, X_Frac, X_Exp);
kono
parents:
diff changeset
460 return X_Frac;
kono
parents:
diff changeset
461 end Fraction;
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 ------------------
kono
parents:
diff changeset
464 -- Leading_Part --
kono
parents:
diff changeset
465 ------------------
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 function Leading_Part (RT : R; X : T; Radix_Digits : UI) return T is
kono
parents:
diff changeset
468 RD : constant UI := UI_Min (Radix_Digits, Machine_Mantissa_Value (RT));
kono
parents:
diff changeset
469 L : UI;
kono
parents:
diff changeset
470 Y : T;
kono
parents:
diff changeset
471 begin
kono
parents:
diff changeset
472 L := Exponent (RT, X) - RD;
kono
parents:
diff changeset
473 Y := UR_From_Uint (UR_Trunc (Scaling (RT, X, -L)));
kono
parents:
diff changeset
474 return Scaling (RT, Y, L);
kono
parents:
diff changeset
475 end Leading_Part;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 -------------
kono
parents:
diff changeset
478 -- Machine --
kono
parents:
diff changeset
479 -------------
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 function Machine
kono
parents:
diff changeset
482 (RT : R;
kono
parents:
diff changeset
483 X : T;
kono
parents:
diff changeset
484 Mode : Rounding_Mode;
kono
parents:
diff changeset
485 Enode : Node_Id) return T
kono
parents:
diff changeset
486 is
kono
parents:
diff changeset
487 X_Frac : T;
kono
parents:
diff changeset
488 X_Exp : UI;
kono
parents:
diff changeset
489 Emin : constant UI := Machine_Emin_Value (RT);
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 begin
kono
parents:
diff changeset
492 Decompose (RT, X, X_Frac, X_Exp, Mode);
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 -- Case of denormalized number or (gradual) underflow
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 -- A denormalized number is one with the minimum exponent Emin, but that
kono
parents:
diff changeset
497 -- breaks the assumption that the first digit of the mantissa is a one.
kono
parents:
diff changeset
498 -- This allows the first non-zero digit to be in any of the remaining
kono
parents:
diff changeset
499 -- Mant - 1 spots. The gap between subsequent denormalized numbers is
kono
parents:
diff changeset
500 -- the same as for the smallest normalized numbers. However, the number
kono
parents:
diff changeset
501 -- of significant digits left decreases as a result of the mantissa now
kono
parents:
diff changeset
502 -- having leading seros.
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 if X_Exp < Emin then
kono
parents:
diff changeset
505 declare
kono
parents:
diff changeset
506 Emin_Den : constant UI := Machine_Emin_Value (RT) -
kono
parents:
diff changeset
507 Machine_Mantissa_Value (RT) + Uint_1;
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 begin
kono
parents:
diff changeset
510 -- Do not issue warnings about underflows in GNATprove mode,
kono
parents:
diff changeset
511 -- as calling Machine as part of interval checking may lead
kono
parents:
diff changeset
512 -- to spurious warnings.
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 if X_Exp < Emin_Den or not Has_Denormals (RT) then
kono
parents:
diff changeset
515 if Has_Signed_Zeros (RT) and then UR_Is_Negative (X) then
kono
parents:
diff changeset
516 if not GNATprove_Mode then
kono
parents:
diff changeset
517 Error_Msg_N
kono
parents:
diff changeset
518 ("floating-point value underflows to -0.0??", Enode);
kono
parents:
diff changeset
519 end if;
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 return Ureal_M_0;
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 else
kono
parents:
diff changeset
524 if not GNATprove_Mode then
kono
parents:
diff changeset
525 Error_Msg_N
kono
parents:
diff changeset
526 ("floating-point value underflows to 0.0??", Enode);
kono
parents:
diff changeset
527 end if;
kono
parents:
diff changeset
528
kono
parents:
diff changeset
529 return Ureal_0;
kono
parents:
diff changeset
530 end if;
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 elsif Has_Denormals (RT) then
kono
parents:
diff changeset
533
kono
parents:
diff changeset
534 -- Emin - Mant <= X_Exp < Emin, so result is denormal. Handle
kono
parents:
diff changeset
535 -- gradual underflow by first computing the number of
kono
parents:
diff changeset
536 -- significant bits still available for the mantissa and
kono
parents:
diff changeset
537 -- then truncating the fraction to this number of bits.
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 -- If this value is different from the original fraction,
kono
parents:
diff changeset
540 -- precision is lost due to gradual underflow.
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 -- We probably should round here and prevent double rounding as
kono
parents:
diff changeset
543 -- a result of first rounding to a model number and then to a
kono
parents:
diff changeset
544 -- machine number. However, this is an extremely rare case that
kono
parents:
diff changeset
545 -- is not worth the extra complexity. In any case, a warning is
kono
parents:
diff changeset
546 -- issued in cases where gradual underflow occurs.
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 declare
kono
parents:
diff changeset
549 Denorm_Sig_Bits : constant UI := X_Exp - Emin_Den + 1;
kono
parents:
diff changeset
550
kono
parents:
diff changeset
551 X_Frac_Denorm : constant T := UR_From_Components
kono
parents:
diff changeset
552 (UR_Trunc (Scaling (RT, abs X_Frac, Denorm_Sig_Bits)),
kono
parents:
diff changeset
553 Denorm_Sig_Bits,
kono
parents:
diff changeset
554 Radix,
kono
parents:
diff changeset
555 UR_Is_Negative (X));
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 begin
kono
parents:
diff changeset
558 -- Do not issue warnings about loss of precision in
kono
parents:
diff changeset
559 -- GNATprove mode, as calling Machine as part of interval
kono
parents:
diff changeset
560 -- checking may lead to spurious warnings.
kono
parents:
diff changeset
561
kono
parents:
diff changeset
562 if X_Frac_Denorm /= X_Frac then
kono
parents:
diff changeset
563 if not GNATprove_Mode then
kono
parents:
diff changeset
564 Error_Msg_N
kono
parents:
diff changeset
565 ("gradual underflow causes loss of precision??",
kono
parents:
diff changeset
566 Enode);
kono
parents:
diff changeset
567 end if;
kono
parents:
diff changeset
568 X_Frac := X_Frac_Denorm;
kono
parents:
diff changeset
569 end if;
kono
parents:
diff changeset
570 end;
kono
parents:
diff changeset
571 end if;
kono
parents:
diff changeset
572 end;
kono
parents:
diff changeset
573 end if;
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 return Scaling (RT, X_Frac, X_Exp);
kono
parents:
diff changeset
576 end Machine;
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 -----------
kono
parents:
diff changeset
579 -- Model --
kono
parents:
diff changeset
580 -----------
kono
parents:
diff changeset
581
kono
parents:
diff changeset
582 function Model (RT : R; X : T) return T is
kono
parents:
diff changeset
583 X_Frac : T;
kono
parents:
diff changeset
584 X_Exp : UI;
kono
parents:
diff changeset
585 begin
kono
parents:
diff changeset
586 Decompose (RT, X, X_Frac, X_Exp);
kono
parents:
diff changeset
587 return Compose (RT, X_Frac, X_Exp);
kono
parents:
diff changeset
588 end Model;
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 ----------
kono
parents:
diff changeset
591 -- Pred --
kono
parents:
diff changeset
592 ----------
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 function Pred (RT : R; X : T) return T is
kono
parents:
diff changeset
595 begin
kono
parents:
diff changeset
596 return -Succ (RT, -X);
kono
parents:
diff changeset
597 end Pred;
kono
parents:
diff changeset
598
kono
parents:
diff changeset
599 ---------------
kono
parents:
diff changeset
600 -- Remainder --
kono
parents:
diff changeset
601 ---------------
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 function Remainder (RT : R; X, Y : T) return T is
kono
parents:
diff changeset
604 A : T;
kono
parents:
diff changeset
605 B : T;
kono
parents:
diff changeset
606 Arg : T;
kono
parents:
diff changeset
607 P : T;
kono
parents:
diff changeset
608 Arg_Frac : T;
kono
parents:
diff changeset
609 P_Frac : T;
kono
parents:
diff changeset
610 Sign_X : T;
kono
parents:
diff changeset
611 IEEE_Rem : T;
kono
parents:
diff changeset
612 Arg_Exp : UI;
kono
parents:
diff changeset
613 P_Exp : UI;
kono
parents:
diff changeset
614 K : UI;
kono
parents:
diff changeset
615 P_Even : Boolean;
kono
parents:
diff changeset
616
kono
parents:
diff changeset
617 pragma Warnings (Off, Arg_Frac);
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 begin
kono
parents:
diff changeset
620 if UR_Is_Positive (X) then
kono
parents:
diff changeset
621 Sign_X := Ureal_1;
kono
parents:
diff changeset
622 else
kono
parents:
diff changeset
623 Sign_X := -Ureal_1;
kono
parents:
diff changeset
624 end if;
kono
parents:
diff changeset
625
kono
parents:
diff changeset
626 Arg := abs X;
kono
parents:
diff changeset
627 P := abs Y;
kono
parents:
diff changeset
628
kono
parents:
diff changeset
629 if Arg < P then
kono
parents:
diff changeset
630 P_Even := True;
kono
parents:
diff changeset
631 IEEE_Rem := Arg;
kono
parents:
diff changeset
632 P_Exp := Exponent (RT, P);
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 else
kono
parents:
diff changeset
635 -- ??? what about zero cases?
kono
parents:
diff changeset
636 Decompose (RT, Arg, Arg_Frac, Arg_Exp);
kono
parents:
diff changeset
637 Decompose (RT, P, P_Frac, P_Exp);
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 P := Compose (RT, P_Frac, Arg_Exp);
kono
parents:
diff changeset
640 K := Arg_Exp - P_Exp;
kono
parents:
diff changeset
641 P_Even := True;
kono
parents:
diff changeset
642 IEEE_Rem := Arg;
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 for Cnt in reverse 0 .. UI_To_Int (K) loop
kono
parents:
diff changeset
645 if IEEE_Rem >= P then
kono
parents:
diff changeset
646 P_Even := False;
kono
parents:
diff changeset
647 IEEE_Rem := IEEE_Rem - P;
kono
parents:
diff changeset
648 else
kono
parents:
diff changeset
649 P_Even := True;
kono
parents:
diff changeset
650 end if;
kono
parents:
diff changeset
651
kono
parents:
diff changeset
652 P := P * Ureal_Half;
kono
parents:
diff changeset
653 end loop;
kono
parents:
diff changeset
654 end if;
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 -- That completes the calculation of modulus remainder. The final step
kono
parents:
diff changeset
657 -- is get the IEEE remainder. Here we compare Rem with (abs Y) / 2.
kono
parents:
diff changeset
658
kono
parents:
diff changeset
659 if P_Exp >= 0 then
kono
parents:
diff changeset
660 A := IEEE_Rem;
kono
parents:
diff changeset
661 B := abs Y * Ureal_Half;
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 else
kono
parents:
diff changeset
664 A := IEEE_Rem * Ureal_2;
kono
parents:
diff changeset
665 B := abs Y;
kono
parents:
diff changeset
666 end if;
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 if A > B or else (A = B and then not P_Even) then
kono
parents:
diff changeset
669 IEEE_Rem := IEEE_Rem - abs Y;
kono
parents:
diff changeset
670 end if;
kono
parents:
diff changeset
671
kono
parents:
diff changeset
672 return Sign_X * IEEE_Rem;
kono
parents:
diff changeset
673 end Remainder;
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 --------------
kono
parents:
diff changeset
676 -- Rounding --
kono
parents:
diff changeset
677 --------------
kono
parents:
diff changeset
678
kono
parents:
diff changeset
679 function Rounding (RT : R; X : T) return T is
kono
parents:
diff changeset
680 Result : T;
kono
parents:
diff changeset
681 Tail : T;
kono
parents:
diff changeset
682
kono
parents:
diff changeset
683 begin
kono
parents:
diff changeset
684 Result := Truncation (RT, abs X);
kono
parents:
diff changeset
685 Tail := abs X - Result;
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687 if Tail >= Ureal_Half then
kono
parents:
diff changeset
688 Result := Result + Ureal_1;
kono
parents:
diff changeset
689 end if;
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 if UR_Is_Negative (X) then
kono
parents:
diff changeset
692 return -Result;
kono
parents:
diff changeset
693 else
kono
parents:
diff changeset
694 return Result;
kono
parents:
diff changeset
695 end if;
kono
parents:
diff changeset
696 end Rounding;
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 -------------
kono
parents:
diff changeset
699 -- Scaling --
kono
parents:
diff changeset
700 -------------
kono
parents:
diff changeset
701
kono
parents:
diff changeset
702 function Scaling (RT : R; X : T; Adjustment : UI) return T is
kono
parents:
diff changeset
703 pragma Warnings (Off, RT);
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 begin
kono
parents:
diff changeset
706 if Rbase (X) = Radix then
kono
parents:
diff changeset
707 return UR_From_Components
kono
parents:
diff changeset
708 (Num => Numerator (X),
kono
parents:
diff changeset
709 Den => Denominator (X) - Adjustment,
kono
parents:
diff changeset
710 Rbase => Radix,
kono
parents:
diff changeset
711 Negative => UR_Is_Negative (X));
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 elsif Adjustment >= 0 then
kono
parents:
diff changeset
714 return X * Radix ** Adjustment;
kono
parents:
diff changeset
715 else
kono
parents:
diff changeset
716 return X / Radix ** (-Adjustment);
kono
parents:
diff changeset
717 end if;
kono
parents:
diff changeset
718 end Scaling;
kono
parents:
diff changeset
719
kono
parents:
diff changeset
720 ----------
kono
parents:
diff changeset
721 -- Succ --
kono
parents:
diff changeset
722 ----------
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 function Succ (RT : R; X : T) return T is
kono
parents:
diff changeset
725 Emin : constant UI := Machine_Emin_Value (RT);
kono
parents:
diff changeset
726 Mantissa : constant UI := Machine_Mantissa_Value (RT);
kono
parents:
diff changeset
727 Exp : UI := UI_Max (Emin, Exponent (RT, X));
kono
parents:
diff changeset
728 Frac : T;
kono
parents:
diff changeset
729 New_Frac : T;
kono
parents:
diff changeset
730
kono
parents:
diff changeset
731 begin
kono
parents:
diff changeset
732 if UR_Is_Zero (X) then
kono
parents:
diff changeset
733 Exp := Emin;
kono
parents:
diff changeset
734 end if;
kono
parents:
diff changeset
735
kono
parents:
diff changeset
736 -- Set exponent such that the radix point will be directly following the
kono
parents:
diff changeset
737 -- mantissa after scaling.
kono
parents:
diff changeset
738
kono
parents:
diff changeset
739 if Has_Denormals (RT) or Exp /= Emin then
kono
parents:
diff changeset
740 Exp := Exp - Mantissa;
kono
parents:
diff changeset
741 else
kono
parents:
diff changeset
742 Exp := Exp - 1;
kono
parents:
diff changeset
743 end if;
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 Frac := Scaling (RT, X, -Exp);
kono
parents:
diff changeset
746 New_Frac := Ceiling (RT, Frac);
kono
parents:
diff changeset
747
kono
parents:
diff changeset
748 if New_Frac = Frac then
kono
parents:
diff changeset
749 if New_Frac = Scaling (RT, -Ureal_1, Mantissa - 1) then
kono
parents:
diff changeset
750 New_Frac := New_Frac + Scaling (RT, Ureal_1, Uint_Minus_1);
kono
parents:
diff changeset
751 else
kono
parents:
diff changeset
752 New_Frac := New_Frac + Ureal_1;
kono
parents:
diff changeset
753 end if;
kono
parents:
diff changeset
754 end if;
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 return Scaling (RT, New_Frac, Exp);
kono
parents:
diff changeset
757 end Succ;
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 ----------------
kono
parents:
diff changeset
760 -- Truncation --
kono
parents:
diff changeset
761 ----------------
kono
parents:
diff changeset
762
kono
parents:
diff changeset
763 function Truncation (RT : R; X : T) return T is
kono
parents:
diff changeset
764 pragma Warnings (Off, RT);
kono
parents:
diff changeset
765 begin
kono
parents:
diff changeset
766 return UR_From_Uint (UR_Trunc (X));
kono
parents:
diff changeset
767 end Truncation;
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 -----------------------
kono
parents:
diff changeset
770 -- Unbiased_Rounding --
kono
parents:
diff changeset
771 -----------------------
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 function Unbiased_Rounding (RT : R; X : T) return T is
kono
parents:
diff changeset
774 Abs_X : constant T := abs X;
kono
parents:
diff changeset
775 Result : T;
kono
parents:
diff changeset
776 Tail : T;
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 begin
kono
parents:
diff changeset
779 Result := Truncation (RT, Abs_X);
kono
parents:
diff changeset
780 Tail := Abs_X - Result;
kono
parents:
diff changeset
781
kono
parents:
diff changeset
782 if Tail > Ureal_Half then
kono
parents:
diff changeset
783 Result := Result + Ureal_1;
kono
parents:
diff changeset
784
kono
parents:
diff changeset
785 elsif Tail = Ureal_Half then
kono
parents:
diff changeset
786 Result := Ureal_2 *
kono
parents:
diff changeset
787 Truncation (RT, (Result / Ureal_2) + Ureal_Half);
kono
parents:
diff changeset
788 end if;
kono
parents:
diff changeset
789
kono
parents:
diff changeset
790 if UR_Is_Negative (X) then
kono
parents:
diff changeset
791 return -Result;
kono
parents:
diff changeset
792 elsif UR_Is_Positive (X) then
kono
parents:
diff changeset
793 return Result;
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 -- For zero case, make sure sign of zero is preserved
kono
parents:
diff changeset
796
kono
parents:
diff changeset
797 else
kono
parents:
diff changeset
798 return X;
kono
parents:
diff changeset
799 end if;
kono
parents:
diff changeset
800 end Unbiased_Rounding;
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 end Eval_Fat;