OSDN Git Service

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