home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / s-fatgen.adb < prev    next >
Text File  |  1996-09-28  |  17KB  |  659 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                       S Y S T E M . F A T _ G E N                        --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.5 $                              --
  10. --                                                                          --
  11. -- The GNAT library is free software; you can redistribute it and/or modify --
  12. -- it under terms of the GNU Library General Public License as published by --
  13. -- the Free Software  Foundation; either version 2, or (at your option) any --
  14. -- later version.  The GNAT library is distributed in the hope that it will --
  15. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  16. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  17. -- Library  General  Public  License for  more  details.  You  should  have --
  18. -- received  a copy of the GNU  Library  General Public License  along with --
  19. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  20. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  21. --                                                                          --
  22. ------------------------------------------------------------------------------
  23.  
  24. --  The implementation here is portable to any IEEE implementation. It does
  25. --  not handle non-binary radix, and also assumes that model numbers and
  26. --  machine numbers are basically identical, which is not true of all possible
  27. --  floating-point implementations. On a non-IEEE machine, this body must be
  28. --  specialized appropriately, or better still, its generic instantiations
  29. --  should be replaced by efficient machine-specific code.
  30.  
  31. package body System.Fat_Gen is
  32.  
  33.    Float_Radix        : constant T := T (T'Machine_Radix);
  34.    Float_Radix_Inv    : constant T := 1.0 / Float_Radix;
  35.    Radix_To_M_Minus_1 : constant T := Float_Radix ** (T'Machine_Mantissa - 1);
  36.  
  37.    pragma Assert (T'Machine_Radix = 2);
  38.    --  This version does not handle radix 16
  39.  
  40.    --  Constants for Decompose and Scaling
  41.  
  42.    Rad    : constant T := T (T'Machine_Radix);
  43.    Invrad : constant T := 1.0 / Rad;
  44.  
  45.    subtype Expbits is Integer range 0 .. 6;
  46.    --  2 ** (2 ** 7) might overflow.  how big can radix-16 exponents get?
  47.  
  48.    Log_Power : constant array (Expbits) of Integer := (1, 2, 4, 8, 16, 32, 64);
  49.  
  50.    R_Power : constant array (Expbits) of T :=
  51.      (Rad **  1,
  52.       Rad **  2,
  53.       Rad **  4,
  54.       Rad **  8,
  55.       Rad ** 16,
  56.       Rad ** 32,
  57.       Rad ** 64);
  58.  
  59.    R_Neg_Power : constant array (Expbits) of T :=
  60.       (Invrad **  1,
  61.        Invrad **  2,
  62.        Invrad **  4,
  63.        Invrad **  8,
  64.        Invrad ** 16,
  65.        Invrad ** 32,
  66.        Invrad ** 64);
  67.  
  68.    -----------------------
  69.    -- Local Subprograms --
  70.    -----------------------
  71.  
  72.    procedure Decompose (XX : T; Frac : out T; Expo : out UI);
  73.    --  Decomposes a floating-point number into fraction and exponent parts
  74.  
  75.    --------------
  76.    -- Adjacent --
  77.    --------------
  78.  
  79.    --  Adjacent( X, 0.0) will be incorrect for abs(X) any power of two
  80.    --  because of a bug in Succ and Pred.  An extra test must be made
  81.    --  for this case ???.
  82.  
  83.    function Adjacent (X, Towards : T) return T is
  84.    begin
  85.       if Towards = X then
  86.          return X;
  87.  
  88.       elsif Towards > X then
  89.          return Succ (X);
  90.  
  91.       else
  92.          return Pred (X);
  93.       end if;
  94.    end Adjacent;
  95.  
  96.    -------------
  97.    -- Ceiling --
  98.    -------------
  99.  
  100.    function Ceiling (X : T) return T is
  101.       XT : constant T := Truncation (X);
  102.  
  103.    begin
  104.       if X <= 0.0 then
  105.          return XT;
  106.  
  107.       elsif X = XT then
  108.          return X;
  109.  
  110.       else
  111.          return XT + 1.0;
  112.       end if;
  113.    end Ceiling;
  114.  
  115.    -------------
  116.    -- Compose --
  117.    -------------
  118.  
  119.    function Compose (Fraction : T; Exponent : UI) return T is
  120.       Arg_Frac : T;
  121.       Arg_Exp  : UI;
  122.  
  123.    begin
  124.       Decompose (Fraction, Arg_Frac, Arg_Exp);
  125.       return Scaling (Arg_Frac, Exponent);
  126.    end Compose;
  127.  
  128.    ---------------
  129.    -- Copy_Sign --
  130.    ---------------
  131.  
  132.    --  Configuration requirement: If this unit is used to implement the
  133.    --  floating-point attributes, then if Signed_Zeros is true, we must
  134.    --  have Machine_Overflows False, and we must generate infinities for
  135.    --  overflow (otherwise we can't implement signed zeroes properly).
  136.  
  137.    function Copy_Sign (Value, Sign : T) return T is
  138.       Result : T;
  139.  
  140.    begin
  141.       Result := abs Value;
  142.  
  143.       --  If we have signed zeroes true, then we know that machine overflows
  144.       --  is false, and that infinities are generated for overflow, so we can
  145.       --  test for minus zero by looking at the sign of the corresponding
  146.       --  infinity value (neat trick eh?)
  147.  
  148.       if Sign = 0.0 and then T'Signed_Zeros then
  149.          if 1.0 / Sign > 0.0 then
  150.             return Result;
  151.          else
  152.             return -Result;
  153.          end if;
  154.       end if;
  155.  
  156.       --  Handle non-zero cases, and also the zero case if signed zeroes
  157.       --  is false. In the latter case we always treat zero as positive.
  158.  
  159.       if Sign >= 0.0 then
  160.          return Result;
  161.       else
  162.          return -Result;
  163.       end if;
  164.    end Copy_Sign;
  165.  
  166.    ---------------
  167.    -- Decompose --
  168.    ---------------
  169.  
  170.    procedure Decompose (XX : T; Frac : out T; Expo : out UI) is
  171.       X : T := T'Machine (XX);
  172.  
  173.    begin
  174.       if X = 0.0 then
  175.          Frac := X;
  176.          Expo := 0;
  177.  
  178.          --  More useful would be defining Expo to be T'Machine_Emin - 1 or
  179.          --  T'Machine_Emin - T'Machine_Mantissa, which would preserve
  180.          --  monotonicity of the exponent fuction..
  181.  
  182.       --  Check for infinities, transfinites, whatnot.
  183.  
  184.       elsif X > T'Safe_Last then
  185.          Frac := Invrad;
  186.          Expo := T'Machine_Emax + 1;
  187.  
  188.       elsif X < T'Safe_First then
  189.          Frac := -Invrad;
  190.          Expo := T'Machine_Emax + 2;    -- how many extra negative values?
  191.  
  192.       else
  193.          --  Case of nonzero finite x. Essentially, we just multiply
  194.          --  by Rad ** (+-2**N) to reduce the range.
  195.  
  196.          declare
  197.             Ax : T  := abs X;
  198.             Ex : UI := 0;
  199.  
  200.          --  Ax * Rad ** Ex is invariant.
  201.  
  202.          begin
  203.             if Ax >= 1.0 then
  204.                while Ax >= R_Power (Expbits'Last) loop
  205.                   Ax := Ax * R_Neg_Power (Expbits'Last);
  206.                   Ex := Ex + Log_Power (Expbits'Last);
  207.                end loop;
  208.  
  209.                --  Ax < Rad ** 64
  210.  
  211.                for N in reverse Expbits'First .. Expbits'Last - 1 loop
  212.                   if Ax >= R_Power (N) then
  213.                      Ax := Ax * R_Neg_Power (N);
  214.                      Ex := Ex + Log_Power (N);
  215.                   end if;
  216.  
  217.                   --  Ax < R_Power (N)
  218.                end loop;
  219.  
  220.                --  1 <= Ax < Rad
  221.  
  222.                Ax := Ax * Invrad;
  223.                Ex := Ex + 1;
  224.  
  225.             else
  226.                --  0 < ax < 1
  227.  
  228.                while Ax < R_Neg_Power (Expbits'Last) loop
  229.                   Ax := Ax * R_Power (Expbits'Last);
  230.                   Ex := Ex - Log_Power (Expbits'Last);
  231.                end loop;
  232.  
  233.                --  Rad ** -64 <= Ax < 1
  234.  
  235.                for N in reverse Expbits'First .. Expbits'Last - 1 loop
  236.                   if Ax < R_Neg_Power (N) then
  237.                      Ax := Ax * R_Power (N);
  238.                      Ex := Ex - Log_Power (N);
  239.                   end if;
  240.  
  241.                   --  R_Neg_Power (N) <= Ax < 1
  242.                end loop;
  243.             end if;
  244.  
  245.             if X > 0.0 then
  246.                Frac := Ax;
  247.             else
  248.                Frac := -Ax;
  249.             end if;
  250.  
  251.             Expo := Ex;
  252.          end;
  253.       end if;
  254.    end Decompose;
  255.  
  256.    --------------
  257.    -- Exponent --
  258.    --------------
  259.  
  260.    function Exponent (X : T) return UI is
  261.       X_Frac : T;
  262.       X_Exp  : UI;
  263.  
  264.    begin
  265.       Decompose (X, X_Frac, X_Exp);
  266.       return X_Exp;
  267.    end Exponent;
  268.  
  269.    -----------
  270.    -- Floor --
  271.    -----------
  272.  
  273.    function Floor (X : T) return T is
  274.       XT : constant T := Truncation (X);
  275.  
  276.    begin
  277.       if X >= 0.0 then
  278.          return XT;
  279.  
  280.       elsif XT = X then
  281.          return X;
  282.  
  283.       else
  284.          return XT - 1.0;
  285.       end if;
  286.    end Floor;
  287.  
  288.    --------------
  289.    -- Fraction --
  290.    --------------
  291.  
  292.    function Fraction (X : T) return T is
  293.       X_Frac : T;
  294.       X_Exp  : UI;
  295.  
  296.    begin
  297.       Decompose (X, X_Frac, X_Exp);
  298.       return X_Frac;
  299.    end Fraction;
  300.  
  301.    ------------------
  302.    -- Leading_Part --
  303.    ------------------
  304.  
  305.    function Leading_Part (X : T; Radix_Digits : UI) return T is
  306.       L    : UI;
  307.       Y, Z : T;
  308.  
  309.    begin
  310.       if Radix_Digits >= T'Machine_Mantissa then
  311.          return X;
  312.  
  313.       else
  314.          L := Exponent (X) - Radix_Digits;
  315.          Y := Truncation (Scaling (X, -L));
  316.          Z := Scaling (Y, L);
  317.          return Z;
  318.       end if;
  319.  
  320.    end Leading_Part;
  321.  
  322.    -------------
  323.    -- Machine --
  324.    -------------
  325.  
  326.    --  The trick with Machine is to force the compiler to store the result
  327.    --  in memory so that we do not have extra precision used. The compiler
  328.    --  is clever, so we have to outwit its possible optimizations!
  329.  
  330.    --  This is achieved by using the following array. In fact only the first
  331.    --  element is used, and Machine_Index is always 1, but we make sure the
  332.    --  compiler can't figure this out.
  333.  
  334.    Machine_Array : array (1 .. 2) of T;
  335.    Machine_Index : Integer;
  336.  
  337.    function Machine (X : T) return T is
  338.    begin
  339.       Machine_Array (1) := X;
  340.       return Machine_Array (Machine_Index);
  341.    end Machine;
  342.  
  343.    -----------
  344.    -- Model --
  345.    -----------
  346.  
  347.    --  We treat Model as identical to Machine. This is true of IEEE and other
  348.    --  nice floating-point systems, but not necessarily true of all systems.
  349.  
  350.    function Model (X : T) return T is
  351.    begin
  352.       return Machine (X);
  353.    end Model;
  354.  
  355.    ----------
  356.    -- Pred --
  357.    ----------
  358.  
  359.    --  Subtract from the given number a number equivalent to the value of its
  360.    --  least significant bit. Given that the most significant bit represents a
  361.    --  value of 1.0 * radix ** (exp - 1), the value we want is obtained by
  362.    --  shifting this by (mantissa-1) bits to the right, i.e. decreasing the
  363.    --  exponent by that amount.
  364.  
  365.    function Pred (X : T) return T is
  366.       X_Frac : T;
  367.       X_Exp  : UI;
  368.  
  369.    begin
  370.       Decompose (X, X_Frac, X_Exp);
  371.       return X - Scaling (1.0, X_Exp - T'Machine_Mantissa);
  372.    end Pred;
  373.  
  374.    ---------------
  375.    -- Remainder --
  376.    ---------------
  377.  
  378.    function Remainder (X, Y : T) return T is
  379.       A        : T;
  380.       B        : T;
  381.       Arg      : T;
  382.       P        : T;
  383.       Arg_Frac : T;
  384.       P_Frac   : T;
  385.       Sign_X   : T;
  386.       IEEE_Rem : T;
  387.       Arg_Exp  : UI;
  388.       P_Exp    : UI;
  389.       K        : UI;
  390.       P_Even   : Boolean;
  391.  
  392.    begin
  393.       if X > 0.0 then
  394.          Sign_X :=  1.0;
  395.       else
  396.          Sign_X := -1.0;
  397.       end if;
  398.  
  399.       Arg := abs X;
  400.       P   := abs Y;
  401.  
  402.       if Arg < P then
  403.          P_Even := True;
  404.          IEEE_Rem := Arg;
  405.          P_Exp := Exponent (P);
  406.  
  407.       else
  408.          Decompose (Arg, Arg_Frac, Arg_Exp);
  409.          Decompose (P,   P_Frac,   P_Exp);
  410.  
  411.          P := Compose (P_Frac, Arg_Exp);
  412.          K := UI (Arg_Exp) - UI (P_Exp);
  413.          P_Even := True;
  414.          IEEE_Rem := Arg;
  415.  
  416.          for Cnt in reverse 0 .. K loop
  417.             if IEEE_Rem >= P then
  418.                P_Even := False;
  419.                IEEE_Rem := IEEE_Rem - P;
  420.             else
  421.                P_Even := True;
  422.             end if;
  423.  
  424.             P := P * 0.5;
  425.          end loop;
  426.       end if;
  427.  
  428.       --  That completes the calculation of modulus remainder. The final
  429.       --  step is get the IEEE remainder. Here we need to compare Rem with
  430.       --  (abs Y) / 2. We must be careful of unrepresentable Y/2 value
  431.       --  caused by subnormal numbers
  432.  
  433.       if P_Exp >= 0 then
  434.          A := IEEE_Rem;
  435.          B := abs Y * 0.5;
  436.       else
  437.          A := IEEE_Rem * 2.0;
  438.          B := abs Y;
  439.       end if;
  440.  
  441.       if A > B or else (A = B and then not P_Even) then
  442.          IEEE_Rem := IEEE_Rem - abs Y;
  443.       end if;
  444.  
  445.       return Sign_X * IEEE_Rem;
  446.  
  447.    end Remainder;
  448.  
  449.    --------------
  450.    -- Rounding --
  451.    --------------
  452.  
  453.    function Rounding (X : T) return T is
  454.       Result : T;
  455.       Tail   : T;
  456.  
  457.    begin
  458.       Result := Truncation (abs X);
  459.       Tail   := abs X - Result;
  460.  
  461.       if Tail >= 0.5  then
  462.          Result := Result + 1.0;
  463.       end if;
  464.  
  465.       if X > 0.0 then
  466.          return Result;
  467.  
  468.       elsif X < 0.0 then
  469.          return -Result;
  470.  
  471.       --  For zero case, make sure sign of zero is preserved
  472.  
  473.       else
  474.          return X;
  475.       end if;
  476.  
  477.    end Rounding;
  478.  
  479.    -------------
  480.    -- Scaling --
  481.    -------------
  482.  
  483.    --  Return x * rad ** adjustment quickly,
  484.    --  or quietly underflow to zero, or overflow naturally.
  485.  
  486.    function Scaling (X : T; Adjustment : UI) return T is
  487.    begin
  488.       if X = 0.0 or else Adjustment = 0 then
  489.          return X;
  490.       end if;
  491.  
  492.       --  Nonzero x. essentially, just multiply repeatedly by Rad ** (+-2**n).
  493.  
  494.       declare
  495.          Y  : T  := X;
  496.          Ex : UI := Adjustment;
  497.  
  498.       --  Y * Rad ** Ex is invariant
  499.  
  500.       begin
  501.          if Ex < 0 then
  502.             while Ex <= -Log_Power (Expbits'Last) loop
  503.                Y := Y * R_Neg_Power (Expbits'Last);
  504.                Ex := Ex + Log_Power (Expbits'Last);
  505.             end loop;
  506.  
  507.             --  -64 < Ex <= 0
  508.  
  509.             for N in reverse Expbits'First .. Expbits'Last - 1 loop
  510.                if Ex <= -Log_Power (N) then
  511.                   Y := Y * R_Neg_Power (N);
  512.                   Ex := Ex + Log_Power (N);
  513.                end if;
  514.  
  515.                --  -Log_Power (N) < Ex <= 0
  516.             end loop;
  517.  
  518.             --  Ex = 0
  519.  
  520.          else
  521.             --  Ex >= 0
  522.  
  523.             while Ex >= Log_Power (Expbits'Last) loop
  524.                Y := Y * R_Power (Expbits'Last);
  525.                Ex := Ex - Log_Power (Expbits'Last);
  526.             end loop;
  527.  
  528.             --  0 <= Ex < 64
  529.  
  530.             for N in reverse Expbits'First .. Expbits'Last - 1 loop
  531.                if Ex >= Log_Power (N) then
  532.                   Y := Y * R_Power (N);
  533.                   Ex := Ex - Log_Power (N);
  534.                end if;
  535.  
  536.                --  0 <= Ex < Log_Power (N)
  537.             end loop;
  538.  
  539.             --  Ex = 0
  540.          end if;
  541.          return Y;
  542.       end;
  543.    end Scaling;
  544.  
  545.    ----------
  546.    -- Succ --
  547.    ----------
  548.  
  549.    --  Similar computation to that of Pred: find value of least significant
  550.    --  bit of given number, and add.
  551.  
  552.    function Succ (X : T) return T is
  553.       X_Frac : T;
  554.       X_Exp  : UI;
  555.  
  556.    begin
  557.       Decompose (X, X_Frac, X_Exp);
  558.       return X + Scaling (1.0, X_Exp - T'Machine_Mantissa);
  559.    end Succ;
  560.  
  561.    ----------------
  562.    -- Truncation --
  563.    ----------------
  564.  
  565.    --  The basic approach is to compute
  566.  
  567.    --    T'Machine (RM1 + N) - RM1.
  568.  
  569.    --  where N >= 0.0 and RM1 = radix ** (mantissa - 1)
  570.  
  571.    --  This works provided that the intermediate result (RM1 + N) does not
  572.    --  have extra precision (which is why we call Machine). When we compute
  573.    --  RM1 + N, the epxonent of N will be normalized and the mantissa shifted
  574.    --  shifted appropriately so the lower order bits, which cannot contribute
  575.    --  to the integer part of N, fall off on the right. When we subtract RM1
  576.    --  again, the significant bits of N are shifted to the left, and what we
  577.    --  have is an integer, because only the first e bits are different from
  578.    --  zero (assuming binary radix here).
  579.  
  580.    function Truncation (X : T) return T is
  581.       Result : T;
  582.  
  583.    begin
  584.       Result := abs X;
  585.  
  586.       if Result >= Radix_To_M_Minus_1 then
  587.          return Machine (X);
  588.  
  589.       else
  590.          Result := Machine (Radix_To_M_Minus_1 + Result) - Radix_To_M_Minus_1;
  591.  
  592.          if Result > abs X  then
  593.             Result := Result - 1.0;
  594.          end if;
  595.  
  596.          if X > 0.0 then
  597.             return  Result;
  598.  
  599.          elsif X < 0.0 then
  600.             return -Result;
  601.  
  602.          --  For zero case, make sure sign of zero is preserved
  603.  
  604.          else
  605.             return X;
  606.          end if;
  607.       end if;
  608.  
  609.    end Truncation;
  610.  
  611.    -----------------------
  612.    -- Unbiased_Rounding --
  613.    -----------------------
  614.  
  615.    function Unbiased_Rounding (X : T) return T is
  616.       Result : T;
  617.       Tail   : T;
  618.  
  619.    begin
  620.       Result := Truncation (abs X);
  621.       Tail   := abs X - Result;
  622.  
  623.       if Tail > 0.5  then
  624.          Result := Result + 1.0;
  625.  
  626.       elsif Tail = 0.5 then
  627.          Result := 2.0 * Truncation ((Result / 2.0) + 0.5);
  628.       end if;
  629.  
  630.       if X > 0.0 then
  631.          return Result;
  632.  
  633.       elsif X < 0.0 then
  634.          return -Result;
  635.  
  636.       --  For zero case, make sure sign of zero is preserved
  637.  
  638.       else
  639.          return X;
  640.       end if;
  641.  
  642.    end Unbiased_Rounding;
  643.  
  644.    ----------------------------
  645.    -- Package Initialization --
  646.    ----------------------------
  647.  
  648. begin
  649.    --  Set Machine_Index to 1, but not in an obvious manner (see function
  650.    --  Machine to understand why we are behaving in this secretive manner)
  651.  
  652.    Machine_Index := 2 ** 3;
  653.  
  654.    for J in 1 .. 3 loop
  655.       Machine_Index := Machine_Index / 2;
  656.    end loop;
  657.  
  658. end System.Fat_Gen;
  659.