OSDN Git Service

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