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