(extendsfdf2): Add pattern accidentally deleted when cirrus instructions were
[official-gcc.git] / gcc / ada / s-imgrea.adb
blob644e54e43849efdd8828f7de99dcd498f15cb8e2
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- S Y S T E M . I M G _ R E A L --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 -- --
33 ------------------------------------------------------------------------------
35 with System.Img_LLU; use System.Img_LLU;
36 with System.Img_Uns; use System.Img_Uns;
37 with System.Powten_Table; use System.Powten_Table;
38 with System.Unsigned_Types; use System.Unsigned_Types;
40 package body System.Img_Real is
42 -- The following defines the maximum number of digits that we can convert
43 -- accurately. This is limited by the precision of Long_Long_Float, and
44 -- also by the number of digits we can hold in Long_Long_Unsigned, which
45 -- is the integer type we use as an intermediate for the result.
47 -- We assume that in practice, the limitation will come from the digits
48 -- value, rather than the integer value. This is true for typical IEEE
49 -- implementations, and at worst, the only loss is for some precision
50 -- in very high precision floating-point output.
52 -- Note that in the following, the "-2" accounts for the sign and one
53 -- extra digits, since we need the maximum number of 9's that can be
54 -- supported, e.g. for the normal 64 bit case, Long_Long_Integer'Width
55 -- is 21, since the maximum value (approx 1.6 * 10**19) has 20 digits,
56 -- but the maximum number of 9's that can be supported is 19.
58 Maxdigs : constant :=
59 Natural'Min
60 (Long_Long_Unsigned'Width - 2, Long_Long_Float'Digits);
62 Unsdigs : constant := Unsigned'Width - 2;
63 -- Number of digits that can be converted using type Unsigned
64 -- See above for the explanation of the -2.
66 Maxscaling : constant := 5000;
67 -- Max decimal scaling required during conversion of floating-point
68 -- numbers to decimal. This is used to defend against infinite
69 -- looping in the conversion, as can be caused by erroneous executions.
70 -- The largest exponent used on any current system is 2**16383, which
71 -- is approximately 10**4932, and the highest number of decimal digits
72 -- is about 35 for 128-bit floating-point formats, so 5000 leaves
73 -- enough room for scaling such values
75 function Is_Negative (V : Long_Long_Float) return Boolean;
76 pragma Import (Intrinsic, Is_Negative);
78 --------------------------
79 -- Image_Floating_Point --
80 --------------------------
82 function Image_Floating_Point
83 (V : Long_Long_Float;
84 Digs : Natural)
85 return String
87 P : Natural := 0;
88 S : String (1 .. Long_Long_Float'Width);
90 begin
91 if not Is_Negative (V) then
92 S (1) := ' ';
93 P := 1;
94 end if;
96 Set_Image_Real (V, S, P, 1, Digs - 1, 3);
97 return S (1 .. P);
98 end Image_Floating_Point;
100 --------------------------------
101 -- Image_Ordinary_Fixed_Point --
102 --------------------------------
104 function Image_Ordinary_Fixed_Point
105 (V : Long_Long_Float;
106 Aft : Natural)
107 return String
109 P : Natural := 0;
110 S : String (1 .. Long_Long_Float'Width);
112 begin
113 if V >= 0.0 then
114 S (1) := ' ';
115 P := 1;
116 end if;
118 Set_Image_Real (V, S, P, 1, Aft, 0);
119 return S (1 .. P);
120 end Image_Ordinary_Fixed_Point;
122 --------------------
123 -- Set_Image_Real --
124 --------------------
126 procedure Set_Image_Real
127 (V : Long_Long_Float;
128 S : out String;
129 P : in out Natural;
130 Fore : Natural;
131 Aft : Natural;
132 Exp : Natural)
134 procedure Reset;
135 pragma Import (C, Reset, "__gnat_init_float");
136 -- We import the floating-point processor reset routine so that we can
137 -- be sure the floating-point processor is properly set for conversion
138 -- calls (see description of Reset in GNAT.Float_Control (g-flocon.ads).
139 -- This is notably need on Windows, where calls to the operating system
140 -- randomly reset the processor into 64-bit mode.
142 NFrac : constant Natural := Natural'Max (Aft, 1);
143 Sign : Character;
144 X : aliased Long_Long_Float;
145 -- This is declared aliased because the expansion of X'Valid passes
146 -- X by access and JGNAT requires all access parameters to be aliased.
147 -- The Valid attribute probably needs to be handled via a different
148 -- expansion for JGNAT, and this use of aliased should be removed
149 -- once Valid is handled properly. ???
150 Scale : Integer;
151 Expon : Integer;
153 Field_Max : constant := 255;
154 -- This should be the same value as Ada.[Wide_]Text_IO.Field'Last.
155 -- It is not worth dragging in Ada.Text_IO to pick up this value,
156 -- since it really should never be necessary to change it!
158 Digs : String (1 .. 2 * Field_Max + 16);
159 -- Array used to hold digits of converted integer value. This is a
160 -- large enough buffer to accommodate ludicrous values of Fore and Aft.
162 Ndigs : Natural;
163 -- Number of digits stored in Digs (and also subscript of last digit)
165 procedure Adjust_Scale (S : Natural);
166 -- Adjusts the value in X by multiplying or dividing by a power of
167 -- ten so that it is in the range 10**(S-1) <= X < 10**S. Includes
168 -- adding 0.5 to round the result, readjusting if the rounding causes
169 -- the result to wander out of the range. Scale is adjusted to reflect
170 -- the power of ten used to divide the result (i.e. one is added to
171 -- the scale value for each division by 10.0, or one is subtracted
172 -- for each multiplication by 10.0).
174 procedure Convert_Integer;
175 -- Takes the value in X, outputs integer digits into Digs. On return,
176 -- Ndigs is set to the number of digits stored. The digits are stored
177 -- in Digs (1 .. Ndigs),
179 procedure Set (C : Character);
180 -- Sets character C in output buffer
182 procedure Set_Blanks_And_Sign (N : Integer);
183 -- Sets leading blanks and minus sign if needed. N is the number of
184 -- positions to be filled (a minus sign is output even if N is zero
185 -- or negative, but for a positive value, if N is non-positive, then
186 -- the call has no effect).
188 procedure Set_Digs (S, E : Natural);
189 -- Set digits S through E from Digs buffer. No effect if S > E
191 procedure Set_Special_Fill (N : Natural);
192 -- After outputting +Inf, -Inf or NaN, this routine fills out the
193 -- rest of the field with * characters. The argument is the number
194 -- of characters output so far (either 3 or 4)
196 procedure Set_Zeros (N : Integer);
197 -- Set N zeros, no effect if N is negative
199 pragma Inline (Set);
200 pragma Inline (Set_Digs);
201 pragma Inline (Set_Zeros);
203 ------------------
204 -- Adjust_Scale --
205 ------------------
207 procedure Adjust_Scale (S : Natural) is
208 Lo : Natural;
209 Hi : Natural;
210 Mid : Natural;
211 XP : Long_Long_Float;
213 begin
214 -- Cases where scaling up is required
216 if X < Powten (S - 1) then
218 -- What we are looking for is a power of ten to multiply X by
219 -- so that the result lies within the required range.
221 loop
222 XP := X * Powten (Maxpow);
223 exit when XP >= Powten (S - 1) or Scale < -Maxscaling;
224 X := XP;
225 Scale := Scale - Maxpow;
226 end loop;
228 -- The following exception is only raised in case of erroneous
229 -- execution, where a number was considered valid but still
230 -- fails to scale up. One situation where this can happen is
231 -- when a system which is supposed to be IEEE-compliant, but
232 -- has been reconfigured to flush denormals to zero.
234 if Scale < -Maxscaling then
235 raise Constraint_Error;
236 end if;
238 -- Here we know that we must multiply by at least 10**1 and that
239 -- 10**Maxpow takes us too far: binary search to find right one.
241 -- Because of roundoff errors, it is possible for the value
242 -- of XP to be just outside of the interval when Lo >= Hi. In
243 -- that case we adjust explicitly by a factor of 10. This
244 -- can only happen with a value that is very close to an
245 -- exact power of 10.
247 Lo := 1;
248 Hi := Maxpow;
250 loop
251 Mid := (Lo + Hi) / 2;
252 XP := X * Powten (Mid);
254 if XP < Powten (S - 1) then
256 if Lo >= Hi then
257 Mid := Mid + 1;
258 XP := XP * 10.0;
259 exit;
261 else
262 Lo := Mid + 1;
263 end if;
265 elsif XP >= Powten (S) then
267 if Lo >= Hi then
268 Mid := Mid - 1;
269 XP := XP / 10.0;
270 exit;
272 else
273 Hi := Mid - 1;
274 end if;
276 else
277 exit;
278 end if;
279 end loop;
281 X := XP;
282 Scale := Scale - Mid;
284 -- Cases where scaling down is required
286 elsif X >= Powten (S) then
288 -- What we are looking for is a power of ten to divide X by
289 -- so that the result lies within the required range.
291 loop
292 XP := X / Powten (Maxpow);
293 exit when XP < Powten (S) or Scale > Maxscaling;
294 X := XP;
295 Scale := Scale + Maxpow;
296 end loop;
298 -- The following exception is only raised in case of erroneous
299 -- execution, where a number was considered valid but still
300 -- fails to scale up. One situation where this can happen is
301 -- when a system which is supposed to be IEEE-compliant, but
302 -- has been reconfigured to flush denormals to zero.
304 if Scale > Maxscaling then
305 raise Constraint_Error;
306 end if;
308 -- Here we know that we must divide by at least 10**1 and that
309 -- 10**Maxpow takes us too far, binary search to find right one.
311 Lo := 1;
312 Hi := Maxpow;
314 loop
315 Mid := (Lo + Hi) / 2;
316 XP := X / Powten (Mid);
318 if XP < Powten (S - 1) then
320 if Lo >= Hi then
321 XP := XP * 10.0;
322 Mid := Mid - 1;
323 exit;
325 else
326 Hi := Mid - 1;
327 end if;
329 elsif XP >= Powten (S) then
331 if Lo >= Hi then
332 XP := XP / 10.0;
333 Mid := Mid + 1;
334 exit;
336 else
337 Lo := Mid + 1;
338 end if;
340 else
341 exit;
342 end if;
343 end loop;
345 X := XP;
346 Scale := Scale + Mid;
348 -- Here we are already scaled right
350 else
351 null;
352 end if;
354 -- Round, readjusting scale if needed. Note that if a readjustment
355 -- occurs, then it is never necessary to round again, because there
356 -- is no possibility of such a second rounding causing a change.
358 X := X + 0.5;
360 if X >= Powten (S) then
361 X := X / 10.0;
362 Scale := Scale + 1;
363 end if;
365 end Adjust_Scale;
367 ---------------------
368 -- Convert_Integer --
369 ---------------------
371 procedure Convert_Integer is
372 begin
373 -- Use Unsigned routine if possible, since on many machines it will
374 -- be significantly more efficient than the Long_Long_Unsigned one.
376 if X < Powten (Unsdigs) then
377 Ndigs := 0;
378 Set_Image_Unsigned
379 (Unsigned (Long_Long_Float'Truncation (X)),
380 Digs, Ndigs);
382 -- But if we want more digits than fit in Unsigned, we have to use
383 -- the Long_Long_Unsigned routine after all.
385 else
386 Ndigs := 0;
387 Set_Image_Long_Long_Unsigned
388 (Long_Long_Unsigned (Long_Long_Float'Truncation (X)),
389 Digs, Ndigs);
390 end if;
391 end Convert_Integer;
393 ---------
394 -- Set --
395 ---------
397 procedure Set (C : Character) is
398 begin
399 P := P + 1;
400 S (P) := C;
401 end Set;
403 -------------------------
404 -- Set_Blanks_And_Sign --
405 -------------------------
407 procedure Set_Blanks_And_Sign (N : Integer) is
408 begin
409 if Sign = '-' then
410 for J in 1 .. N - 1 loop
411 Set (' ');
412 end loop;
414 Set ('-');
416 else
417 for J in 1 .. N loop
418 Set (' ');
419 end loop;
420 end if;
421 end Set_Blanks_And_Sign;
423 --------------
424 -- Set_Digs --
425 --------------
427 procedure Set_Digs (S, E : Natural) is
428 begin
429 for J in S .. E loop
430 Set (Digs (J));
431 end loop;
432 end Set_Digs;
434 ----------------------
435 -- Set_Special_Fill --
436 ----------------------
438 procedure Set_Special_Fill (N : Natural) is
439 F : Natural;
441 begin
442 F := Fore + 1 + Aft - N;
444 if Exp /= 0 then
445 F := F + Exp + 1;
446 end if;
448 for J in 1 .. F loop
449 Set ('*');
450 end loop;
451 end Set_Special_Fill;
453 ---------------
454 -- Set_Zeros --
455 ---------------
457 procedure Set_Zeros (N : Integer) is
458 begin
459 for J in 1 .. N loop
460 Set ('0');
461 end loop;
462 end Set_Zeros;
464 -- Start of processing for Set_Image_Real
466 begin
467 Reset;
468 Scale := 0;
470 -- Positive values
472 if V > 0.0 then
473 X := V;
474 Sign := '+';
476 -- Negative values
478 elsif V < 0.0 then
479 X := -V;
480 Sign := '-';
482 -- Zero values
484 elsif V = 0.0 then
485 if Long_Long_Float'Signed_Zeros and then Is_Negative (V) then
486 Sign := '-';
487 else
488 Sign := '+';
489 end if;
491 Set_Blanks_And_Sign (Fore - 1);
492 Set ('0');
493 Set ('.');
494 Set_Zeros (NFrac);
496 if Exp /= 0 then
497 Set ('E');
498 Set ('+');
499 Set_Zeros (Natural'Max (1, Exp - 1));
500 end if;
502 return;
503 end if;
505 -- Deal with invalid values
507 if not X'Valid then
509 -- Note that we're taking our chances here, as X might be
510 -- an invalid bit pattern resulting from erroneous execution
511 -- (caused by using uninitialized variables for example).
513 -- No matter what, we'll at least get reasonable behaviour,
514 -- converting to infinity or some other value, or causing an
515 -- exception to be raised is fine.
517 -- If the following test succeeds, then we definitely have
518 -- an infinite value, so we print Inf.
520 if X > Long_Long_Float'Last then
521 Set (Sign);
522 Set ('I');
523 Set ('n');
524 Set ('f');
525 Set_Special_Fill (4);
527 -- In all other cases we print NaN
529 else
530 Set ('N');
531 Set ('a');
532 Set ('N');
533 Set_Special_Fill (3);
534 end if;
536 return;
538 -- Case of non-zero value with Exp = 0
540 elsif Exp = 0 then
542 -- First step is to multiply by 10 ** Nfrac to get an integer
543 -- value to be output, an then add 0.5 to round the result.
545 declare
546 NF : Natural := NFrac;
548 begin
549 loop
550 -- If we are larger than Powten (Maxdigs) now, then
551 -- we have too many significant digits, and we have
552 -- not even finished multiplying by NFrac (NF shows
553 -- the number of unaccounted-for digits).
555 if X >= Powten (Maxdigs) then
557 -- In this situation, we only to generate a reasonable
558 -- number of significant digits, and then zeroes after.
559 -- So first we rescale to get:
561 -- 10 ** (Maxdigs - 1) <= X < 10 ** Maxdigs
563 -- and then convert the resulting integer
565 Adjust_Scale (Maxdigs);
566 Convert_Integer;
568 -- If that caused rescaling, then add zeros to the end
569 -- of the number to account for this scaling. Also add
570 -- zeroes to account for the undone multiplications
572 for J in 1 .. Scale + NF loop
573 Ndigs := Ndigs + 1;
574 Digs (Ndigs) := '0';
575 end loop;
577 exit;
579 -- If multiplication is complete, then convert the resulting
580 -- integer after rounding (note that X is non-negative)
582 elsif NF = 0 then
583 X := X + 0.5;
584 Convert_Integer;
585 exit;
587 -- Otherwise we can go ahead with the multiplication. If it
588 -- can be done in one step, then do it in one step.
590 elsif NF < Maxpow then
591 X := X * Powten (NF);
592 NF := 0;
594 -- If it cannot be done in one step, then do partial scaling
596 else
597 X := X * Powten (Maxpow);
598 NF := NF - Maxpow;
599 end if;
600 end loop;
601 end;
603 -- If number of available digits is less or equal to NFrac,
604 -- then we need an extra zero before the decimal point.
606 if Ndigs <= NFrac then
607 Set_Blanks_And_Sign (Fore - 1);
608 Set ('0');
609 Set ('.');
610 Set_Zeros (NFrac - Ndigs);
611 Set_Digs (1, Ndigs);
613 -- Normal case with some digits before the decimal point
615 else
616 Set_Blanks_And_Sign (Fore - (Ndigs - NFrac));
617 Set_Digs (1, Ndigs - NFrac);
618 Set ('.');
619 Set_Digs (Ndigs - NFrac + 1, Ndigs);
620 end if;
622 -- Case of non-zero value with non-zero Exp value
624 else
625 -- If NFrac is less than Maxdigs, then all the fraction digits are
626 -- significant, so we can scale the resulting integer accordingly.
628 if NFrac < Maxdigs then
629 Adjust_Scale (NFrac + 1);
630 Convert_Integer;
632 -- Otherwise, we get the maximum number of digits available
634 else
635 Adjust_Scale (Maxdigs);
636 Convert_Integer;
638 for J in 1 .. NFrac - Maxdigs + 1 loop
639 Ndigs := Ndigs + 1;
640 Digs (Ndigs) := '0';
641 Scale := Scale - 1;
642 end loop;
643 end if;
645 Set_Blanks_And_Sign (Fore - 1);
646 Set (Digs (1));
647 Set ('.');
648 Set_Digs (2, Ndigs);
650 -- The exponent is the scaling factor adjusted for the digits
651 -- that we output after the decimal point, since these were
652 -- included in the scaled digits that we output.
654 Expon := Scale + NFrac;
656 Set ('E');
657 Ndigs := 0;
659 if Expon >= 0 then
660 Set ('+');
661 Set_Image_Unsigned (Unsigned (Expon), Digs, Ndigs);
662 else
663 Set ('-');
664 Set_Image_Unsigned (Unsigned (-Expon), Digs, Ndigs);
665 end if;
667 Set_Zeros (Exp - Ndigs - 1);
668 Set_Digs (1, Ndigs);
669 end if;
671 end Set_Image_Real;
673 end System.Img_Real;