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-ngcoty.adb < prev    next >
Text File  |  2000-07-19  |  18KB  |  667 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --   A D A . N U M E R I C S . G E N E R I C _ C O M P L E X _ T Y P E S    --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.14 $                              --
  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 Ada.Numerics.Aux; use Ada.Numerics.Aux;
  37. package body Ada.Numerics.Generic_Complex_Types is
  38.  
  39.    subtype R is Real'Base;
  40.  
  41.    Two_Pi     : constant R := R (2.0) * Pi;
  42.    Half_Pi    : constant R := Pi / R (2.0);
  43.  
  44.    ---------
  45.    -- "+" --
  46.    ---------
  47.  
  48.    function "+" (Right : Complex) return Complex is
  49.    begin
  50.       return Right;
  51.    end "+";
  52.  
  53.    function "+" (Left, Right : Complex) return Complex is
  54.    begin
  55.       return Complex'(Left.Re + Right.Re, Left.Im + Right.Im);
  56.    end "+";
  57.  
  58.    function "+" (Right : Imaginary) return Imaginary is
  59.    begin
  60.       return Right;
  61.    end "+";
  62.  
  63.    function "+" (Left, Right : Imaginary) return Imaginary is
  64.    begin
  65.       return Imaginary (R (Left) + R (Right));
  66.    end "+";
  67.  
  68.    function "+" (Left : Complex; Right : Real'Base) return Complex is
  69.    begin
  70.       return Complex'(Left.Re + Right, Left.Im);
  71.    end "+";
  72.  
  73.    function "+" (Left : Real'Base; Right : Complex) return Complex is
  74.    begin
  75.       return Complex'(Left + Right.Re, Right.Im);
  76.    end "+";
  77.  
  78.    function "+" (Left : Complex; Right : Imaginary) return Complex is
  79.    begin
  80.       return Complex'(Left.Re, Left.Im + R (Right));
  81.    end "+";
  82.  
  83.    function "+" (Left : Imaginary; Right : Complex) return Complex is
  84.    begin
  85.       return Complex'(Right.Re, R (Left) + Right.Im);
  86.    end "+";
  87.  
  88.    function "+" (Left : Imaginary; Right : Real'Base) return Complex is
  89.    begin
  90.       return Complex'(Right, R (Left));
  91.    end "+";
  92.  
  93.    function "+" (Left : Real'Base; Right : Imaginary) return Complex is
  94.    begin
  95.       return Complex'(Left, R (Right));
  96.    end "+";
  97.  
  98.    ---------
  99.    -- "-" --
  100.    ---------
  101.  
  102.    function "-" (Right : Complex) return Complex is
  103.    begin
  104.       return (-Right.Re, -Right.Im);
  105.    end "-";
  106.  
  107.    function "-" (Left, Right : Complex) return Complex is
  108.    begin
  109.       return (Left.Re - Right.Re, Left.Im - Right.Im);
  110.    end "-";
  111.  
  112.    function "-" (Right : Imaginary) return Imaginary is
  113.    begin
  114.       return Imaginary (-R (Right));
  115.    end "-";
  116.  
  117.    function "-" (Left, Right : Imaginary) return Imaginary is
  118.    begin
  119.       return Imaginary (R (Left) - R (Right));
  120.    end "-";
  121.  
  122.    function "-" (Left : Complex; Right : Real'Base) return Complex is
  123.    begin
  124.       return Complex'(Left.Re - Right, Left.Im);
  125.    end "-";
  126.  
  127.    function "-" (Left : Real'Base; Right : Complex) return Complex is
  128.    begin
  129.       return Complex'(Left - Right.Re, -Right.Im);
  130.    end "-";
  131.  
  132.    function "-" (Left : Complex; Right : Imaginary) return Complex is
  133.    begin
  134.       return Complex'(Left.Re, Left.Im - R (Right));
  135.    end "-";
  136.  
  137.    function "-" (Left : Imaginary; Right : Complex) return Complex is
  138.    begin
  139.       return Complex'(-Right.Re, R (Left) - Right.Im);
  140.    end "-";
  141.  
  142.    function "-" (Left : Imaginary; Right : Real'Base) return Complex is
  143.    begin
  144.       return Complex'(-Right, R (Left));
  145.    end "-";
  146.  
  147.    function "-" (Left : Real'Base; Right : Imaginary) return Complex is
  148.    begin
  149.       return Complex'(Left, -R (Right));
  150.    end "-";
  151.  
  152.    ---------
  153.    -- "*" --
  154.    ---------
  155.  
  156.    function "*" (Left, Right : Complex) return Complex is
  157.       X : R;
  158.       Y : R;
  159.    begin
  160.       X := Left.Re * Right.Re - Left.Im * Right.Im;
  161.       Y := Left.Re * Right.Im + Left.Im * Right.Re;
  162.  
  163.       --  If either component overflows, try to scale.
  164.  
  165.       if abs (X) > R'Last then
  166.          X := R' (4.0) * (R'(Left.Re / 2.0)  * R'(Right.Re / 2.0)
  167.                 - R'(Left.Im / 2.0) * R'(Right.Im / 2.0));
  168.       end if;
  169.  
  170.       if abs (Y) > R'Last then
  171.          Y := R' (4.0) * (R'(Left.Re / 2.0)  * R'(Right.Im / 2.0)
  172.                 - R'(Left.Im / 2.0) * R'(Right.Re / 2.0));
  173.       end if;
  174.  
  175.       return (X, Y);
  176.    end "*";
  177.  
  178.    function "*" (Left, Right : Imaginary) return Real'Base is
  179.    begin
  180.       return -R (Left) * R (Right);
  181.    end "*";
  182.  
  183.    function "*" (Left : Complex; Right : Real'Base) return Complex is
  184.    begin
  185.       return Complex'(Left.Re * Right, Left.Im * Right);
  186.    end "*";
  187.  
  188.    function "*" (Left : Real'Base; Right : Complex) return Complex is
  189.    begin
  190.       return (Left * Right.Re, Left * Right.Im);
  191.    end "*";
  192.  
  193.    function "*" (Left : Complex; Right : Imaginary) return Complex is
  194.    begin
  195.       return Complex'(-(Left.Im * R (Right)), Left.Re * R (Right));
  196.    end "*";
  197.  
  198.    function "*" (Left : Imaginary; Right : Complex) return Complex is
  199.    begin
  200.       return Complex'(-(R (Left) * Right.Im), R (Left) * Right.Re);
  201.    end "*";
  202.  
  203.    function "*" (Left : Imaginary; Right : Real'Base) return Imaginary is
  204.    begin
  205.       return Left * Imaginary (Right);
  206.    end "*";
  207.  
  208.    function "*" (Left : Real'Base; Right : Imaginary) return Imaginary is
  209.    begin
  210.       return Imaginary (Left * R (Right));
  211.    end "*";
  212.  
  213.    ---------
  214.    -- "/" --
  215.    ---------
  216.  
  217.    function "/" (Left, Right : Complex) return Complex is
  218.       a : constant R := Left.Re;
  219.       b : constant R := Left.Im;
  220.       c : constant R := Right.Re;
  221.       d : constant R := Right.Im;
  222.  
  223.    begin
  224.       if c = 0.0 and then d = 0.0 then
  225.          raise Constraint_Error;
  226.       else
  227.          return Complex'(Re => ((a * c) + (b * d)) / (c ** 2 + d ** 2),
  228.                          Im => ((b * c) - (a * d)) / (c ** 2 + d ** 2));
  229.       end if;
  230.    end "/";
  231.  
  232.    function "/" (Left, Right : Imaginary) return Real'Base is
  233.    begin
  234.       return R (Left) / R (Right);
  235.    end "/";
  236.  
  237.    function "/" (Left : Complex; Right : Real'Base) return Complex is
  238.    begin
  239.       return Complex'(Left.Re / Right, Left.Im / Right);
  240.    end "/";
  241.  
  242.    function "/" (Left : Real'Base; Right : Complex) return Complex is
  243.       a : constant R := Left;
  244.       c : constant R := Right.Re;
  245.       d : constant R := Right.Im;
  246.    begin
  247.       return Complex'(Re =>  (a * c) / (c ** 2 + d ** 2),
  248.                       Im => -(a * d) / (c ** 2 + d ** 2));
  249.    end "/";
  250.  
  251.    function "/" (Left : Complex; Right : Imaginary) return Complex is
  252.       a : constant R := Left.Re;
  253.       b : constant R := Left.Im;
  254.       d : constant R := R (Right);
  255.  
  256.    begin
  257.       return (b / d,  -a / d);
  258.    end "/";
  259.  
  260.    function "/" (Left : Imaginary; Right : Complex) return Complex is
  261.       b : constant R := R (Left);
  262.       c : constant R := Right.Re;
  263.       d : constant R := Right.Im;
  264.  
  265.    begin
  266.       return (Re => b * d / (c ** 2 + d ** 2),
  267.               Im => b * c / (c ** 2 + d ** 2));
  268.    end "/";
  269.  
  270.    function "/" (Left : Imaginary; Right : Real'Base) return Imaginary is
  271.    begin
  272.       return Imaginary (R (Left) / Right);
  273.    end "/";
  274.  
  275.    function "/" (Left : Real'Base; Right : Imaginary) return Imaginary is
  276.    begin
  277.       return Imaginary (-Left / R (Right));
  278.    end "/";
  279.  
  280.    ----------
  281.    -- "**" --
  282.    ----------
  283.  
  284.    function "**" (Left : Complex; Right : Integer) return Complex is
  285.       Result : Complex := (1.0, 0.0);
  286.       Factor : Complex := Left;
  287.       Exp    : Natural := Right;
  288.  
  289.    begin
  290.       --  We use the standard logarithmic approach, Exp gets shifted right
  291.       --  testing successive low order bits and Factor is the value of the
  292.       --  base raised to the next power of 2. For positive exponents we
  293.       --  multiply the result by this factor, for negative exponents, we
  294.       --  divide by this factor.
  295.  
  296.       if Exp >= 0 then
  297.  
  298.          --  For a positive exponent, if we get a constraint error during
  299.          --  this loop, it is an overflow, and the constraint error will
  300.          --  simply be passed on to the caller.
  301.  
  302.          while Exp /= 0 loop
  303.             if Exp rem 2 /= 0 then
  304.                Result := Result * Factor;
  305.             end if;
  306.  
  307.             Factor := Factor * Factor;
  308.             Exp := Exp / 2;
  309.          end loop;
  310.  
  311.          return Result;
  312.  
  313.       else -- Exp < 0 then
  314.  
  315.          --  For the negative exponent case, a constraint error during this
  316.          --  calculation happens if Factor gets too large, and the proper
  317.          --  response is to return 0.0, since what we essentially have is
  318.          --  1.0 / infinity, and the closest model number will be zero.
  319.  
  320.          begin
  321.  
  322.             while Exp /= 0 loop
  323.                if Exp rem 2 /= 0 then
  324.                   Result := Result * Factor;
  325.                end if;
  326.  
  327.                Factor := Factor * Factor;
  328.                Exp := Exp / 2;
  329.             end loop;
  330.  
  331.             return R ' (1.0) / Result;
  332.  
  333.          exception
  334.  
  335.             when Constraint_Error =>
  336.                return (0.0, 0.0);
  337.          end;
  338.       end if;
  339.    end "**";
  340.  
  341.    function "**" (Left : Imaginary; Right : Integer) return Complex is
  342.       M : R := R (Left) ** Right;
  343.    begin
  344.       case Right mod 4 is
  345.          when 0 => return (M,   0.0);
  346.          when 1 => return (0.0, M);
  347.          when 2 => return (-M,  0.0);
  348.          when 3 => return (0.0, -M);
  349.          when others => raise Program_Error;
  350.       end case;
  351.    end "**";
  352.  
  353.    ---------
  354.    -- "<" --
  355.    ---------
  356.  
  357.    function "<" (Left, Right : Imaginary) return Boolean is
  358.    begin
  359.       return R (Left) < R (Right);
  360.    end "<";
  361.  
  362.    ----------
  363.    -- "<=" --
  364.    ----------
  365.  
  366.    function "<=" (Left, Right : Imaginary) return Boolean is
  367.    begin
  368.       return R (Left) <= R (Right);
  369.    end "<=";
  370.  
  371.    ---------
  372.    -- ">" --
  373.    ---------
  374.  
  375.    function ">" (Left, Right : Imaginary) return Boolean is
  376.    begin
  377.       return R (Left) > R (Right);
  378.    end ">";
  379.  
  380.    ----------
  381.    -- ">=" --
  382.    ----------
  383.  
  384.    function ">=" (Left, Right : Imaginary) return Boolean is
  385.    begin
  386.       return R (Left) >= R (Right);
  387.    end ">=";
  388.  
  389.    -----------
  390.    -- "abs" --
  391.    -----------
  392.  
  393.    function "abs" (Right : Imaginary) return Real'Base is
  394.    begin
  395.       return abs R (Right);
  396.    end "abs";
  397.  
  398.    --------------
  399.    -- Argument --
  400.    --------------
  401.  
  402.    function Argument (X : Complex) return Real'Base is
  403.       a   : constant R := X.Re;
  404.       b   : constant R := X.Im;
  405.       arg : R;
  406.  
  407.    begin
  408.       if b = 0.0 then
  409.  
  410.          if a >= 0.0 then
  411.             return 0.0;
  412.          else
  413.             return R'Copy_Sign (Pi, b);
  414.          end if;
  415.  
  416.       elsif a = 0.0 then
  417.  
  418.          if b >= 0.0 then
  419.             return Half_Pi;
  420.          else
  421.             return -Half_Pi;
  422.          end if;
  423.  
  424.       else
  425.          arg := R (Atan (Double (abs (b / a))));
  426.  
  427.          if a > 0.0 then
  428.             if b > 0.0 then
  429.                return arg;
  430.             else                  --  b < 0.0
  431.                return -arg;
  432.             end if;
  433.  
  434.          else                     --  a < 0.0
  435.             if b >= 0.0 then
  436.                return Pi - arg;
  437.             else                  --  b < 0.0
  438.                return -(Pi - arg);
  439.             end if;
  440.          end if;
  441.       end if;
  442.  
  443.    exception
  444.       when Constraint_Error =>
  445.          if b > 0.0 then
  446.             return Half_Pi;
  447.          else
  448.             return -Half_Pi;
  449.          end if;
  450.    end Argument;
  451.  
  452.    function Argument (X : Complex; Cycle : Real'Base) return Real'Base is
  453.    begin
  454.       if Cycle > 0.0 then
  455.          return Argument (X) * Cycle / Two_Pi;
  456.       else
  457.          raise Argument_Error;
  458.       end if;
  459.    end Argument;
  460.  
  461.    ----------------------------
  462.    -- Compose_From_Cartesian --
  463.    ----------------------------
  464.  
  465.    function Compose_From_Cartesian (Re, Im : Real'Base) return Complex is
  466.    begin
  467.       return (Re, Im);
  468.    end Compose_From_Cartesian;
  469.  
  470.    function Compose_From_Cartesian (Re : Real'Base) return Complex is
  471.    begin
  472.       return (Re, 0.0);
  473.    end Compose_From_Cartesian;
  474.  
  475.    function Compose_From_Cartesian (Im : Imaginary) return Complex is
  476.    begin
  477.       return (0.0, R (Im));
  478.    end Compose_From_Cartesian;
  479.  
  480.    ------------------------
  481.    -- Compose_From_Polar --
  482.    ------------------------
  483.  
  484.    function Compose_From_Polar (
  485.      Modulus, Argument : Real'Base)
  486.      return Complex
  487.    is
  488.    begin
  489.       if Modulus = 0.0 then
  490.          return (0.0, 0.0);
  491.       else
  492.          return (Modulus * R (Cos (Double (Argument))),
  493.                  Modulus * R (Sin (Double (Argument))));
  494.       end if;
  495.    end Compose_From_Polar;
  496.  
  497.    function Compose_From_Polar (
  498.      Modulus, Argument, Cycle : Real'Base)
  499.      return Complex
  500.    is
  501.       Arg : Real'Base;
  502.  
  503.    begin
  504.       if Modulus = 0.0 then
  505.          return (0.0, 0.0);
  506.  
  507.       elsif Cycle > 0.0 then
  508.          if Argument = 0.0 then
  509.             return (Modulus, 0.0);
  510.  
  511.          elsif Argument = Cycle / 4.0 then
  512.             return (0.0, Modulus);
  513.  
  514.          elsif Argument = Cycle / 2.0 then
  515.             return (-Modulus, 0.0);
  516.  
  517.          elsif Argument = 3.0 * Cycle / R (4.0) then
  518.             return (0.0, -Modulus);
  519.          else
  520.             Arg := Two_Pi * Argument / Cycle;
  521.             return (Modulus * R (Cos (Double (Arg))),
  522.                     Modulus * R (Sin (Double (Arg))));
  523.          end if;
  524.       else
  525.          raise Argument_Error;
  526.       end if;
  527.    end Compose_From_Polar;
  528.  
  529.    ---------------
  530.    -- Conjugate --
  531.    ---------------
  532.  
  533.    function Conjugate (X : Complex) return Complex is
  534.    begin
  535.       return Complex'(X.Re, -X.Im);
  536.    end Conjugate;
  537.  
  538.    --------
  539.    -- Im --
  540.    --------
  541.  
  542.    function Im (X : Complex) return Real'Base is
  543.    begin
  544.       return X.Im;
  545.    end Im;
  546.  
  547.    function Im (X : Imaginary) return Real'Base is
  548.    begin
  549.       return R (X);
  550.    end Im;
  551.  
  552.    -------------
  553.    -- Modulus --
  554.    -------------
  555.  
  556.    function Modulus (X : Complex) return Real'Base is
  557.       Re2, Im2 : R;
  558.  
  559.    begin
  560.  
  561.       begin
  562.          Re2 := X.Re ** 2;
  563.  
  564.          --  To compute (a**2 + b**2) ** (0.5) when a**2 may be out of bounds,
  565.          --  compute a * (1 + (b/a) **2) ** (0.5). On a machine where the
  566.          --  squaring does not raise constraint_error but generates infinity,
  567.          --  we can use an explicit comparison to determine whether to use
  568.          --  the scaling expression.
  569.  
  570.          if Re2 > R'Last then
  571.             raise Constraint_Error;
  572.          end if;
  573.  
  574.       exception
  575.          when Constraint_Error =>
  576.             return abs (X.Re)
  577.               * R (Sqrt (Double (R (1.0) + (X.Im / X.Re) ** 2)));
  578.       end;
  579.  
  580.       begin
  581.          Im2 := X.Im ** 2;
  582.  
  583.          if Im2 > R'Last then
  584.             raise Constraint_Error;
  585.          end if;
  586.  
  587.       exception
  588.          when Constraint_Error =>
  589.             return abs (X.Im)
  590.               * R (Sqrt (Double (R (1.0) + (X.Re / X.Im) ** 2)));
  591.       end;
  592.  
  593.       --  Now deal with cases of underflow. If only one of the squares
  594.       --  underflows, return the modulus of the other component. If both
  595.       --  squares underflow, use scaling as above.
  596.  
  597.       if Re2 = 0.0 then
  598.  
  599.          if X.Re = 0.0 then
  600.             return abs (X.Im);
  601.  
  602.          elsif Im2 = 0.0 then
  603.  
  604.             if X.Im = 0.0 then
  605.                return abs (X.Re);
  606.  
  607.             else
  608.                if abs (X.Re) > abs (X.Im) then
  609.                   return
  610.                     abs (X.Re)
  611.                       * R (Sqrt (Double (R (1.0) + (X.Im / X.Re) ** 2)));
  612.                else
  613.                   return
  614.                     abs (X.Im)
  615.                       * R (Sqrt (Double (R (1.0) + (X.Re / X.Im) ** 2)));
  616.                end if;
  617.             end if;
  618.  
  619.          else
  620.             return abs (X.Im);
  621.          end if;
  622.  
  623.  
  624.       elsif Im2 = 0.0 then
  625.          return abs (X.Re);
  626.  
  627.          --  in all other cases, the naive computation will do.
  628.  
  629.       else
  630.          return R (Sqrt (Double (Re2 + Im2)));
  631.       end if;
  632.    end Modulus;
  633.  
  634.    --------
  635.    -- Re --
  636.    --------
  637.  
  638.    function Re (X : Complex) return Real'Base is
  639.    begin
  640.       return X.Re;
  641.    end Re;
  642.  
  643.    ------------
  644.    -- Set_Im --
  645.    ------------
  646.  
  647.    procedure Set_Im (X : in out Complex; Im : in Real'Base) is
  648.    begin
  649.       X.Im := Im;
  650.    end Set_Im;
  651.  
  652.    procedure Set_Im (X : out Imaginary; Im : in Real'Base) is
  653.    begin
  654.       X := Imaginary (Im);
  655.    end Set_Im;
  656.  
  657.    ------------
  658.    -- Set_Re --
  659.    ------------
  660.  
  661.    procedure Set_Re (X : in out Complex; Re : in Real'Base) is
  662.    begin
  663.       X.Re := Re;
  664.    end Set_Re;
  665.  
  666. end Ada.Numerics.Generic_Complex_Types;
  667.