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
/
a-ngcefu.adb
< prev
next >
Wrap
Text File
|
1996-09-28
|
18KB
|
669 lines
------------------------------------------------------------------------------
-- --
-- GNAT RUNTIME COMPONENTS --
-- --
-- A D A . N U M E R I C S . G C E F --
-- --
-- B o d y --
-- --
-- $Revision: 1.2 $ --
-- --
-- Copyright (c) 1992,1993,1994 NYU, All Rights Reserved --
-- --
-- The GNAT library is free software; you can redistribute it and/or modify --
-- it under terms of the GNU Library General Public License as published by --
-- the Free Software Foundation; either version 2, or (at your option) any --
-- later version. The GNAT library is distributed in the hope that it will --
-- be useful, but WITHOUT ANY WARRANTY; without even the implied warranty --
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
-- Library General Public License for more details. You should have --
-- received a copy of the GNU Library General Public License along with --
-- the GNAT library; see the file COPYING.LIB. If not, write to the Free --
-- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
-- This is an early trial implementation, simplified for early gnat.
-- It is not a "strict" implementation.
-- All Ada required exception handling is provided.
-- Many special cases are handled locally to avoid unnecessary calls
with Ada.Numerics.Generic_Elementary_Functions;
package body Ada.Numerics.Generic_Complex_Elementary_Functions is
package Elementary_Functions is new
Ada.Numerics.Generic_Elementary_Functions (Real'Base);
use Elementary_Functions;
PI : constant := 3.14159_26535_89793_23846_26433_83279_50288_41971;
PI_2 : constant := PI / 2.0;
Log_Two : constant := 0.69314_71805_59945_30941_72321_21458_17656_80755;
Epsilon : Real'Base;
Square_Root_Epsilon : Real'Base;
Inv_Square_Root_Epsilon : Real'Base;
Root_Root_Epsilon : Real'Base;
Log_Inverse_Epsilon_2 : Real'Base;
Complex_Zero : constant Complex := Compose_From_Cartesian (0.0, 0.0);
Complex_One : constant Complex := Compose_From_Cartesian (1.0, 0.0);
Complex_I : constant Complex := Compose_From_Cartesian (0.0, 1.0);
HALF_PI : constant Complex := Compose_From_Cartesian (PI_2, 0.0);
----------
-- Sqrt --
----------
function Sqrt (X : Complex) return Complex is
Z : Complex := X; -- remove if definition gets fixed
R : Real'Base;
R_X : Real'Base;
R_Y : Real'Base;
XR : Real'Base := abs Re (Z);
YR : Real'Base := abs Im (Z);
A : Real'Base;
begin
if XR > YR then
A := YR / XR;
A := A * A;
if A < 32.0 * Square_Root_Epsilon then
if Re (Z) > 0.0 then
R_X := Sqrt (XR + 0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
R_Y := Sqrt (0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
else
R_X := Sqrt (0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
R_Y := Sqrt (XR + 0.5 *
(0.5 * YR * YR / XR - (YR * YR / XR) * A / 8.0));
end if;
else
R := XR * Sqrt (1.0 + A);
R_X := Sqrt (0.5 * (R + Re (Z)));
R_Y := Sqrt (0.5 * (R - Re (Z)));
end if;
else -- YR > XR
A := XR / YR;
A := A * A;
if A < 32.0 * Square_Root_Epsilon then -- YR >> XR
R := YR + 0.5 * XR * XR / YR - 0.125 * (XR * XR / YR) * A;
R_X := Sqrt (0.5 * (YR + (0.5 * XR * XR / YR + Re (Z))));
R_Y := Sqrt (0.5 * (YR + (0.5 * XR * XR / YR - Re (Z))));
else
R := YR * Sqrt (1.0 + A);
R_X := Sqrt (0.5 * (R + Re (Z)));
R_Y := Sqrt (0.5 * (R - Re (Z)));
end if;
end if;
if Im (Z) < 0.0 then -- halve angle, Sqrt of magnitude
R_Y := -R_Y;
end if;
return Compose_From_Cartesian (R_X, R_Y);
exception
when Constraint_Error =>
R := Modulus (Compose_From_Cartesian (Re (Z / 4.0), Im (Z / 4.0)));
R_X := 2.0 * Sqrt (0.5 * R + 0.5 * Re (Z / 4.0));
R_Y := 2.0 * Sqrt (0.5 * R - 0.5 * Re (Z / 4.0));
if Im (Z) < 0.0 then -- halve angle, Sqrt of magnitude
R_Y := -R_Y;
end if;
return Compose_From_Cartesian (R_X, R_Y);
end Sqrt;
---------
-- Log --
---------
function Log (X : Complex) return Complex is
Z : Complex := X;
RE_Z, IM_Z : Real'Base;
begin
if Re (Z) = 0.0 and then Im (Z) = 0.0 then
raise Constraint_Error;
elsif abs (1.0 - Re (Z)) < Root_Root_Epsilon and then
abs Im (Z) < Root_Root_Epsilon then
Set_Re (Z, Re (Z) - 1.0);
return (1.0 - (1.0 / 2.0 -
(1.0 / 3.0 - (1.0 / 4.0) * Z) * Z) * Z) * Z;
end if;
begin
RE_Z := Log (Modulus (Z));
exception
when Constraint_Error =>
RE_Z := Log (Modulus (Z / 2.0)) - Log_Two;
end;
IM_Z := Arctan (Im (Z), Re (Z));
if IM_Z > PI then
IM_Z := IM_Z - 2.0 * PI;
end if;
return Compose_From_Cartesian (RE_Z, IM_Z);
end Log;
---------
-- Exp --
---------
function Exp (X : Complex) return Complex is
Z : Complex := X;
EXP_RE_Z : Real'Base := Exp (Re (Z));
begin
return Compose_From_Cartesian (EXP_RE_Z * Cos (Im (Z)),
EXP_RE_Z * Sin (Im (Z)));
end Exp;
function Exp (X : Imaginary) return Complex is
IM_Z : Real'Base := Im (X);
begin
return Compose_From_Cartesian (Cos (IM_Z), Sin (IM_Z));
end Exp;
--------
-- ** --
--------
function "**"
(Left : Complex;
Right : Complex)
return Complex is
Z1 : Complex := Left;
Z2 : Complex := Right;
begin
if Re (Z2) = 0.0 and then Im (Z2) = 0.0 and then
Re (Z1) = 0.0 and then Im (Z1) = 0.0 then
raise Argument_Error;
elsif Re (Z1) = 0.0 and then Im (Z1) = 0.0 and then
Re (Z2) < 0.0 then
raise Constraint_Error;
elsif Re (Z1) = 0.0 and then Im (Z1) = 0.0 then
return Z1;
elsif Re (Z2) = 0.0 and then Im (Z2) = 0.0 then
return 1.0 + Z2;
elsif Re (Z2) = 1.0 and then Im (Z2) = 0.0 then
return Z1;
else
return Exp (Z2 * Log (Z1));
end if;
end "**";
function "**"
(Left : Real'Base;
Right : Complex)
return Complex is
X : Real'Base := Left;
Z : Complex := Right;
begin
if Re (Z) = 0.0 and then Im (Z) = 0.0 and then
X = 0.0 then
raise Argument_Error;
elsif X = 0.0 and then Re (Z) < 0.0 then
raise Constraint_Error;
elsif X = 0.0 then
return Compose_From_Cartesian (X, 0.0);
elsif Re (Z) = 0.0 and then Im (Z) = 0.0 then
return Complex_One;
elsif Re (Z) = 1.0 and then Im (Z) = 0.0 then
return Compose_From_Cartesian (X, 0.0);
else
return Exp (Log (X) * Z);
end if;
end "**";
function "**" (Left : Complex;
Right : Real'Base) return Complex is
Z : Complex := Left;
Y : Real'Base := Right;
begin
if Y = 0.0 and then
Re (Z) = 0.0 and then Im (Z) = 0.0 then
raise Argument_Error;
elsif Re (Z) = 0.0 and then Im (Z) = 0.0 and then
Y < 0.0 then
raise Constraint_Error;
elsif Re (Z) = 0.0 and then Im (Z) = 0.0 then
return Z;
elsif Y = 0.0 then
return Complex_One;
elsif Y = 1.0 then
return Z;
else
return Exp (Y * Log (Z));
end if;
end "**";
---------
-- Sin --
---------
function Sin (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
end if;
return Compose_From_Cartesian (Sin (Re (Z)) * Cosh (Im (Z)),
Cos (Re (Z)) * Sinh (Im (Z)));
end Sin;
---------
-- Cos --
---------
function Cos (X : Complex) return Complex is
Z : Complex := X;
begin
return Compose_From_Cartesian (Cos (Re (Z)) * Cosh (Im (Z)),
-Sin (Re (Z)) * Sinh (Im (Z)));
end Cos;
---------
-- Tan --
---------
function Tan (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
elsif Im (Z) > Log_Inverse_Epsilon_2 then
return Complex_I;
elsif Im (Z) < -Log_Inverse_Epsilon_2 then
return -Complex_I;
end if;
return Sin (Z) / Cos (Z);
end Tan;
---------
-- Cot --
---------
function Cot (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Complex_One / Z;
elsif Im (Z) > Log_Inverse_Epsilon_2 then
return -Complex_I;
elsif Im (Z) < -Log_Inverse_Epsilon_2 then
return Complex_I;
end if;
return Cos (Z) / Sin (Z);
end Cot;
------------
-- Arcsin --
------------
function Arcsin (X : Complex) return Complex is
Z : Complex := X;
ZA : Complex := Z;
Result : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
elsif abs Re (Z) > Inv_Square_Root_Epsilon or
abs Im (Z) > Inv_Square_Root_Epsilon then
Result := -Complex_I * (Log (Complex_I * Z) + Log (2.0 * Complex_I));
if Im (Result) > PI_2 then
Set_Im (Result, PI - Im (Z));
elsif Im (Result) < -PI_2 then
Set_Im (Result, -(PI + Im (Z)));
end if;
end if;
Result := -Complex_I * Log (Complex_I * Z + Sqrt (1.0 - Z * Z));
if Re (Z) = 0.0 then
Set_Re (Result, Re (Z));
elsif Im (Z) = 0.0 then
Set_Im (Result, Im (Z));
end if;
return Result;
end Arcsin;
------------
-- Arccos --
------------
function Arccos (X : Complex) return Complex is
Z : Complex := X;
Result : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return HALF_PI - Z;
elsif abs Re (Z) > Inv_Square_Root_Epsilon or
abs Im (Z) > Inv_Square_Root_Epsilon then
return -2.0 * Complex_I * Log (Sqrt ((1.0 + Z) / 2.0) +
Complex_I * Sqrt ((1.0 - Z) / 2.0));
end if;
Result := -Complex_I * Log (Z + Complex_I * Sqrt (1.0 - Z * Z));
if Im (Z) = 0.0 then
Set_Im (Result, Im (Z));
end if;
return Result;
end Arccos;
------------
-- Arctan --
------------
function Arctan (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
end if;
return -Complex_I * (Log (1.0 + Complex_I * Z)
- Log (1.0 - Complex_I * Z)) / 2.0;
end Arctan;
------------
-- Arccot --
------------
function Arccot (X : Complex) return Complex is
Z : Complex := X;
Zt : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return HALF_PI - Z;
elsif abs Re (Z) > 1.0 / Epsilon or
abs Im (Z) > 1.0 / Epsilon then
Zt := Complex_One / Z;
if Re (Z) < 0.0 then
Set_Re (Zt, PI - Re (Zt));
return Zt;
else
return Zt;
end if;
end if;
Zt := Complex_I * Log ((Z - Complex_I) / (Z + Complex_I)) / 2.0;
if Re (Zt) < 0.0 then
Zt := PI + Zt;
end if;
return Zt;
end Arccot;
----------
-- Sinh --
----------
function Sinh (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
end if;
return Compose_From_Cartesian (Sinh (Re (Z)) * Cos (Im (Z)),
Cosh (Re (Z)) * Sin (Im (Z)));
end Sinh;
----------
-- Cosh --
----------
function Cosh (X : Complex) return Complex is
Z : Complex := X;
begin
return Compose_From_Cartesian (Cosh (Re (Z)) * Cos (Im (Z)),
Sinh (Re (Z)) * Sin (Im (Z)));
end Cosh;
----------
-- Tanh --
----------
function Tanh (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
elsif Re (Z) > Log_Inverse_Epsilon_2 then
return Complex_One;
elsif Re (Z) < -Log_Inverse_Epsilon_2 then
return -Complex_One;
end if;
return Sinh (Z) / Cosh (Z);
end Tanh;
----------
-- Coth --
----------
function Coth (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Complex_One / X;
elsif Re (X) > Log_Inverse_Epsilon_2 then
return Complex_One;
elsif Re (X) < -Log_Inverse_Epsilon_2 then
return -Complex_One;
end if;
return Cosh (Z) / Sinh (Z);
end Coth;
-------------
-- Arcsinh --
-------------
function Arcsinh (X : Complex) return Complex is
Z : Complex := X;
Result : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
elsif abs Re (Z) > Inv_Square_Root_Epsilon or
abs Im (Z) > Inv_Square_Root_Epsilon then
Result := Log_Two + Log (Z); -- may have wrong sign
if (Re (Z) < 0.0 and Re (Result) > 0.0)
or else (Re (Z) > 0.0 and Re (Result) < 0.0)
then
Set_Re (Result, -Re (Result));
end if;
return Result;
end if;
Result := Log (Z + Sqrt (1.0 + Z*Z));
if Re (Z) = 0.0 then
Set_Re (Result, Re (Z));
elsif Im (Z) = 0.0 then
Set_Im (Result, Im (Z));
end if;
return Result;
end Arcsinh;
-------------
-- Arccosh --
-------------
function Arccosh (X : Complex) return Complex is
Z : Complex := X;
Result : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
Result := Compose_From_Cartesian (-Im (Z), -PI_2 + Re (Z));
elsif abs Re (Z) > Inv_Square_Root_Epsilon or
abs Im (Z) > Inv_Square_Root_Epsilon then
Result := Log_Two + Log (Z);
else
Result := 2.0 * Log (Sqrt ((1.0 + Z) / 2.0) +
Sqrt ((Z - 1.0) / 2.0));
end if;
if Re (Result) <= 0.0 then
Result := -Result;
end if;
return Result;
end Arccosh;
-------------
-- Arctanh --
-------------
function Arctanh (X : Complex) return Complex is
Z : Complex := X;
begin
if abs Re (Z) < Square_Root_Epsilon and then
abs Im (Z) < Square_Root_Epsilon then
return Z;
end if;
return (Log (1.0 + Z) - Log (1.0 - Z)) / 2.0;
end Arctanh;
--------------
-- Arctcoth --
--------------
function Arccoth (X : Complex) return Complex is
Z : Complex := X;
R : Complex;
begin
if abs Re (Z) < Square_Root_Epsilon
and then abs Im (Z) < Square_Root_Epsilon
then
return PI_2 * Complex_I + Z;
elsif abs Re (Z) > 1.0 / Epsilon or else
abs Im (Z) > 1.0 / Epsilon then
if Im (Z) > 0.0 then
return Complex_Zero;
else
return PI * Complex_I;
end if;
elsif Im (Z) = 0.0 and then Re (Z) = 1.0 then
raise Constraint_Error;
elsif Im (Z) = 0.0 and then Re (Z) = -1.0 then
raise Constraint_Error;
end if;
begin
R := Log ((1.0 + Z) / (Z - 1.0)) / 2.0;
exception
when Constraint_Error =>
R := (Log (1.0 + Z) - Log (Z - 1.0)) / 2.0;
end;
if Im (R) < 0.0 then
Set_Im (R, PI + Im (R));
end if;
if Re (Z) = 0.0 then
Set_Re (R, Re (Z));
end if;
return R;
end Arccoth;
begin -- initialize needed pseudo-constants
Epsilon := Real (Real'Model_Epsilon);
while Epsilon / Real (Real'Machine_Radix) + 1.0 /= 1.0 loop
Epsilon := Epsilon / Real (Real'Machine_Radix);
end loop;
Square_Root_Epsilon := Sqrt (Epsilon);
Inv_Square_Root_Epsilon := 1.0 / Square_Root_Epsilon;
Root_Root_Epsilon := Sqrt (Square_Root_Epsilon);
Log_Inverse_Epsilon_2 := Log (1.0 / Epsilon) / 2.0;
end Ada.Numerics.Generic_Complex_Elementary_Functions;