annotate gcc/ada/libgnat/s-imgrea.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 RUN-TIME COMPONENTS --
kono
parents:
diff changeset
4 -- --
kono
parents:
diff changeset
5 -- S Y S T E M . I M G _ R E A L --
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. --
kono
parents:
diff changeset
17 -- --
kono
parents:
diff changeset
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
kono
parents:
diff changeset
19 -- additional permissions described in the GCC Runtime Library Exception, --
kono
parents:
diff changeset
20 -- version 3.1, as published by the Free Software Foundation. --
kono
parents:
diff changeset
21 -- --
kono
parents:
diff changeset
22 -- You should have received a copy of the GNU General Public License and --
kono
parents:
diff changeset
23 -- a copy of the GCC Runtime Library Exception along with this program; --
kono
parents:
diff changeset
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
kono
parents:
diff changeset
25 -- <http://www.gnu.org/licenses/>. --
kono
parents:
diff changeset
26 -- --
kono
parents:
diff changeset
27 -- GNAT was originally developed by the GNAT team at New York University. --
kono
parents:
diff changeset
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
kono
parents:
diff changeset
29 -- --
kono
parents:
diff changeset
30 ------------------------------------------------------------------------------
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 with System.Img_LLU; use System.Img_LLU;
kono
parents:
diff changeset
33 with System.Img_Uns; use System.Img_Uns;
kono
parents:
diff changeset
34 with System.Powten_Table; use System.Powten_Table;
kono
parents:
diff changeset
35 with System.Unsigned_Types; use System.Unsigned_Types;
kono
parents:
diff changeset
36 with System.Float_Control;
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 package body System.Img_Real is
kono
parents:
diff changeset
39
kono
parents:
diff changeset
40 -- The following defines the maximum number of digits that we can convert
kono
parents:
diff changeset
41 -- accurately. This is limited by the precision of Long_Long_Float, and
kono
parents:
diff changeset
42 -- also by the number of digits we can hold in Long_Long_Unsigned, which
kono
parents:
diff changeset
43 -- is the integer type we use as an intermediate for the result.
kono
parents:
diff changeset
44
kono
parents:
diff changeset
45 -- We assume that in practice, the limitation will come from the digits
kono
parents:
diff changeset
46 -- value, rather than the integer value. This is true for typical IEEE
kono
parents:
diff changeset
47 -- implementations, and at worst, the only loss is for some precision
kono
parents:
diff changeset
48 -- in very high precision floating-point output.
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 -- Note that in the following, the "-2" accounts for the sign and one
kono
parents:
diff changeset
51 -- extra digits, since we need the maximum number of 9's that can be
kono
parents:
diff changeset
52 -- supported, e.g. for the normal 64 bit case, Long_Long_Integer'Width
kono
parents:
diff changeset
53 -- is 21, since the maximum value (approx 1.6 * 10**19) has 20 digits,
kono
parents:
diff changeset
54 -- but the maximum number of 9's that can be supported is 19.
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 Maxdigs : constant :=
kono
parents:
diff changeset
57 Natural'Min
kono
parents:
diff changeset
58 (Long_Long_Unsigned'Width - 2, Long_Long_Float'Digits);
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 Unsdigs : constant := Unsigned'Width - 2;
kono
parents:
diff changeset
61 -- Number of digits that can be converted using type Unsigned
kono
parents:
diff changeset
62 -- See above for the explanation of the -2.
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 Maxscaling : constant := 5000;
kono
parents:
diff changeset
65 -- Max decimal scaling required during conversion of floating-point
kono
parents:
diff changeset
66 -- numbers to decimal. This is used to defend against infinite
kono
parents:
diff changeset
67 -- looping in the conversion, as can be caused by erroneous executions.
kono
parents:
diff changeset
68 -- The largest exponent used on any current system is 2**16383, which
kono
parents:
diff changeset
69 -- is approximately 10**4932, and the highest number of decimal digits
kono
parents:
diff changeset
70 -- is about 35 for 128-bit floating-point formats, so 5000 leaves
kono
parents:
diff changeset
71 -- enough room for scaling such values
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 function Is_Negative (V : Long_Long_Float) return Boolean;
kono
parents:
diff changeset
74 pragma Import (Intrinsic, Is_Negative);
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 --------------------------
kono
parents:
diff changeset
77 -- Image_Floating_Point --
kono
parents:
diff changeset
78 --------------------------
kono
parents:
diff changeset
79
kono
parents:
diff changeset
80 procedure Image_Floating_Point
kono
parents:
diff changeset
81 (V : Long_Long_Float;
kono
parents:
diff changeset
82 S : in out String;
kono
parents:
diff changeset
83 P : out Natural;
kono
parents:
diff changeset
84 Digs : Natural)
kono
parents:
diff changeset
85 is
kono
parents:
diff changeset
86 pragma Assert (S'First = 1);
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 begin
kono
parents:
diff changeset
89 -- Decide whether a blank should be prepended before the call to
kono
parents:
diff changeset
90 -- Set_Image_Real. We generate a blank for positive values, and
kono
parents:
diff changeset
91 -- also for positive zeroes. For negative zeroes, we generate a
kono
parents:
diff changeset
92 -- space only if Signed_Zeroes is True (the RM only permits the
kono
parents:
diff changeset
93 -- output of -0.0 on targets where this is the case). We can of
kono
parents:
diff changeset
94 -- course still see a -0.0 on a target where Signed_Zeroes is
kono
parents:
diff changeset
95 -- False (since this attribute refers to the proper handling of
kono
parents:
diff changeset
96 -- negative zeroes, not to their existence). We do not generate
kono
parents:
diff changeset
97 -- a blank for positive infinity, since we output an explicit +.
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 if (not Is_Negative (V) and then V <= Long_Long_Float'Last)
kono
parents:
diff changeset
100 or else (not Long_Long_Float'Signed_Zeros and then V = -0.0)
kono
parents:
diff changeset
101 then
kono
parents:
diff changeset
102 S (1) := ' ';
kono
parents:
diff changeset
103 P := 1;
kono
parents:
diff changeset
104 else
kono
parents:
diff changeset
105 P := 0;
kono
parents:
diff changeset
106 end if;
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 Set_Image_Real (V, S, P, 1, Digs - 1, 3);
kono
parents:
diff changeset
109 end Image_Floating_Point;
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 --------------------------------
kono
parents:
diff changeset
112 -- Image_Ordinary_Fixed_Point --
kono
parents:
diff changeset
113 --------------------------------
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 procedure Image_Ordinary_Fixed_Point
kono
parents:
diff changeset
116 (V : Long_Long_Float;
kono
parents:
diff changeset
117 S : in out String;
kono
parents:
diff changeset
118 P : out Natural;
kono
parents:
diff changeset
119 Aft : Natural)
kono
parents:
diff changeset
120 is
kono
parents:
diff changeset
121 pragma Assert (S'First = 1);
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 begin
kono
parents:
diff changeset
124 -- Output space at start if non-negative
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 if V >= 0.0 then
kono
parents:
diff changeset
127 S (1) := ' ';
kono
parents:
diff changeset
128 P := 1;
kono
parents:
diff changeset
129 else
kono
parents:
diff changeset
130 P := 0;
kono
parents:
diff changeset
131 end if;
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 Set_Image_Real (V, S, P, 1, Aft, 0);
kono
parents:
diff changeset
134 end Image_Ordinary_Fixed_Point;
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 --------------------
kono
parents:
diff changeset
137 -- Set_Image_Real --
kono
parents:
diff changeset
138 --------------------
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 procedure Set_Image_Real
kono
parents:
diff changeset
141 (V : Long_Long_Float;
kono
parents:
diff changeset
142 S : out String;
kono
parents:
diff changeset
143 P : in out Natural;
kono
parents:
diff changeset
144 Fore : Natural;
kono
parents:
diff changeset
145 Aft : Natural;
kono
parents:
diff changeset
146 Exp : Natural)
kono
parents:
diff changeset
147 is
kono
parents:
diff changeset
148 NFrac : constant Natural := Natural'Max (Aft, 1);
kono
parents:
diff changeset
149 Sign : Character;
kono
parents:
diff changeset
150 X : Long_Long_Float;
kono
parents:
diff changeset
151 Scale : Integer;
kono
parents:
diff changeset
152 Expon : Integer;
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 Field_Max : constant := 255;
kono
parents:
diff changeset
155 -- This should be the same value as Ada.[Wide_]Text_IO.Field'Last.
kono
parents:
diff changeset
156 -- It is not worth dragging in Ada.Text_IO to pick up this value,
kono
parents:
diff changeset
157 -- since it really should never be necessary to change it.
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 Digs : String (1 .. 2 * Field_Max + 16);
kono
parents:
diff changeset
160 -- Array used to hold digits of converted integer value. This is a
kono
parents:
diff changeset
161 -- large enough buffer to accommodate ludicrous values of Fore and Aft.
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 Ndigs : Natural;
kono
parents:
diff changeset
164 -- Number of digits stored in Digs (and also subscript of last digit)
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 procedure Adjust_Scale (S : Natural);
kono
parents:
diff changeset
167 -- Adjusts the value in X by multiplying or dividing by a power of
kono
parents:
diff changeset
168 -- ten so that it is in the range 10**(S-1) <= X < 10**S. Includes
kono
parents:
diff changeset
169 -- adding 0.5 to round the result, readjusting if the rounding causes
kono
parents:
diff changeset
170 -- the result to wander out of the range. Scale is adjusted to reflect
kono
parents:
diff changeset
171 -- the power of ten used to divide the result (i.e. one is added to
kono
parents:
diff changeset
172 -- the scale value for each division by 10.0, or one is subtracted
kono
parents:
diff changeset
173 -- for each multiplication by 10.0).
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 procedure Convert_Integer;
kono
parents:
diff changeset
176 -- Takes the value in X, outputs integer digits into Digs. On return,
kono
parents:
diff changeset
177 -- Ndigs is set to the number of digits stored. The digits are stored
kono
parents:
diff changeset
178 -- in Digs (1 .. Ndigs),
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 procedure Set (C : Character);
kono
parents:
diff changeset
181 -- Sets character C in output buffer
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 procedure Set_Blanks_And_Sign (N : Integer);
kono
parents:
diff changeset
184 -- Sets leading blanks and minus sign if needed. N is the number of
kono
parents:
diff changeset
185 -- positions to be filled (a minus sign is output even if N is zero
kono
parents:
diff changeset
186 -- or negative, but for a positive value, if N is non-positive, then
kono
parents:
diff changeset
187 -- the call has no effect).
kono
parents:
diff changeset
188
kono
parents:
diff changeset
189 procedure Set_Digs (S, E : Natural);
kono
parents:
diff changeset
190 -- Set digits S through E from Digs buffer. No effect if S > E
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 procedure Set_Special_Fill (N : Natural);
kono
parents:
diff changeset
193 -- After outputting +Inf, -Inf or NaN, this routine fills out the
kono
parents:
diff changeset
194 -- rest of the field with * characters. The argument is the number
kono
parents:
diff changeset
195 -- of characters output so far (either 3 or 4)
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 procedure Set_Zeros (N : Integer);
kono
parents:
diff changeset
198 -- Set N zeros, no effect if N is negative
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 pragma Inline (Set);
kono
parents:
diff changeset
201 pragma Inline (Set_Digs);
kono
parents:
diff changeset
202 pragma Inline (Set_Zeros);
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 ------------------
kono
parents:
diff changeset
205 -- Adjust_Scale --
kono
parents:
diff changeset
206 ------------------
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 procedure Adjust_Scale (S : Natural) is
kono
parents:
diff changeset
209 Lo : Natural;
kono
parents:
diff changeset
210 Hi : Natural;
kono
parents:
diff changeset
211 Mid : Natural;
kono
parents:
diff changeset
212 XP : Long_Long_Float;
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 begin
kono
parents:
diff changeset
215 -- Cases where scaling up is required
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 if X < Powten (S - 1) then
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 -- What we are looking for is a power of ten to multiply X by
kono
parents:
diff changeset
220 -- so that the result lies within the required range.
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 loop
kono
parents:
diff changeset
223 XP := X * Powten (Maxpow);
kono
parents:
diff changeset
224 exit when XP >= Powten (S - 1) or else Scale < -Maxscaling;
kono
parents:
diff changeset
225 X := XP;
kono
parents:
diff changeset
226 Scale := Scale - Maxpow;
kono
parents:
diff changeset
227 end loop;
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 -- The following exception is only raised in case of erroneous
kono
parents:
diff changeset
230 -- execution, where a number was considered valid but still
kono
parents:
diff changeset
231 -- fails to scale up. One situation where this can happen is
kono
parents:
diff changeset
232 -- when a system which is supposed to be IEEE-compliant, but
kono
parents:
diff changeset
233 -- has been reconfigured to flush denormals to zero.
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235 if Scale < -Maxscaling then
kono
parents:
diff changeset
236 raise Constraint_Error;
kono
parents:
diff changeset
237 end if;
kono
parents:
diff changeset
238
kono
parents:
diff changeset
239 -- Here we know that we must multiply by at least 10**1 and that
kono
parents:
diff changeset
240 -- 10**Maxpow takes us too far: binary search to find right one.
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 -- Because of roundoff errors, it is possible for the value
kono
parents:
diff changeset
243 -- of XP to be just outside of the interval when Lo >= Hi. In
kono
parents:
diff changeset
244 -- that case we adjust explicitly by a factor of 10. This
kono
parents:
diff changeset
245 -- can only happen with a value that is very close to an
kono
parents:
diff changeset
246 -- exact power of 10.
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 Lo := 1;
kono
parents:
diff changeset
249 Hi := Maxpow;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 loop
kono
parents:
diff changeset
252 Mid := (Lo + Hi) / 2;
kono
parents:
diff changeset
253 XP := X * Powten (Mid);
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 if XP < Powten (S - 1) then
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 if Lo >= Hi then
kono
parents:
diff changeset
258 Mid := Mid + 1;
kono
parents:
diff changeset
259 XP := XP * 10.0;
kono
parents:
diff changeset
260 exit;
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 else
kono
parents:
diff changeset
263 Lo := Mid + 1;
kono
parents:
diff changeset
264 end if;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 elsif XP >= Powten (S) then
kono
parents:
diff changeset
267
kono
parents:
diff changeset
268 if Lo >= Hi then
kono
parents:
diff changeset
269 Mid := Mid - 1;
kono
parents:
diff changeset
270 XP := XP / 10.0;
kono
parents:
diff changeset
271 exit;
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 else
kono
parents:
diff changeset
274 Hi := Mid - 1;
kono
parents:
diff changeset
275 end if;
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 else
kono
parents:
diff changeset
278 exit;
kono
parents:
diff changeset
279 end if;
kono
parents:
diff changeset
280 end loop;
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 X := XP;
kono
parents:
diff changeset
283 Scale := Scale - Mid;
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 -- Cases where scaling down is required
kono
parents:
diff changeset
286
kono
parents:
diff changeset
287 elsif X >= Powten (S) then
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 -- What we are looking for is a power of ten to divide X by
kono
parents:
diff changeset
290 -- so that the result lies within the required range.
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 loop
kono
parents:
diff changeset
293 XP := X / Powten (Maxpow);
kono
parents:
diff changeset
294 exit when XP < Powten (S) or else Scale > Maxscaling;
kono
parents:
diff changeset
295 X := XP;
kono
parents:
diff changeset
296 Scale := Scale + Maxpow;
kono
parents:
diff changeset
297 end loop;
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 -- The following exception is only raised in case of erroneous
kono
parents:
diff changeset
300 -- execution, where a number was considered valid but still
kono
parents:
diff changeset
301 -- fails to scale up. One situation where this can happen is
kono
parents:
diff changeset
302 -- when a system which is supposed to be IEEE-compliant, but
kono
parents:
diff changeset
303 -- has been reconfigured to flush denormals to zero.
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 if Scale > Maxscaling then
kono
parents:
diff changeset
306 raise Constraint_Error;
kono
parents:
diff changeset
307 end if;
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 -- Here we know that we must divide by at least 10**1 and that
kono
parents:
diff changeset
310 -- 10**Maxpow takes us too far, binary search to find right one.
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 Lo := 1;
kono
parents:
diff changeset
313 Hi := Maxpow;
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 loop
kono
parents:
diff changeset
316 Mid := (Lo + Hi) / 2;
kono
parents:
diff changeset
317 XP := X / Powten (Mid);
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 if XP < Powten (S - 1) then
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 if Lo >= Hi then
kono
parents:
diff changeset
322 XP := XP * 10.0;
kono
parents:
diff changeset
323 Mid := Mid - 1;
kono
parents:
diff changeset
324 exit;
kono
parents:
diff changeset
325
kono
parents:
diff changeset
326 else
kono
parents:
diff changeset
327 Hi := Mid - 1;
kono
parents:
diff changeset
328 end if;
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 elsif XP >= Powten (S) then
kono
parents:
diff changeset
331
kono
parents:
diff changeset
332 if Lo >= Hi then
kono
parents:
diff changeset
333 XP := XP / 10.0;
kono
parents:
diff changeset
334 Mid := Mid + 1;
kono
parents:
diff changeset
335 exit;
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 else
kono
parents:
diff changeset
338 Lo := Mid + 1;
kono
parents:
diff changeset
339 end if;
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 else
kono
parents:
diff changeset
342 exit;
kono
parents:
diff changeset
343 end if;
kono
parents:
diff changeset
344 end loop;
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 X := XP;
kono
parents:
diff changeset
347 Scale := Scale + Mid;
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349 -- Here we are already scaled right
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 else
kono
parents:
diff changeset
352 null;
kono
parents:
diff changeset
353 end if;
kono
parents:
diff changeset
354
kono
parents:
diff changeset
355 -- Round, readjusting scale if needed. Note that if a readjustment
kono
parents:
diff changeset
356 -- occurs, then it is never necessary to round again, because there
kono
parents:
diff changeset
357 -- is no possibility of such a second rounding causing a change.
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 X := X + 0.5;
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 if X >= Powten (S) then
kono
parents:
diff changeset
362 X := X / 10.0;
kono
parents:
diff changeset
363 Scale := Scale + 1;
kono
parents:
diff changeset
364 end if;
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 end Adjust_Scale;
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 ---------------------
kono
parents:
diff changeset
369 -- Convert_Integer --
kono
parents:
diff changeset
370 ---------------------
kono
parents:
diff changeset
371
kono
parents:
diff changeset
372 procedure Convert_Integer is
kono
parents:
diff changeset
373 begin
kono
parents:
diff changeset
374 -- Use Unsigned routine if possible, since on many machines it will
kono
parents:
diff changeset
375 -- be significantly more efficient than the Long_Long_Unsigned one.
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 if X < Powten (Unsdigs) then
kono
parents:
diff changeset
378 Ndigs := 0;
kono
parents:
diff changeset
379 Set_Image_Unsigned
kono
parents:
diff changeset
380 (Unsigned (Long_Long_Float'Truncation (X)),
kono
parents:
diff changeset
381 Digs, Ndigs);
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 -- But if we want more digits than fit in Unsigned, we have to use
kono
parents:
diff changeset
384 -- the Long_Long_Unsigned routine after all.
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 else
kono
parents:
diff changeset
387 Ndigs := 0;
kono
parents:
diff changeset
388 Set_Image_Long_Long_Unsigned
kono
parents:
diff changeset
389 (Long_Long_Unsigned (Long_Long_Float'Truncation (X)),
kono
parents:
diff changeset
390 Digs, Ndigs);
kono
parents:
diff changeset
391 end if;
kono
parents:
diff changeset
392 end Convert_Integer;
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 ---------
kono
parents:
diff changeset
395 -- Set --
kono
parents:
diff changeset
396 ---------
kono
parents:
diff changeset
397
kono
parents:
diff changeset
398 procedure Set (C : Character) is
kono
parents:
diff changeset
399 begin
kono
parents:
diff changeset
400 P := P + 1;
kono
parents:
diff changeset
401 S (P) := C;
kono
parents:
diff changeset
402 end Set;
kono
parents:
diff changeset
403
kono
parents:
diff changeset
404 -------------------------
kono
parents:
diff changeset
405 -- Set_Blanks_And_Sign --
kono
parents:
diff changeset
406 -------------------------
kono
parents:
diff changeset
407
kono
parents:
diff changeset
408 procedure Set_Blanks_And_Sign (N : Integer) is
kono
parents:
diff changeset
409 begin
kono
parents:
diff changeset
410 if Sign = '-' then
kono
parents:
diff changeset
411 for J in 1 .. N - 1 loop
kono
parents:
diff changeset
412 Set (' ');
kono
parents:
diff changeset
413 end loop;
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 Set ('-');
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 else
kono
parents:
diff changeset
418 for J in 1 .. N loop
kono
parents:
diff changeset
419 Set (' ');
kono
parents:
diff changeset
420 end loop;
kono
parents:
diff changeset
421 end if;
kono
parents:
diff changeset
422 end Set_Blanks_And_Sign;
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 --------------
kono
parents:
diff changeset
425 -- Set_Digs --
kono
parents:
diff changeset
426 --------------
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 procedure Set_Digs (S, E : Natural) is
kono
parents:
diff changeset
429 begin
kono
parents:
diff changeset
430 for J in S .. E loop
kono
parents:
diff changeset
431 Set (Digs (J));
kono
parents:
diff changeset
432 end loop;
kono
parents:
diff changeset
433 end Set_Digs;
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 ----------------------
kono
parents:
diff changeset
436 -- Set_Special_Fill --
kono
parents:
diff changeset
437 ----------------------
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 procedure Set_Special_Fill (N : Natural) is
kono
parents:
diff changeset
440 F : Natural;
kono
parents:
diff changeset
441
kono
parents:
diff changeset
442 begin
kono
parents:
diff changeset
443 F := Fore + 1 + Aft - N;
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 if Exp /= 0 then
kono
parents:
diff changeset
446 F := F + Exp + 1;
kono
parents:
diff changeset
447 end if;
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 for J in 1 .. F loop
kono
parents:
diff changeset
450 Set ('*');
kono
parents:
diff changeset
451 end loop;
kono
parents:
diff changeset
452 end Set_Special_Fill;
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 ---------------
kono
parents:
diff changeset
455 -- Set_Zeros --
kono
parents:
diff changeset
456 ---------------
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 procedure Set_Zeros (N : Integer) is
kono
parents:
diff changeset
459 begin
kono
parents:
diff changeset
460 for J in 1 .. N loop
kono
parents:
diff changeset
461 Set ('0');
kono
parents:
diff changeset
462 end loop;
kono
parents:
diff changeset
463 end Set_Zeros;
kono
parents:
diff changeset
464
kono
parents:
diff changeset
465 -- Start of processing for Set_Image_Real
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 begin
kono
parents:
diff changeset
468 -- We call the floating-point processor reset routine so that we can
kono
parents:
diff changeset
469 -- be sure the floating-point processor is properly set for conversion
kono
parents:
diff changeset
470 -- calls. This is notably need on Windows, where calls to the operating
kono
parents:
diff changeset
471 -- system randomly reset the processor into 64-bit mode.
kono
parents:
diff changeset
472
kono
parents:
diff changeset
473 System.Float_Control.Reset;
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 Scale := 0;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 -- Deal with invalid values first,
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 if not V'Valid then
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 -- Note that we're taking our chances here, as V might be
kono
parents:
diff changeset
482 -- an invalid bit pattern resulting from erroneous execution
kono
parents:
diff changeset
483 -- (caused by using uninitialized variables for example).
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 -- No matter what, we'll at least get reasonable behavior,
kono
parents:
diff changeset
486 -- converting to infinity or some other value, or causing an
kono
parents:
diff changeset
487 -- exception to be raised is fine.
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 -- If the following test succeeds, then we definitely have
kono
parents:
diff changeset
490 -- an infinite value, so we print Inf.
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 if V > Long_Long_Float'Last then
kono
parents:
diff changeset
493 Set ('+');
kono
parents:
diff changeset
494 Set ('I');
kono
parents:
diff changeset
495 Set ('n');
kono
parents:
diff changeset
496 Set ('f');
kono
parents:
diff changeset
497 Set_Special_Fill (4);
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 -- In all other cases we print NaN
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 elsif V < Long_Long_Float'First then
kono
parents:
diff changeset
502 Set ('-');
kono
parents:
diff changeset
503 Set ('I');
kono
parents:
diff changeset
504 Set ('n');
kono
parents:
diff changeset
505 Set ('f');
kono
parents:
diff changeset
506 Set_Special_Fill (4);
kono
parents:
diff changeset
507
kono
parents:
diff changeset
508 else
kono
parents:
diff changeset
509 Set ('N');
kono
parents:
diff changeset
510 Set ('a');
kono
parents:
diff changeset
511 Set ('N');
kono
parents:
diff changeset
512 Set_Special_Fill (3);
kono
parents:
diff changeset
513 end if;
kono
parents:
diff changeset
514
kono
parents:
diff changeset
515 return;
kono
parents:
diff changeset
516 end if;
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 -- Positive values
kono
parents:
diff changeset
519
kono
parents:
diff changeset
520 if V > 0.0 then
kono
parents:
diff changeset
521 X := V;
kono
parents:
diff changeset
522 Sign := '+';
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 -- Negative values
kono
parents:
diff changeset
525
kono
parents:
diff changeset
526 elsif V < 0.0 then
kono
parents:
diff changeset
527 X := -V;
kono
parents:
diff changeset
528 Sign := '-';
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 -- Zero values
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 elsif V = 0.0 then
kono
parents:
diff changeset
533 if Long_Long_Float'Signed_Zeros and then Is_Negative (V) then
kono
parents:
diff changeset
534 Sign := '-';
kono
parents:
diff changeset
535 else
kono
parents:
diff changeset
536 Sign := '+';
kono
parents:
diff changeset
537 end if;
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 Set_Blanks_And_Sign (Fore - 1);
kono
parents:
diff changeset
540 Set ('0');
kono
parents:
diff changeset
541 Set ('.');
kono
parents:
diff changeset
542 Set_Zeros (NFrac);
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 if Exp /= 0 then
kono
parents:
diff changeset
545 Set ('E');
kono
parents:
diff changeset
546 Set ('+');
kono
parents:
diff changeset
547 Set_Zeros (Natural'Max (1, Exp - 1));
kono
parents:
diff changeset
548 end if;
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 return;
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 else
kono
parents:
diff changeset
553 -- It should not be possible for a NaN to end up here.
kono
parents:
diff changeset
554 -- Either the 'Valid test has failed, or we have some form
kono
parents:
diff changeset
555 -- of erroneous execution. Raise Constraint_Error instead of
kono
parents:
diff changeset
556 -- attempting to go ahead printing the value.
kono
parents:
diff changeset
557
kono
parents:
diff changeset
558 raise Constraint_Error;
kono
parents:
diff changeset
559 end if;
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 -- X and Sign are set here, and X is known to be a valid,
kono
parents:
diff changeset
562 -- non-zero floating-point number.
kono
parents:
diff changeset
563
kono
parents:
diff changeset
564 -- Case of non-zero value with Exp = 0
kono
parents:
diff changeset
565
kono
parents:
diff changeset
566 if Exp = 0 then
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 -- First step is to multiply by 10 ** Nfrac to get an integer
kono
parents:
diff changeset
569 -- value to be output, an then add 0.5 to round the result.
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 declare
kono
parents:
diff changeset
572 NF : Natural := NFrac;
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 begin
kono
parents:
diff changeset
575 loop
kono
parents:
diff changeset
576 -- If we are larger than Powten (Maxdigs) now, then
kono
parents:
diff changeset
577 -- we have too many significant digits, and we have
kono
parents:
diff changeset
578 -- not even finished multiplying by NFrac (NF shows
kono
parents:
diff changeset
579 -- the number of unaccounted-for digits).
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 if X >= Powten (Maxdigs) then
kono
parents:
diff changeset
582
kono
parents:
diff changeset
583 -- In this situation, we only to generate a reasonable
kono
parents:
diff changeset
584 -- number of significant digits, and then zeroes after.
kono
parents:
diff changeset
585 -- So first we rescale to get:
kono
parents:
diff changeset
586
kono
parents:
diff changeset
587 -- 10 ** (Maxdigs - 1) <= X < 10 ** Maxdigs
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 -- and then convert the resulting integer
kono
parents:
diff changeset
590
kono
parents:
diff changeset
591 Adjust_Scale (Maxdigs);
kono
parents:
diff changeset
592 Convert_Integer;
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 -- If that caused rescaling, then add zeros to the end
kono
parents:
diff changeset
595 -- of the number to account for this scaling. Also add
kono
parents:
diff changeset
596 -- zeroes to account for the undone multiplications
kono
parents:
diff changeset
597
kono
parents:
diff changeset
598 for J in 1 .. Scale + NF loop
kono
parents:
diff changeset
599 Ndigs := Ndigs + 1;
kono
parents:
diff changeset
600 Digs (Ndigs) := '0';
kono
parents:
diff changeset
601 end loop;
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 exit;
kono
parents:
diff changeset
604
kono
parents:
diff changeset
605 -- If multiplication is complete, then convert the resulting
kono
parents:
diff changeset
606 -- integer after rounding (note that X is non-negative)
kono
parents:
diff changeset
607
kono
parents:
diff changeset
608 elsif NF = 0 then
kono
parents:
diff changeset
609 X := X + 0.5;
kono
parents:
diff changeset
610 Convert_Integer;
kono
parents:
diff changeset
611 exit;
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 -- Otherwise we can go ahead with the multiplication. If it
kono
parents:
diff changeset
614 -- can be done in one step, then do it in one step.
kono
parents:
diff changeset
615
kono
parents:
diff changeset
616 elsif NF < Maxpow then
kono
parents:
diff changeset
617 X := X * Powten (NF);
kono
parents:
diff changeset
618 NF := 0;
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 -- If it cannot be done in one step, then do partial scaling
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 else
kono
parents:
diff changeset
623 X := X * Powten (Maxpow);
kono
parents:
diff changeset
624 NF := NF - Maxpow;
kono
parents:
diff changeset
625 end if;
kono
parents:
diff changeset
626 end loop;
kono
parents:
diff changeset
627 end;
kono
parents:
diff changeset
628
kono
parents:
diff changeset
629 -- If number of available digits is less or equal to NFrac,
kono
parents:
diff changeset
630 -- then we need an extra zero before the decimal point.
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 if Ndigs <= NFrac then
kono
parents:
diff changeset
633 Set_Blanks_And_Sign (Fore - 1);
kono
parents:
diff changeset
634 Set ('0');
kono
parents:
diff changeset
635 Set ('.');
kono
parents:
diff changeset
636 Set_Zeros (NFrac - Ndigs);
kono
parents:
diff changeset
637 Set_Digs (1, Ndigs);
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 -- Normal case with some digits before the decimal point
kono
parents:
diff changeset
640
kono
parents:
diff changeset
641 else
kono
parents:
diff changeset
642 Set_Blanks_And_Sign (Fore - (Ndigs - NFrac));
kono
parents:
diff changeset
643 Set_Digs (1, Ndigs - NFrac);
kono
parents:
diff changeset
644 Set ('.');
kono
parents:
diff changeset
645 Set_Digs (Ndigs - NFrac + 1, Ndigs);
kono
parents:
diff changeset
646 end if;
kono
parents:
diff changeset
647
kono
parents:
diff changeset
648 -- Case of non-zero value with non-zero Exp value
kono
parents:
diff changeset
649
kono
parents:
diff changeset
650 else
kono
parents:
diff changeset
651 -- If NFrac is less than Maxdigs, then all the fraction digits are
kono
parents:
diff changeset
652 -- significant, so we can scale the resulting integer accordingly.
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 if NFrac < Maxdigs then
kono
parents:
diff changeset
655 Adjust_Scale (NFrac + 1);
kono
parents:
diff changeset
656 Convert_Integer;
kono
parents:
diff changeset
657
kono
parents:
diff changeset
658 -- Otherwise, we get the maximum number of digits available
kono
parents:
diff changeset
659
kono
parents:
diff changeset
660 else
kono
parents:
diff changeset
661 Adjust_Scale (Maxdigs);
kono
parents:
diff changeset
662 Convert_Integer;
kono
parents:
diff changeset
663
kono
parents:
diff changeset
664 for J in 1 .. NFrac - Maxdigs + 1 loop
kono
parents:
diff changeset
665 Ndigs := Ndigs + 1;
kono
parents:
diff changeset
666 Digs (Ndigs) := '0';
kono
parents:
diff changeset
667 Scale := Scale - 1;
kono
parents:
diff changeset
668 end loop;
kono
parents:
diff changeset
669 end if;
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 Set_Blanks_And_Sign (Fore - 1);
kono
parents:
diff changeset
672 Set (Digs (1));
kono
parents:
diff changeset
673 Set ('.');
kono
parents:
diff changeset
674 Set_Digs (2, Ndigs);
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 -- The exponent is the scaling factor adjusted for the digits
kono
parents:
diff changeset
677 -- that we output after the decimal point, since these were
kono
parents:
diff changeset
678 -- included in the scaled digits that we output.
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 Expon := Scale + NFrac;
kono
parents:
diff changeset
681
kono
parents:
diff changeset
682 Set ('E');
kono
parents:
diff changeset
683 Ndigs := 0;
kono
parents:
diff changeset
684
kono
parents:
diff changeset
685 if Expon >= 0 then
kono
parents:
diff changeset
686 Set ('+');
kono
parents:
diff changeset
687 Set_Image_Unsigned (Unsigned (Expon), Digs, Ndigs);
kono
parents:
diff changeset
688 else
kono
parents:
diff changeset
689 Set ('-');
kono
parents:
diff changeset
690 Set_Image_Unsigned (Unsigned (-Expon), Digs, Ndigs);
kono
parents:
diff changeset
691 end if;
kono
parents:
diff changeset
692
kono
parents:
diff changeset
693 Set_Zeros (Exp - Ndigs - 1);
kono
parents:
diff changeset
694 Set_Digs (1, Ndigs);
kono
parents:
diff changeset
695 end if;
kono
parents:
diff changeset
696
kono
parents:
diff changeset
697 end Set_Image_Real;
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 end System.Img_Real;