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 / a-numaux.adb < prev    next >
Text File  |  2000-07-19  |  18KB  |  596 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                     A D A . N U M E R I C S . A U X                      --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                        (Machine Version for x86)                         --
  9. --                                                                          --
  10. --                            $Revision: 1.15 $
  11. --                                                                          --
  12. --          Copyright (C) 1998-2000 Free Software Foundation, Inc.          --
  13. --                                                                          --
  14. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  15. -- terms of the  GNU General Public License as published  by the Free Soft- --
  16. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  17. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  18. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  19. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  20. -- for  more details.  You should have  received  a copy of the GNU General --
  21. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  22. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  23. -- MA 02111-1307, USA.                                                      --
  24. --                                                                          --
  25. -- As a special exception,  if other files  instantiate  generics from this --
  26. -- unit, or you link  this unit with other files  to produce an executable, --
  27. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  28. -- covered  by the  GNU  General  Public  License.  This exception does not --
  29. -- however invalidate  any other reasons why  the executable file  might be --
  30. -- covered by the  GNU Public License.                                      --
  31. --                                                                          --
  32. -- GNAT was originally developed  by the GNAT team at  New York University. --
  33. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. --  File a-numaux.adb <- 86numaux.adb
  38.  
  39. --  This version of Numerics.Aux is for the IEEE Double Extended floating
  40. --  point format on x86.
  41.  
  42. with System.Machine_Code; use System.Machine_Code;
  43.  
  44. package body Ada.Numerics.Aux is
  45.  
  46.    NL           : constant String := ASCII.LF & ASCII.HT;
  47.  
  48.    type FPU_Stack_Pointer is range 0 .. 7;
  49.    for FPU_Stack_Pointer'Size use 3;
  50.  
  51.    type FPU_Status_Word is record
  52.       B   : Boolean; -- FPU Busy (for 8087 compatability only)
  53.       ES  : Boolean; -- Error Summary Status
  54.       SF  : Boolean; -- Stack Fault
  55.  
  56.       Top : FPU_Stack_Pointer;
  57.  
  58.       --  Condition Code Flags
  59.  
  60.       --  C2 is set by FPREM and FPREM1 to indicate incomplete reduction.
  61.       --  In case of successfull recorction, C0, C3 and C1 are set to the
  62.       --  three least significant bits of the result (resp. Q2, Q1 and Q0).
  63.  
  64.       --  C2 is used by FPTAN, FSIN, FCOS, and FSINCOS to indicate that
  65.       --  that source operand is beyond the allowable range of
  66.       --  -2.0**63 .. 2.0**63.
  67.  
  68.       C3  : Boolean;
  69.       C2  : Boolean;
  70.       C1  : Boolean;
  71.       C0  : Boolean;
  72.  
  73.       --  Exception Flags
  74.  
  75.       PE  : Boolean; -- Precision
  76.       UE  : Boolean; -- Underflow
  77.       OE  : Boolean; -- Overflow
  78.       ZE  : Boolean; -- Zero Divide
  79.       DE  : Boolean; -- Denormalized Operand
  80.       IE  : Boolean; -- Invalid Operation
  81.    end record;
  82.  
  83.    for FPU_Status_Word use record
  84.       B   at 0 range 15 .. 15;
  85.       C3  at 0 range 14 .. 14;
  86.       Top at 0 range 11 .. 13;
  87.       C2  at 0 range 10 .. 10;
  88.       C1  at 0 range  9 ..  9;
  89.       C0  at 0 range  8 ..  8;
  90.       ES  at 0 range  7 ..  7;
  91.       SF  at 0 range  6 ..  6;
  92.       PE  at 0 range  5 ..  5;
  93.       UE  at 0 range  4 ..  4;
  94.       OE  at 0 range  3 ..  3;
  95.       ZE  at 0 range  2 ..  2;
  96.       DE  at 0 range  1 ..  1;
  97.       IE  at 0 range  0 ..  0;
  98.    end record;
  99.  
  100.    for FPU_Status_Word'Size use 16;
  101.  
  102.    -----------------------
  103.    -- Local subprograms --
  104.    -----------------------
  105.  
  106.    function Is_Nan (X : Double) return Boolean;
  107.    --  Return True iff X is a IEEE NaN value
  108.  
  109.    function Logarithmic_Pow (X, Y : Double) return Double;
  110.    --  Implementation of X**Y using Exp and Log functions (binary base)
  111.    --  to calculate the exponentiation. This is used by Pow for values
  112.    --  for values of Y in the open interval (-0.25, 0.25)
  113.  
  114.    function Reduce (X : Double) return Double;
  115.    --  Implement partial reduction of X by Pi in the x86.
  116.  
  117.    --  Note that for the Sin, Cos and Tan functions completely accurate
  118.    --  reduction of the argument is done for arguments in the range of
  119.    --  -2.0**63 .. 2.0**63, using a 66-bit approximation of Pi.
  120.  
  121.  
  122.    pragma Inline (Is_Nan);
  123.    pragma Inline (Reduce);
  124.  
  125.    ---------------------------------
  126.    --  Basic Elementary Functions --
  127.    ---------------------------------
  128.  
  129.    --  This section implements a few elementary functions that are
  130.    --  used to build the more complex ones. This ordering enables
  131.    --  better inlining.
  132.  
  133.    ----------
  134.    -- Atan --
  135.    ----------
  136.  
  137.    function Atan (X : Double) return Double is
  138.       Result  : Double;
  139.  
  140.    begin
  141.       Asm (Template =>
  142.            "fld1" & NL
  143.          & "fpatan",
  144.          Outputs  => Double'Asm_Output ("=t", Result),
  145.          Inputs   => Double'Asm_Input  ("0", X));
  146.  
  147.       --  The result value is NaN iff input was invalid
  148.  
  149.       if not (Result = Result) then
  150.          raise Argument_Error;
  151.       end if;
  152.  
  153.       return Result;
  154.    end Atan;
  155.  
  156.    ---------
  157.    -- Exp --
  158.    ---------
  159.  
  160.    function Exp (X : Double) return Double is
  161.       Result : Double;
  162.    begin
  163.       Asm (Template =>
  164.          "fldl2e               " & NL
  165.        & "fmulp   %%st, %%st(1)" & NL -- X * log2 (E)
  166.        & "fld     %%st(0)      " & NL
  167.        & "frndint              " & NL -- Integer (X * Log2 (E))
  168.        & "fsubr   %%st, %%st(1)" & NL -- Fraction (X * Log2 (E))
  169.        & "fxch                 " & NL
  170.        & "f2xm1                " & NL -- 2**(...) - 1
  171.        & "fld1                 " & NL
  172.        & "faddp   %%st, %%st(1)" & NL -- 2**(Fraction (X * Log2 (E)))
  173.        & "fscale               " & NL -- E ** X
  174.        & "fstp    %%st(1)      ",
  175.          Outputs  => Double'Asm_Output ("=t", Result),
  176.          Inputs   => Double'Asm_Input  ("0", X));
  177.       return Result;
  178.    end Exp;
  179.  
  180.    ------------
  181.    -- Is_Nan --
  182.    ------------
  183.  
  184.    function Is_Nan (X : Double) return Boolean is
  185.    begin
  186.       --  The IEEE NaN values are the only ones that do not equal themselves
  187.  
  188.       return not (X = X);
  189.    end Is_Nan;
  190.  
  191.    ---------
  192.    -- Log --
  193.    ---------
  194.  
  195.    function Log (X : Double) return Double is
  196.       Result : Double;
  197.  
  198.    begin
  199.       Asm (Template =>
  200.          "fldln2               " & NL
  201.        & "fxch                 " & NL
  202.        & "fyl2x                " & NL,
  203.          Outputs  => Double'Asm_Output ("=t", Result),
  204.          Inputs   => Double'Asm_Input  ("0", X));
  205.       return Result;
  206.    end Log;
  207.  
  208.    ------------
  209.    -- Reduce --
  210.    ------------
  211.  
  212.    function Reduce (X : Double) return Double is
  213.       Result : Double;
  214.    begin
  215.       Asm
  216.         (Template =>
  217.          --  Partial argument reduction
  218.          "fldpi                " & NL
  219.        & "fadd    %%st(0), %%st" & NL
  220.        & "fxch    %%st(1)      " & NL
  221.        & "fprem1               " & NL
  222.        & "fstp    %%st(1)      ",
  223.          Outputs  => Double'Asm_Output ("=t", Result),
  224.          Inputs   => Double'Asm_Input  ("0", X));
  225.       return Result;
  226.    end Reduce;
  227.  
  228.    ----------
  229.    -- Sqrt --
  230.    ----------
  231.  
  232.    function Sqrt (X : Double) return Double is
  233.       Result  : Double;
  234.  
  235.    begin
  236.       if X < 0.0 then
  237.          raise Argument_Error;
  238.       end if;
  239.  
  240.       Asm (Template => "fsqrt",
  241.            Outputs  => Double'Asm_Output ("=t", Result),
  242.            Inputs   => Double'Asm_Input  ("0", X));
  243.  
  244.       return Result;
  245.    end Sqrt;
  246.  
  247.    ---------------------------------
  248.    --  Other Elementary Functions --
  249.    ---------------------------------
  250.  
  251.    --  These are built using the previously implemented basic functions
  252.  
  253.    ----------
  254.    -- Acos --
  255.    ----------
  256.  
  257.    function Acos (X : Double) return Double is
  258.       Result  : Double;
  259.    begin
  260.       Result := 2.0 * Atan (Sqrt ((1.0 - X) / (1.0 + X)));
  261.  
  262.       --  The result value is NaN iff input was invalid
  263.  
  264.       if Is_Nan (Result) then
  265.          raise Argument_Error;
  266.       end if;
  267.  
  268.       return Result;
  269.    end Acos;
  270.  
  271.    ----------
  272.    -- Asin --
  273.    ----------
  274.  
  275.    function Asin (X : Double) return Double is
  276.       Result  : Double;
  277.    begin
  278.  
  279.       Result := Atan (X / Sqrt ((1.0 - X) * (1.0 + X)));
  280.  
  281.       --  The result value is NaN iff input was invalid
  282.  
  283.       if Is_Nan (Result) then
  284.          raise Argument_Error;
  285.       end if;
  286.  
  287.       return Result;
  288.    end Asin;
  289.  
  290.    ---------
  291.    -- Cos --
  292.    ---------
  293.  
  294.    function Cos (X : Double) return Double is
  295.       Reduced_X : Double := X;
  296.       Result    : Double;
  297.       Status    : FPU_Status_Word;
  298.  
  299.    begin
  300.  
  301.       loop
  302.          Asm
  303.            (Template =>
  304.             "fcos                 " & NL
  305.           & "xorl    %%eax, %%eax " & NL
  306.           & "fnstsw  %%ax         ",
  307.             Outputs  => (Double'Asm_Output         ("=t", Result),
  308.                         FPU_Status_Word'Asm_Output ("=a", Status)),
  309.             Inputs   => Double'Asm_Input           ("0", Reduced_X));
  310.  
  311.          exit when not Status.C2;
  312.  
  313.          --  Original argument was not in range and the result
  314.          --  is the unmodified argument.
  315.  
  316.          Reduced_X := Reduce (Result);
  317.       end loop;
  318.  
  319.       return Result;
  320.    end Cos;
  321.  
  322.    ---------------------
  323.    -- Logarithmic_Pow --
  324.    ---------------------
  325.  
  326.    function Logarithmic_Pow (X, Y : Double) return Double is
  327.       Result  : Double;
  328.  
  329.    begin
  330.       Asm (Template => ""             --  X                  : Y
  331.        & "fyl2x                " & NL --  Y * Log2 (X)
  332.        & "fst     %%st(1)      " & NL --  Y * Log2 (X)       : Y * Log2 (X)
  333.        & "frndint              " & NL --  Int (...)          : Y * Log2 (X)
  334.        & "fsubr   %%st, %%st(1)" & NL --  Int (...)          : Fract (...)
  335.        & "fxch                 " & NL --  Fract (...)        : Int (...)
  336.        & "f2xm1                " & NL --  2**Fract (...) - 1 : Int (...)
  337.        & "fld1                 " & NL --  1 : 2**Fract (...) - 1 : Int (...)
  338.        & "faddp   %%st, %%st(1)" & NL --  2**Fract (...)     : Int (...)
  339.        & "fscale               " & NL --  2**(Fract (...) + Int (...))
  340.        & "fstp    %%st(1)      ",
  341.          Outputs  => Double'Asm_Output ("=t", Result),
  342.          Inputs   =>
  343.            (Double'Asm_Input  ("0", X),
  344.             Double'Asm_Input  ("u", Y)));
  345.  
  346.       return Result;
  347.    end Logarithmic_Pow;
  348.  
  349.    ---------
  350.    -- Pow --
  351.    ---------
  352.  
  353.    function Pow (X, Y : Double) return Double is
  354.       type Mantissa_Type is mod 2**Double'Machine_Mantissa;
  355.       --  Modular type that can hold all bits of the mantissa of Double
  356.  
  357.       --  For negative exponents, a division is done
  358.       --  at the end of the processing.
  359.  
  360.       Negative_Y : constant Boolean := Y < 0.0;
  361.       Abs_Y      : constant Double := abs Y;
  362.  
  363.       --  During this function the following invariant is kept:
  364.       --  X ** (abs Y) = Base**(Exp_High + Exp_Mid + Exp_Low) * Factor
  365.  
  366.       Base : Double := X;
  367.  
  368.       Exp_High : Double := Double'Floor (Abs_Y);
  369.       Exp_Mid  : Double;
  370.       Exp_Low  : Double;
  371.       Exp_Int  : Mantissa_Type;
  372.  
  373.       Factor : Double := 1.0;
  374.  
  375.    begin
  376.       --  Select algorithm for calculating Pow:
  377.       --  integer cases fall through
  378.  
  379.       if Exp_High >= 2.0**Double'Machine_Mantissa then
  380.  
  381.          --  In case of Y that is IEEE infinity, just raise constraint error
  382.  
  383.          if Exp_High > Double'Safe_Last then
  384.             raise Constraint_Error;
  385.          end if;
  386.  
  387.          --  Large values of Y are even integers and will stay integer
  388.          --  after division by two.
  389.  
  390.          loop
  391.             --  Exp_Mid and Exp_Low are zero, so
  392.             --    X**(abs Y) = Base ** Exp_High = (Base**2) ** (Exp_High / 2)
  393.  
  394.             Exp_High := Exp_High / 2.0;
  395.             Base := Base * Base;
  396.             exit when Exp_High < 2.0**Double'Machine_Mantissa;
  397.          end loop;
  398.  
  399.       elsif Exp_High /= Abs_Y then
  400.          Exp_Low := Abs_Y - Exp_High;
  401.  
  402.          Factor := 1.0;
  403.  
  404.          if Exp_Low /= 0.0 then
  405.  
  406.             --  Exp_Low now is in interval (0.0, 1.0)
  407.             --  Exp_Mid := Double'Floor (Exp_Low * 4.0) / 4.0;
  408.  
  409.             Exp_Mid := 0.0;
  410.             Exp_Low := Exp_Low - Exp_Mid;
  411.  
  412.             if Exp_Low >= 0.5 then
  413.                Factor := Sqrt (X);
  414.                Exp_Low := Exp_Low - 0.5;  -- exact
  415.  
  416.                if Exp_Low >= 0.25 then
  417.                   Factor := Factor * Sqrt (Factor);
  418.                   Exp_Low := Exp_Low - 0.25; --  exact
  419.                end if;
  420.  
  421.             elsif Exp_Low >= 0.25 then
  422.                Factor := Sqrt (Sqrt (X));
  423.                Exp_Low := Exp_Low - 0.25; --  exact
  424.             end if;
  425.  
  426.             --  Exp_Low now is in interval (0.0, 0.25)
  427.  
  428.             --  This means it is safe to call Logarithmic_Pow
  429.             --  for the remaining part.
  430.  
  431.             Factor := Factor * Logarithmic_Pow (X, Exp_Low);
  432.          end if;
  433.  
  434.       elsif X = 0.0 then
  435.          return 0.0;
  436.       end if;
  437.  
  438.       --  Exp_High is non-zero integer smaller than 2**Double'Machine_Mantissa
  439.  
  440.       Exp_Int := Mantissa_Type (Exp_High);
  441.  
  442.       --  Standard way for processing integer powers > 0
  443.  
  444.       while Exp_Int > 1 loop
  445.          if (Exp_Int and 1) = 1 then
  446.  
  447.             --  Base**Y = Base**(Exp_Int - 1) * Exp_Int for Exp_Int > 0
  448.  
  449.             Factor := Factor * Base;
  450.          end if;
  451.  
  452.          --  Exp_Int is even and Exp_Int > 0, so
  453.          --    Base**Y = (Base**2)**(Exp_Int / 2)
  454.  
  455.          Base := Base * Base;
  456.          Exp_Int := Exp_Int / 2;
  457.       end loop;
  458.  
  459.       --  Exp_Int = 1 or Exp_Int = 0
  460.  
  461.       if Exp_Int = 1 then
  462.          Factor := Base * Factor;
  463.       end if;
  464.  
  465.       if Negative_Y then
  466.          Factor := 1.0 / Factor;
  467.       end if;
  468.  
  469.       return Factor;
  470.    end Pow;
  471.  
  472.    ---------
  473.    -- Sin --
  474.    ---------
  475.  
  476.    function Sin (X : Double) return Double is
  477.       Reduced_X : Double := X;
  478.       Result    : Double;
  479.       Status    : FPU_Status_Word;
  480.  
  481.    begin
  482.  
  483.       loop
  484.          Asm
  485.            (Template =>
  486.             "fsin                 " & NL
  487.           & "xorl    %%eax, %%eax " & NL
  488.           & "fnstsw  %%ax         ",
  489.             Outputs  => (Double'Asm_Output          ("=t", Result),
  490.                          FPU_Status_Word'Asm_Output ("=a", Status)),
  491.             Inputs   => Double'Asm_Input            ("0", Reduced_X));
  492.  
  493.          exit when not Status.C2;
  494.  
  495.          --  Original argument was not in range and the result
  496.          --  is the unmodified argument.
  497.  
  498.          Reduced_X := Reduce (Result);
  499.       end loop;
  500.  
  501.       return Result;
  502.    end Sin;
  503.  
  504.    ---------
  505.    -- Tan --
  506.    ---------
  507.  
  508.    function Tan (X : Double) return Double is
  509.       Reduced_X : Double := X;
  510.       Result    : Double;
  511.       Status    : FPU_Status_Word;
  512.  
  513.    begin
  514.  
  515.       loop
  516.          Asm
  517.            (Template =>
  518.             "fptan                " & NL
  519.           & "xorl    %%eax, %%eax " & NL
  520.           & "fnstsw  %%ax         " & NL
  521.           & "ffree   %%st(0)      " & NL
  522.           & "fincstp              ",
  523.  
  524.             Outputs  => (Double'Asm_Output         ("=t", Result),
  525.                         FPU_Status_Word'Asm_Output ("=a", Status)),
  526.             Inputs   => Double'Asm_Input           ("0", Reduced_X));
  527.  
  528.          exit when not Status.C2;
  529.  
  530.          --  Original argument was not in range and the result
  531.          --  is the unmodified argument.
  532.  
  533.          Reduced_X := Reduce (Result);
  534.       end loop;
  535.  
  536.       return Result;
  537.    end Tan;
  538.  
  539.    ----------
  540.    -- Sinh --
  541.    ----------
  542.  
  543.    function Sinh (X : Double) return Double is
  544.    begin
  545.       --  Mathematically Sinh (x) is defined to be (Exp (X) - Exp (-X)) / 2.0
  546.  
  547.       if abs X < 25.0 then
  548.          return (Exp (X) - Exp (-X)) / 2.0;
  549.  
  550.       else
  551.          return Exp (X) / 2.0;
  552.       end if;
  553.  
  554.    end Sinh;
  555.  
  556.    ----------
  557.    -- Cosh --
  558.    ----------
  559.  
  560.    function Cosh (X : Double) return Double is
  561.    begin
  562.       --  Mathematically Cosh (X) is defined to be (Exp (X) + Exp (-X)) / 2.0
  563.  
  564.       if abs X < 22.0 then
  565.          return (Exp (X) + Exp (-X)) / 2.0;
  566.  
  567.       else
  568.          return Exp (X) / 2.0;
  569.       end if;
  570.  
  571.    end Cosh;
  572.  
  573.    ----------
  574.    -- Tanh --
  575.    ----------
  576.  
  577.    function Tanh (X : Double) return Double is
  578.    begin
  579.       --  Return the Hyperbolic Tangent of x
  580.       --
  581.       --                                    x    -x
  582.       --                                   e  - e        Sinh (X)
  583.       --       Tanh (X) is defined to be -----------   = --------
  584.       --                                    x    -x      Cosh (X)
  585.       --                                   e  + e
  586.  
  587.       if abs X > 23.0 then
  588.          return Double'Copy_Sign (1.0, X);
  589.       end if;
  590.  
  591.       return 1.0 / (1.0 + Exp (-2.0 * X)) - 1.0 / (1.0 + Exp (2.0 * X));
  592.  
  593.    end Tanh;
  594.  
  595. end Ada.Numerics.Aux;
  596.