home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / s-imgrea.adb < prev    next >
Text File  |  2000-07-19  |  19KB  |  617 lines

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