module mpi_ari; {============================================================================} {=== mpi_ari ====== Multi-Precision Interval Arithmetic ===============} {==================== = = = === ===============} {============================================================================} { } { File : MPI_ARI.P } { } {= Version : 1.1 } { } {= Date : 10/07/91 ( first implementation ) } {= 03/21/95 ( last change ) } { } { Language: PASCAL-XSC, Vers. 3.0 or later } { } { Authors : W. Kraemer, W. Hofschuster, R. Hammer } { } { Site : Institute for Applied Mathematics (IAM), } { University of Karlsruhe, } { 76128 Karlsruhe, Germany. } { } { Tel. : +49 721 608-6013 (W. Kraemer) } { Fax : +49 721 69 52 83 (IAM) } {----------------------------------------------------------------------------} { } { Short Description: } { ------------------ } { Module for multi-precision interval arithmetic. This module is based } { on module MP_ARI for real multi-precision arithmetic. } { } { Literature: } { ----------- } { [1] W. Kraemer: Eine portable Langzahl- und Langzahlintervallarithme- } { tik mit Anwendungen. ZAMM 73, 1992. } { } { [2] W. Kraemer: Die Berechnung von Standardfunktionen in Rechenanla- } { gen. In Chatterji, S., Fuchssteiner, B., Kulisch, U., } { Liedl, R., Purkert, W. (Eds): Jahrbuch Ueberblicke } { Mathematik 1992, Vieweg, Braunschweig, 1992. } { } { [3] W. Kraemer: Multiple-Precision Computations with Result Verifica- } { tion. In Adams, E., Kulisch, U. (Eds.): Scientific } { Computing with Automatic Result Verification. } { Academic Press, San Diego, 1993. } { } { [4] R. Hammer : Multi-Precision Arithmetic in PASCAL-XSC, Implementa- } { tion and Apllication. Special Issue of the SCAN-93 } { and the MMSC'93, Math. and Comp. for Simulation, to } { appear 1994. } {============================================================================} use iostd, { For exception handling } i_ari; { Interval arithmetic } use global mp_ari; { Real multi-precision arithmetic } {============================================================================} {========== Datatypes and Variables =====================================} {============================================================================} { Multi-precision interval data type: } global type mpinterval = global record inf, sup: mpreal; end; var one : mpreal; { mpreal and mpinterval } ione : mpinterval; { constants for 1 } {============================================================================} {========== Memory Management ===========================================} {============================================================================} global procedure mpinit( var x : mpinterval ); { Initialize a mpinterval } begin { variable } mpinit(x.inf); mpinit(x.sup); end; global procedure mpvlcp ( var x : mpinterval ); { Get a local copy of a } begin { mpinterval variable } mpvlcp(x.inf); mpvlcp(x.sup); end; global procedure mpfree ( var x : mpinterval ); { Free a mpinterval } begin { variable } mpfree(x.inf); mpfree(x.sup); end; {============================================================================} {========== I/O - Routines ==============================================} {============================================================================} global procedure read( var t : text; var x : mpinterval ); { Input without } begin { brackets } read(t,x.inf:-1); { round downwards } {---------------} read(t,x.sup:+1); { round upwards } end; global procedure write( var t : text; x : mpinterval ); begin mpvlcp(x); writeln(t,x.inf:0:0:-1); write (t,x.sup:0:0:+1); mpfree(x); end; {============================================================================} {========== Exception Handling ==========================================} {============================================================================} const { Error codes } div_by_zero = 1; {-------------} sqrt_range = 10; ln_range = 20; loga_range = 21; log2_range = 22; log10_range = 23; power_range = 30; power_notdef = 31; arcsin_range = 40; arccos_range = 41; sin_range = 50; cos_range = 51; tan_range = 52; cot_range = 53; coth_range = 60; arcosh_range = 70; artanh_range = 71; arcoth_range = 72; procedure traceback( var t : text ); external f_back ; procedure exit( ReturnCode : integer ); external a_exit; procedure _math_message( ErrNo : integer; var Arg1, Arg2 : mpinterval ); var Msg : text; begin rewrite(Msg,stderr); write(Msg,'MPI_ARI.P: !!! ERROR !!! '); case (ErrNo) of div_by_zero : writeln(Msg,'Division by 0 in MPI / MPI !'); sqrt_range : writeln(Msg,'Range error in sqrt(MPI)!'); ln_range : writeln(Msg,'Range error in ln(MPI)!'); loga_range : writeln(Msg,'Range error in loga(MPI)!'); log2_range : writeln(Msg,'Range error in log2(MPI)!'); log10_range : writeln(Msg,'Range error in log10(MPI)!'); power_range : writeln(Msg,'Range error in power(MPI,MPI)!'); power_notdef : writeln(Msg,'0^0 not defined for power(MPI,MPI)!'); arcsin_range : writeln(Msg,'Range error in arcsin(MPI)!'); arccos_range : writeln(Msg,'Range error in arccos(MPI)!'); sin_range : writeln(Msg,'Range error in sin(MPI)!'); cos_range : writeln(Msg,'Range error in cos(MPI)!'); tan_range : writeln(Msg,'Range error in tan(MPI)!'); cot_range : writeln(Msg,'Range error in tan(MPI)!'); coth_range : writeln(Msg,'Range error in coth(MPI)!'); arcosh_range : writeln(Msg,'Range error in arcosh(MPI)!'); artanh_range : writeln(Msg,'Range error in artanh(MPI)!'); arcoth_range : writeln(Msg,'Range error in arcoth(MPI)!'); else : writeln(Msg,'Unknown error!'); end ; if (ErrNo in [div_by_zero,power_range,power_notdef]) then begin { Error message for two arguments } writeln(Msg,'First argument:'); writeln(Msg,Arg1); writeln(Msg,'Second argument:'); writeln(Msg,Arg2); end else { Second argument is a dummy } begin writeln(Msg,'Argument: '); writeln(Msg,Arg1); end; traceback(Msg); exit(-1); end; {============================================================================} {========== Special Assignment Operators =================================} {============================================================================} {= A special assignment operator is used to initialize the result variable of } {= a function (InitFunc) or operator (InitOp) or to mark the result variable } {= to be temporary (TempFunc, TempOp). 'InitFunc' and 'InitOp' are synonyms. } {= 'TempFunc' and 'TempOp' are also synonyms. For compatibility to older } {= versions of the multi-precision modules there also exists an assignment } {= operator of type boolean. The value 'true' is equivalent to 'InitFunc' and } {= 'InitOp', the value 'false' is equivalent to 'TempFunc' and 'TempOp'. For } {= definition of type 'mpmode' see module mp_ari. } {=---------------------------------------------------------------------------} global operator := ( var x : mpinterval; mode : mpmode ); begin case mode of InitFunc, InitOp : begin mpinit(x.inf); mpinit(x.sup); end; TempFunc, TempOp : begin mptemp(x.inf); mptemp(x.sup); end; else: { No action } end; end; global operator := ( var x : mpinterval; mode : boolean ); begin if (mode) then begin mpinit(x.inf); mpinit(x.sup); end else begin mptemp(x.inf); mptemp(x.sup); end; end; {============================================================================} {========== Assignment Operators ========================================} {============================================================================} global operator := ( var x : mpinterval; { mpinterval := mpinterval } y : mpinterval ); {--------------------------} begin mpvlcp(y); x.inf := y.inf; x.sup := y.sup; mpfree(y); end; global operator := ( var x : mpinterval; { mpinterval := interval } y : interval ); {------------------------} begin x.inf := y.inf; x.sup := y.sup; end; global operator := ( var x : mpinterval; { mpinterval := mpreal } y : mpreal ); {----------------------} begin mpvlcp(y); x.inf := y; x.sup := y; mpfree(y); end; global operator := ( var x : mpinterval; { mpinterval := real } r : real ); {--------------------} begin x.inf := _mpreal(r,-1); x.sup := _mpreal(r,+1); end; global operator := ( var x : interval; { interval := mpinterval } y : mpinterval ); {------------------------} begin mpvlcp(y); x.inf := _real(y.inf,-1); x.sup := _real(y.sup,+1); mpfree(y); end; {============================================================================} {========== Functions for Type Coercions ================================} {============================================================================} global function _mpinterval( x : mpreal ) : mpinterval; { mpreal-coercion } begin {-----------------} mpvlcp(x); _mpinterval := InitFunc; _mpinterval := x; _mpinterval := TempFunc; mpfree(x); end; global function _mpinterval( x : interval ) : mpinterval; { interval-coerc. } begin {-----------------} _mpinterval := InitFunc; _mpinterval.inf := x.inf; _mpinterval.sup := x.sup; _mpinterval := TempFunc; end; global function _mpinterval( r : real ) : mpinterval; { real-coercion } begin {---------------} _mpinterval := InitFunc; _mpinterval := r; _mpinterval := TempFunc; end; {============================================================================} {========== Logical Operators: mpinterval <--> mpinterval ===============} {============================================================================} global operator = ( x, y : mpinterval ) eq : boolean; { Equality } begin {----------} mpvlcp(x); mpvlcp(y); eq := (x.inf = y.inf) and (x.sup = y.sup); mpfree(x); mpfree(y); end; global operator <> ( x, y : mpinterval ) neq : boolean; { Unequality } begin {------------} mpvlcp(x); mpvlcp(y); neq := (x.inf <> y.inf) or (x.sup <> y.sup); mpfree(x); mpfree(y); end; global operator <= ( x, y : mpinterval ) sub : boolean; { Subset } begin {--------} mpvlcp(x); mpvlcp(y); sub := (y.inf <= x.inf) and (x.sup <= y.sup); mpfree(x); mpfree(y); end; global operator < ( x, y : mpinterval ) psub : boolean; { Proper subset } begin {---------------} mpvlcp(x); mpvlcp(y); psub := (x <= y) and (x <> y); mpfree(x); mpfree(y); end; global operator >= ( x, y : mpinterval ) sup : boolean; { Superset } begin {----------} mpvlcp(x); mpvlcp(y); sup := (x.inf <= y.inf) and (y.sup <= x.sup); mpfree(x); mpfree(y); end; global operator > ( x, y : mpinterval ) psup : boolean; { Proper Superset } begin {-----------------} mpvlcp(x); mpvlcp(y); psup := (x >= y) and (x <> y); mpfree(x); mpfree(y); end; global operator in ( x, y : mpinterval ) cont : boolean; { Contained-in test } begin {-------------------} mpvlcp(x); mpvlcp(y); cont := (y.inf < x.inf) and (x.sup < y.sup); mpfree(x); mpfree(y); end; global operator >< ( x, y : mpinterval ) disj : boolean; { Disjointedness } begin {----------------} mpvlcp(x); mpvlcp(y); disj := (x.sup < y.inf) or (y.sup < x.inf); mpfree(x); mpfree(y); end; global function point( x : mpinterval ) : boolean; { Point interval test } begin {---------------------} mpvlcp(x); point := (x.inf = x.sup); mpfree(x); end; {============================================================================} {========== Logical Operators: mpreal <--> mpinterval ===============} {========== mpinterval <--> mpreal ===============} {============================================================================} global operator = ( x : mpinterval; a : mpreal ) eq : boolean; begin mpvlcp(x); mpvlcp(a); eq := (x.inf = a) and (x.sup = a); mpfree(a); mpfree(x); end; global operator = ( a : mpreal; x : mpinterval ) eq : boolean; begin mpvlcp(x); mpvlcp(a); eq := (a = x.inf) and (a = x.sup); mpfree(a); mpfree(x); end; global operator in ( a : mpreal; x : mpinterval ) cont : boolean; begin mpvlcp(x); mpvlcp(a); cont := (x.inf <= a) and (a <= x.sup); mpfree(a); mpfree(x); end; {============================================================================} {========== Logical Operators: real <--> mpinterval ===============} {========== mpinterval <--> real ===============} {============================================================================} global operator = ( x : mpinterval; r : real ) eq : boolean; begin mpvlcp(x); eq := (x.inf = r) and (x.sup = r); mpfree(x); end; global operator = ( r : real; x : mpinterval ) eq : boolean; begin mpvlcp(x); eq := (r = x.inf) and (r = x.sup); mpfree(x); end; global operator in ( r : real; x : mpinterval ) cont : boolean; begin mpvlcp(x); cont := (x.inf <= r) and (r <= x.sup); mpfree(x); end; {============================================================================} {========== Logical Operators: interval <--> mpinterval ===============} {========== mpinterval <--> interval ===============} {============================================================================} global operator = ( x : mpinterval; a : interval ) eq : boolean; begin mpvlcp(x); eq := (x.inf = a.inf) and (x.sup = a.sup); mpfree(x); end; global operator = ( a : interval; x : mpinterval ) eq : boolean; begin mpvlcp(x); eq := (a.inf = x.inf) and (a.sup = x.sup); mpfree(x); end; global operator in ( a : interval; x : mpinterval ) cont : boolean; begin mpvlcp(x); cont := (x.inf < _mpreal(a.inf,-1)) and (_mpreal(a.sup,+1) < x.sup); mpfree(x); end; {============================================================================} {========== Arithmetic Operators: mpinterval <--> mpinterval ============} {============================================================================} global operator + ( x : mpinterval ) mplus : mpinterval; begin mpvlcp(x); mplus := InitOp; mplus := x; mplus := TempOp; mpfree(x); end; global operator - ( x : mpinterval ) mminus : mpinterval; begin mpvlcp(x); mminus := InitOp; mminus.inf := -x.sup; mminus.sup := -x.inf; mminus := TempOp; mpfree(x); end; global operator + ( x, y : mpinterval ) add : mpinterval; begin mpvlcp(x); mpvlcp(y); add := InitOp; add.inf := x.inf +< y.inf; add.sup := x.sup +> y.sup; add := TempOp; mpfree(x); mpfree(y); end; global operator - ( x, y : mpinterval ) sub : mpinterval; begin mpvlcp(x); mpvlcp(y); sub := InitOp; sub.inf := x.inf -< y.sup; sub.sup := x.sup -> y.inf; sub := TempOp; mpfree(x); mpfree(y); end; global operator * ( x, y : mpinterval ) mul : mpinterval; {----------------------------------------------------------------------------} { For the multiplication of two intervals [z] = [x] * [y] the following } { rules are applied: } { } { x.inf x.sup y.inf y.sup | z.inf | z.sup } { ----------------------------+---------------------+-------------------- } { + + + + | x.inf * y.inf | x.sup * y.sup } { + + - + | x.sup * y.inf | x.sup * y.sup } { + + - - | x.sup * y.inf | x.inf * y.sup } { | | } { - - + + | x.inf * y.sup | x.sup * y.inf } { - - - + | x.inf * y.sup | x.inf * y.inf } { - - - - | x.sup * y.sup | x.inf * y.inf } { | | } { - + + + | x.inf * y.sup | x.sup * y.sup } { - + - - | x.sup * y.inf | x.inf * y.inf } { | | } { - + - + | min(x.inf * y.sup, | max(x.inf * y.inf, } { | x.sup * y.inf ) | x.sup * y.sup ) } {----------------------------------------------------------------------------} begin mpvlcp(x); mpvlcp(y); mul := InitOp; if (sign(x.inf) >= 0) then begin if (sign(y.inf) >= 0) then mul.inf := x.inf *< y.inf else mul.inf := x.sup *< y.inf; if (sign(y.sup) >= 0) then mul.sup := x.sup *> y.sup else mul.sup := x.inf *> y.sup; end else if (sign(x.sup) <= 0) then begin if (sign(y.sup) >= 0) then mul.inf := x.inf *< y.sup else mul.inf := x.sup *< y.sup; if (sign(y.inf) >= 0) then mul.sup := x.sup *> y.inf else mul.sup := x.inf *> y.inf; end else if (sign(y.inf) >= 0) then begin mul.inf := x.inf *< y.sup; mul.sup := x.sup *> y.sup; end else if (sign(y.sup) <= 0) then begin mul.inf := x.sup *< y.inf; mul.sup := x.inf *> y.inf; end else begin mul.inf := min( x.inf *< y.sup, x.sup *< y.inf); mul.sup := max( x.inf *> y.inf, x.sup *> y.sup); end; mul := TempOp; mpfree(x); mpfree(y); end; global operator / ( x, y : mpinterval ) frac : mpinterval; {----------------------------------------------------------------------------} { Suppose that 0 is not contained in [y]. For an interval division it holds } { [z] = [x] / [y] = [x] * [1/y.sup,1/y.inf]. Applying the rules for multi- } { plication the following rules can be derived: } { } { y.inf, y.sup x.inf x.sup | z.inf | z.sup } { ------------------------------+---------------+--------------- } { + + + | x.inf / y.sup | x.sup / y.inf } { + - + | x.inf / y.inf | x.sup / y.inf } { + - - | x.inf / y.inf | x.sup / y.sup } { | | } { - + + | x.sup / y.sup | x.inf / y.inf } { - - + | x.sup / y.sup | x.inf / y.sup } { - - - | x.sup / y.inf | x.inf / y.sup } {----------------------------------------------------------------------------} begin mpvlcp(x); mpvlcp(y); frac := InitOp; if (sign(y.inf) > 0) then begin if (sign(x.inf) >= 0) then frac.inf := x.inf /< y.sup else frac.inf := x.inf /< y.inf; if (sign(x.sup) >= 0) then frac.sup := x.sup /> y.inf else frac.sup := x.sup /> y.sup; end else if (sign(y.sup) < 0) then begin if (sign(x.sup) >= 0) then frac.inf := x.sup /< y.sup else frac.inf := x.sup /< y.inf; if (sign(x.inf) >= 0) then frac.sup := x.inf /> y.inf else frac.sup := x.inf /> y.sup; end else _math_message(div_by_zero,x,y); frac := TempOp; mpfree(x); mpfree(y); end; {============================================================================} {========== Arithmetic Operators: mpreal <--> mpinterval ============} {========== mpinterval <--> mpreal ============} {============================================================================} global operator + ( a : mpreal; x : mpinterval ) add : mpinterval; begin mpvlcp(x); mpvlcp(a); add := InitOp; add := _mpinterval(a) + x; add := TempOp; mpfree(a); mpfree(x); end; global operator + ( x : mpinterval ; a : mpreal ) add : mpinterval; begin mpvlcp(x); mpvlcp(a); add := InitOp; add := x + _mpinterval(a); add := TempOp; mpfree(a); mpfree(x); end; global operator - ( a : mpreal; x : mpinterval ) sub : mpinterval; begin mpvlcp(x); mpvlcp(a); sub := InitOp; sub := _mpinterval(a) - x; sub := TempOp; mpfree(a); mpfree(x); end; global operator - ( x : mpinterval ; a : mpreal ) sub : mpinterval; begin mpvlcp(x); mpvlcp(a); sub := InitOp; sub := x - _mpinterval(a); sub := TempOp; mpfree(a); mpfree(x); end; global operator * ( a : mpreal; x : mpinterval ) mul : mpinterval; begin mpvlcp(x); mpvlcp(a); mul := InitOp; mul := _mpinterval(a) * x; mul := TempOp; mpfree(a); mpfree(x); end; global operator * ( x : mpinterval ; a : mpreal ) mul : mpinterval; begin mpvlcp(x); mpvlcp(a); mul := InitOp; mul := x * _mpinterval(a); mul := TempOp; mpfree(a); mpfree(x); end; global operator / ( a : mpreal; x : mpinterval ) frac : mpinterval; begin mpvlcp(x); mpvlcp(a); frac := InitOp; frac := _mpinterval(a) / x; frac := TempOp; mpfree(a); mpfree(x); end; global operator / ( x : mpinterval ; a : mpreal ) frac : mpinterval; begin mpvlcp(x); mpvlcp(a); frac := InitOp; frac := x / _mpinterval(a); frac := TempOp; mpfree(a); mpfree(x); end; {============================================================================} {========== Arithmetic Operators: real <--> mpinterval ============} {========== mpinterval <--> real ============} {============================================================================} global operator + ( r : real; x : mpinterval ) add : mpinterval; begin mpvlcp(x); add := InitOp; add := _mpinterval(r) + x; add := TempOp; mpfree(x); end; global operator + ( x : mpinterval; r : real ) add : mpinterval; begin mpvlcp(x); add := InitOp; add := x + _mpinterval(r); add := TempOp; mpfree(x); end; global operator - ( r : real; x : mpinterval ) sub : mpinterval; begin mpvlcp(x); sub := InitOp; sub := _mpinterval(r) - x; sub := TempOp; mpfree(x); end; global operator - ( x : mpinterval; r : real ) sub : mpinterval; begin mpvlcp(x); sub := InitOp; sub := x - _mpinterval(r); sub := TempOp; mpfree(x); end; global operator * ( r : real; x : mpinterval ) mul : mpinterval; begin mpvlcp(x); mul := InitOp; mul := _mpinterval(r) * x; mul := TempOp; mpfree(x); end; global operator * ( x : mpinterval; r : real ) mul : mpinterval; begin mpvlcp(x); mul := InitOp; mul := x * _mpinterval(r); mul := TempOp; mpfree(x); end; global operator / ( r : real; x : mpinterval ) frac : mpinterval; begin mpvlcp(x); frac := InitOp; frac := _mpinterval(r) / x; frac := TempOp; mpfree(x); end; global operator / ( x : mpinterval; r : real ) frac : mpinterval; begin mpvlcp(x); frac := InitOp; frac := x / _mpinterval(r); frac := TempOp; mpfree(x); end; {============================================================================} {========== Arithmetic Operators: interval <--> mpinterval ============} {========== mpinterval <--> interval ============} {============================================================================} global operator + ( a : interval; x : mpinterval ) add : mpinterval; begin mpvlcp(x); add := InitOp; add := _mpinterval(a) + x; add := TempOp; mpfree(x); end; global operator + ( x : mpinterval ; a : interval ) add : mpinterval; begin mpvlcp(x); add := InitOp; add := x + _mpinterval(a); add := TempOp; mpfree(x); end; global operator - ( a : interval; x : mpinterval ) sub : mpinterval; begin mpvlcp(x); sub := InitOp; sub := _mpinterval(a) - x; sub := TempOp; mpfree(x); end; global operator - ( x : mpinterval ; a : interval ) sub : mpinterval; begin mpvlcp(x); sub := InitOp; sub := x - _mpinterval(a); sub := TempOp; mpfree(x); end; global operator * ( a : interval; x : mpinterval ) mul : mpinterval; begin mpvlcp(x); mul := InitOp; mul := _mpinterval(a) * x; mul := TempOp; mpfree(x); end; global operator * ( x : mpinterval ; a : interval ) mul : mpinterval; begin mpvlcp(x); mul := InitOp; mul := x * _mpinterval(a); mul := TempOp; mpfree(x); end; global operator / ( a : interval; x : mpinterval ) frac : mpinterval; begin mpvlcp(x); frac := InitOp; frac := _mpinterval(a) / x; frac := TempOp; mpfree(x); end; global operator / ( x : mpinterval ; a : interval ) frac : mpinterval; begin mpvlcp(x); frac := InitOp; frac := x / _mpinterval(a); frac := TempOp; mpfree(x); end; {============================================================================} {========== Lattice Operators ===========================================} {============================================================================} global operator +* ( x, y : mpinterval ) hull : mpinterval; { Convex hull } begin {-------------} mpvlcp(x); mpvlcp(y); hull := InitFunc; if (x.inf <= y.inf) then hull.inf := x.inf else hull.inf := y.inf; if (x.sup >= y.sup) then hull.sup := x.sup else hull.sup := y.sup; hull := TempFunc; mpfree(x); mpfree(y); end; global operator ** ( x, y : mpinterval ) intsec : mpinterval; { Intersection } begin {--------------} mpvlcp(x); mpvlcp(y); intsec := InitFunc; if (x.inf >= y.inf) then intsec.inf:= x.inf else intsec.inf:= y.inf; if (x.sup <= y.sup) then intsec.sup:= x.sup else intsec.sup:= y.sup; intsec := TempFunc; mpfree(x); mpfree(y); end; {============================================================================} {========== Access and Transfer Functions ===============================} {============================================================================} global function inf( x : mpinterval ) : mpreal; begin mpvlcp(x); inf := InitFunc; inf := x.inf; inf := TempFunc; mpfree(x); end; global function sup( x : mpinterval ) : mpreal; begin mpvlcp(x); sup := InitFunc; sup := x.sup; sup := TempFunc; mpfree(x); end; global function intval( lb, ub : mpreal) : mpinterval; begin mpvlcp(lb); mpvlcp(ub); intval := InitFunc; intval.inf := lb; intval.sup := ub; intval := TempFunc; mpfree(lb); mpfree(ub); end; {============================================================================} {========== Utilities ===================================================} {============================================================================} global procedure iround( value: mpreal; var lb, ub : mpreal ); external b_irnd; { Creates a lower and an upper bound of type 'mpreal' } { according to the number of ulps indicated by the } { representation of the mpreal value. } function is_integer( x : mpinterval ) : boolean; { Check for an integer } begin { point interval } mpvlcp(x); {----------------------} is_integer := point(x) and (x.inf = trunc_mp(x.inf)); mpfree(x); end; { Function increasing() is used to compute an enclosure of a monotonically } { increasing function f on the interval [x]. For [z] := f([x]) it holds } { z.inf := inf( f(x.inf) ) and z.sup := sup( f(x.sup) ). } {----------------------------------------------------------------------------} function increasing( var x : mpinterval; function f(y : mpreal) : mpreal ) : mpinterval; var lb, ub : mpreal; begin mpinit(lb); mpinit(ub); increasing := InitFunc; iround(f(x.inf),lb,ub); increasing.inf := lb; if point(x) then increasing.sup := ub else begin iround(f(x.sup),lb,ub); increasing.sup := ub; end; increasing := TempFunc; mpfree(lb); mpfree(ub); end; { Function decreasing() is used to compute an enclosure of a monotonically } { decreasing function f on the interval [x]. For [z] := f([x]) it holds } { z.inf := inf( f(x.sup) ) and z.sup := sup( f(x.inf) ). } {----------------------------------------------------------------------------} function decreasing( var x : mpinterval; function f(y : mpreal) : mpreal ) : mpinterval; var lb, ub : mpreal; begin mpinit(lb); mpinit(ub); decreasing := InitFunc; iround(f(x.sup),lb,ub); decreasing.inf := lb; if point(x) then decreasing.sup := ub else begin iround(f(x.inf),lb,ub); decreasing.sup := ub; end; decreasing := TempFunc; mpfree(lb); mpfree(ub); end; {============================================================================} {========== Standard Functions ==========================================} {============================================================================} {----------------------------------------------------------------------------} { Local functions for computing an interval enclosure for point arguments } {----------------------------------------------------------------------------} function pt_loga( x, a : mpreal ) : mpinterval; { Logarithm, base a for } var { point arguments } lb, ub : mpreal; {-----------------------} x1, x2, z1, z2 : mpreal; exact : boolean; j : integer; begin mpvlcp(x); mpvlcp(a); mpinit(lb); mpinit(ub); mpinit(x1); mpinit(x2); mpinit(z1); mpinit(z2); pt_loga := InitFunc; { Check if x = a^j with an integer j } {------------------------------------} if (x = 1) then begin j := 0; exact := true; end else if (a < 1) then if (x < 1) then if (a < x) then exact := false else begin z1 := a; z2 := a; j := 1; while (z1 > x) and (z1 = z2) do begin z2 := z2 *> a; z1 := z1 *< a; j := succ(j); end; exact := (z1 = z2) and (z1 = x); end else { a < 1 and x > 1 } begin x1 := 1 /< x; x2 := 1 /> x; z1 := a; z2 := a; j := -1; if (x1 = x2) then begin while (z1 > x1) and (z1 = z2) do begin z1 := z1 *< a; z2 := z2 *> a; j := pred(j); end; exact := (z1 = z2) and (z1 = x1); end else exact := false; end else { a > 1 } if (x < 1) then begin z1 := 1 /< a; z2 := 1 /> a; j := -1; while (z1 > x) and (z1 = z2) do begin z1 := z1 /< a; z2 := z2 /> a; j := pred(j); end; exact := (z1 = z2) and (z1 = x); end else if (a > x) then exact := false else begin { a < x and a, x > 1 } x1 := x; x2 := x; j := 1; while (a < x1) and (x1 = x2) do begin x1 := x1 /< a; x2 := x2 /> a; j := succ(j); end; exact := (x1 = x2) and (x1 = a); end; if exact then { x = a^j } begin pt_loga.inf := j; pt_loga.sup := j; end else begin iround(loga(x,a),lb,ub); pt_loga.inf := lb; pt_loga.sup := ub; end; pt_loga := TempFunc; mpfree(x); mpfree(a); mpfree(lb); mpfree(ub); mpfree(x1); mpfree(x2); mpfree(z1); mpfree(z2); end; {pt_loga} function pt_power( x, y : mpreal) : mpinterval; { x^y for point arguments } var {-------------------------} lb, ub : mpreal; begin mpvlcp(x); mpvlcp(y); mpinit(lb); mpinit(ub); iround(power(x,y),lb,ub); pt_power := InitFunc; pt_power.inf := lb; pt_power.sup := ub; pt_power:= TempFunc; mpfree(x); mpfree(y); mpfree(lb); mpfree(ub); end; {----------------------------------------------------------------------------} { Arg(x,y) computes an enclosure for the angle of the point p = (x,y) to the } { x-axis. For the origin p = (0,0) the interval [-Pi,+Pi] is returned. } {----------------------------------------------------------------------------} global function arctan( x : mpinterval ) : mpinterval; forward; function pt_arg( x, y : mpreal ) : mpinterval; { argument function for } var { point parameters } long_pi : mpinterval; {-----------------------} begin mpvlcp(x); mpvlcp(y); mpinit(long_pi); pt_arg := InitFunc; if (x = 0) and (y = 0) then { Return [-Pi,+Pi] for the origin p = (0,0) } begin long_pi := 4*arctan(ione); pt_arg.inf:= -long_pi.sup; pt_arg.sup:= long_pi.sup; end else if (x > 0) then { p lies in the right halve plane ... } if (y = 0) then { ... and is part of the pos. real axis } pt_arg := 0 else { .. and lies in quadrant I or IV } pt_arg := arctan(_mpinterval(y) / _mpinterval(x)) else if (x = 0) then { p lies not in the right halve plane ... } if (y > 0) then { ... and lies on the positive imag. axis } pt_arg := 2*long_pi else { ... and lies on the negative imag. axis } pt_arg := -2*long_pi else {x < 0} { p in the left halve plane ... } if (y = 0) then pt_arg := long_pi else if (y >= 0) then { ... and lies in quadrant II } pt_arg := arctan(_mpinterval(y) / _mpinterval(x)) + long_pi else { ... and lies in quadrant III } pt_arg := arctan(_mpinterval(y) / _mpinterval(x)) - long_pi; pt_arg := TempFunc; mpfree(x); mpfree(y); mpfree(long_pi); end; {pt_arg} {----------------------------------------------------------------------------} { Special version of the above arg(.,.) function for a point p = (x,y) in } { quadrant III. In contrast to the above implementation the angle is not } { normalized between -Pi and +Pi. The function returns an enclosure of an } { angle > Pi. } {----------------------------------------------------------------------------} function special_arg( x, y : mpreal ) : mpinterval; var long_pi : mpinterval; begin mpvlcp(x); mpvlcp(y); mpinit(long_pi); special_arg:= InitFunc; if (x = 0) then special_arg := 1.5 * long_pi { p lies on the negative imaginary axis } else special_arg := arctan(_mpinterval(y) / _mpinterval(x)) + long_pi; special_arg := TempFunc; mpfree(x); mpfree(y); mpfree(long_pi); end; {special_arg} {-------------------} { String conversion } {-------------------} global function mpival( s : string ) : mpinterval; begin mpival := InitFunc; mpival.inf := mpval(s,-1); mpival.sup := mpval(s,+1); mpival := TempFunc; end; {----------------------------------------} { Midpoint, diameter, and blow functions } {----------------------------------------} global function mid( x : mpinterval ) : mpreal; { Interval midpoint } begin {-------------------} mpvlcp(x); mid := InitFunc; mid := x.inf + 0.5*(x.sup-x.inf); mid := TempFunc; mpfree(x); end; {mid} global function diam ( x : mpinterval ) : real; { Real interval diameter } begin {------------------------} mpvlcp(x); diam := x.sup -> x.inf; mpfree(x); end; {diam} global function blow( x : mpinterval ) : mpinterval; { Blow 2 ULPs } begin {-------------} mpvlcp(x); blow := InitFunc; blow.inf := pred(pred(x.inf)); blow.sup := succ(succ(x.sup)); blow := TempFunc; mpfree(x); end; {blow} {----------------------------------------} { Absolute value, square and square root } {----------------------------------------} global function abs( x : mpinterval ) : mpinterval; { Absolute value } begin {----------------} mpvlcp(x); abs := InitFunc; if (sign(x.inf) >= 0) then abs := x { Interval positiv } else if (sign(x.sup) <= 0) then abs := -x { Interval negativ } else begin { 0 in interval } abs.inf := 0; if (-x.inf > x.sup) then abs.sup := -x.inf else abs.sup := x.sup; end; abs := TempFunc; mpfree(x); end; {abs} global function sqr( x : mpinterval ) : mpinterval; { Square function } begin {-----------------} mpvlcp(x); sqr := InitFunc; if (sign(x.inf) >= 0) then begin { Interval positiv } sqr.inf := x.inf *< x.inf; sqr.sup := x.sup *> x.sup; end else if (sign(x.sup) <= 0) then begin { Interval negativ } sqr.inf := x.sup *< x.sup; sqr.sup := x.inf *> x.inf; end else begin { 0 in interval } sqr.inf := 0; if (-x.inf > x.sup) then sqr.sup := x.inf *> x.inf else sqr.sup := x.sup *> x.sup; end; sqr := TempFunc; mpfree(x); end; {sqr} global function sqrt( x : mpinterval ) : mpinterval; { Square root } begin {-------------} mpvlcp(x); if (x.inf < 0) then _math_message(sqrt_range,x,x); sqrt := InitFunc; sqrt := increasing(x,sqrt); sqrt := TempFunc; mpfree(x); end; {sqrt} {-----------------------} { Logarithmic functions } {-----------------------} global function ln( x : mpinterval ) : mpinterval; { Natural logarithm } begin {-------------------} mpvlcp(x); if (x.inf <= 0) then _math_message(ln_range,x,x); ln := InitFunc; ln := increasing(x,ln); ln := TempFunc; mpfree(x); end; {ln} global function log2( x : mpinterval ) : mpinterval; { Logarithm, base 2 } begin {-------------------} mpvlcp(x); if (x.inf <= 0) then _math_message(log2_range,x,x); log2 := InitFunc; log2 := increasing(x,log2); log2 := TempFunc; mpfree(x); end; {log2} global function log10( x : mpinterval ): mpinterval; { Logarithm, base 10 } begin {--------------------} mpvlcp(x); if (x.inf <= 0) then _math_message(log10_range,x,x); log10 := InitFunc; log10 := increasing(x,log10); log10 := TempFunc; mpfree(x); end; {log10} global function loga( x, a : mpinterval ) : mpinterval; { Logarithm, base a } begin {-------------------} mpvlcp(x); mpvlcp(a); loga := InitFunc; if (x.inf <= 0) or (a.inf <= 0) or (1 in a) then _math_message(loga_range,x,x) else if point(x) and point(a) then loga := pt_loga(x.inf,a.inf) else if (a.sup < 1) then if (x.sup <= 1) then begin loga.inf := inf( pt_loga(x.inf,a.sup) ); loga.sup := sup( pt_loga(x.sup,a.inf) ); end else if (x.inf >= 1) then begin loga.inf := inf( pt_loga(x.sup,a.sup) ); loga.sup := sup( pt_loga(x.inf,a.inf) ); end else begin loga.inf := inf( pt_loga(x.sup,a.sup) ); loga.sup := sup( pt_loga(x.sup,a.inf) ); end else if (x.sup <= 1) then begin loga.inf := inf( pt_loga(x.inf,a.inf) ); loga.sup := sup( pt_loga(x.sup,a.sup) ); end else if (x.inf >= 1) then begin loga.inf := inf( pt_loga(x.sup,a.inf) ); loga.sup := sup( pt_loga(x.inf,a.sup) ); end else begin loga.inf := inf( pt_loga(x.inf,a.inf) ); loga.sup := sup( pt_loga(x.inf,a.sup) ); end; loga := TempFunc; mpfree(x); mpfree(a); end; {loga} {-----------------------} { Exponential functions } {-----------------------} global function exp( x : mpinterval ) : mpinterval; { Exponential function } begin {----------------------} mpvlcp(x); exp := InitFunc; exp := increasing(x,exp); exp := TempFunc; mpfree(x); end; {exp} global function exp2( x : mpinterval ) : mpinterval; { Power fct., base 2 } begin {--------------------} mpvlcp(x); exp2 := InitFunc; exp2 := increasing(x,exp2); exp2 := TempFunc; mpfree(x); end; {exp2} global function exp10( x : mpinterval ) : mpinterval; { Power fct., base 10 } begin {---------------------} mpvlcp(x); exp10 := InitFunc; exp10 := increasing(x,exp10); exp10 := TempFunc; mpfree(x); end; {exp10} {----------------------------------------------------------------------------} { For computing the power function [z] = [x]^[y] for interval arguments [x] } { and [y] the following cases are to be distinguished: } { } { 1. [y] = 0: } { 0 in [x] ==> Error: contains 0^0, not defined! } { else ==> [z] := 1 } { } { 2. x.inf < 0: } { y is an integer point interval: } { y <= -1: } { x.sup >= 0: ==> Error: contains 0^0, not defined! } { x.sup < 0: } { y is odd: ==> [z] := [ x.sup^y , x.inf^y ] } { y is even: ==> [z] := [ x.inf^y , x.sup^y ] } { y >= +1: } { y is odd: ==> [z] := [ x.inf^y , x.sup^y ] } { y is even: } { x.sup < 0: ==> [z] := [ x.sup^y , x.inf^y ] } { x.sup >= 0: ==> [z] := [ 0, max(|x.inf|,x.sup)^y ] } { y is not an integer point interval: } { ==> Error: Illegal range! } { } { 3. x.inf = 0: } { y.inf <= 0: ==> Error: contains 0^0, not defined! } { y.inf > 0: } { x.sup <= 1: ==> [z] := [ 0, x.sup^y.inf ] } { x.sup > 1: ==> [z] := [ 0, x.sup^y.sup ] } { } { 4. x.inf > 0: } { x.sup <= 1: } { y.sup <= 0: ==> [z] := [ x.sup^y.sup , x.inf^y.inf ] } { y.inf >= 0: ==> [z] := [ x.inf^y.sup , x.sup^y.inf ] } { y.inf < 0 < y.sup: ==> [z] := [ x.inf^y.sup , x.inf^y.inf ] } { x.inf >= 1: } { y.sup <= 0: ==> [z] := [ x.sup^y.inf , x.inf^y.sup ] } { y.inf >= 0: ==> [z] := [ x.inf^y.inf , x.sup^y.sup ] } { y.inf < 0 < y.sup: ==> [z] := [ x.sup^y.inf , x.sup^y.sup ] } { x.inf < 0 < x.sup: } { y.sup <= 0: ==> [z] := [ x.sup^y.inf , x.inf^y.inf ] } { y.inf >= 0: ==> [z] := [ x.inf^y.sup , x.sup^y.sup ] } { y.inf < 0 < y.sup: ==> [z] := [ min(x.inf^y.sup,x.sup^y.inf), } { max(x.inf^y.inf,x.sup^y.sup) ] } { } {----------------------------------------------------------------------------} global function power( x, y : mpinterval ) : mpinterval; begin mpvlcp(x); mpvlcp(y); power := InitFunc; if point(y) and (y.inf = 0) then { Zero exponent inteval } if (0 in x) then {-----------------------} _math_message(power_notdef,x,y) { 0^0 not defined! } else power := 1 { [x]^0 := 1 } else if (x.inf < 0) then { [x] contains negative values } {------------------------------} if is_integer(y) then { y = [y] is an integer point } { interval with y <> 0 ... } if (y.inf <= -1) then { ... and y is negative } if (x.sup >= 0) then _math_message(power_range,x,y) else {x.sup < 0} if odd_mp(y.inf) then { y is an odd integer } begin power.inf := inf(pt_power(x.sup,y.inf)); power.sup := sup(pt_power(x.inf,y.inf)); end else { y is an even integer } begin power.inf := inf(pt_power(x.inf,y.inf)); power.sup := sup(pt_power(x.sup,y.sup)); end else { y >= 1 } { ... and y is positive } if odd_mp(y.inf) then { y is an odd integer } begin power.inf := inf(pt_power(x.inf,y.inf)); power.sup := sup(pt_power(x.sup,y.inf)); end else { y is an even integer } if (x.sup < 0) then begin power.inf := inf(pt_power(x.sup,y.inf)); power.sup := sup(pt_power(x.inf,y.inf)); end else {x.sup >= 0} begin power.inf := 0; x.inf := -x.inf; { x.inf := |x.inf| } if (x.inf > x.sup) then power.sup := sup(pt_power(x.inf,y.inf)) else power.sup := sup(pt_power(x.sup,y.inf)) end else { [x] contains neg. values and y is } _math_message(power_range,x,y) { not an integer point interval } else if (x.inf = 0) then { Lower bound of [x] is zero ... } {--------------------------------} if (y.inf <= 0) then _math_message(power_notdef,x,y) { 0^0 not defined! } else {y.inf > 0} if (x.sup <= 1) then { ... and [x] lies in [0,1] } begin power.inf := 0; power.sup := sup(pt_power(x.sup,y.inf)); end else {1 < x.sup} { ... and 1 in the interior of [x] } begin power.inf := 0; power.sup := sup(pt_power(x.sup,y.sup)); end else {0 < x.inf} { [x] is positive ... } {---------------------} if (x.sup <= 1) then { ... and [x] lies in (0,1] } if (y.sup <= 0) then { negative exponents } begin power.inf := inf(pt_power(x.sup,y.sup)); power.sup := sup(pt_power(x.inf,y.inf)); end else if (0 <= y.inf) then { positive exponents } begin power.inf := inf(pt_power(x.inf,y.sup)); power.sup := sup(pt_power(x.sup,y.inf)); end else {y.inf < 0 < y.sup} { pos. and neg. exponents } begin power.inf := inf(pt_power(x.inf,y.sup)); power.sup := sup(pt_power(x.inf,y.inf)); end else if (1 <= x.inf) then { ... and [x] lies right of 1 } if (y.sup <= 0) then { negative exponents } begin power.inf := inf(pt_power(x.sup,y.inf)); power.sup := sup(pt_power(x.inf,y.sup)); end else if (0 <= y.inf) then { positive exponents } begin power.inf := inf(pt_power(x.inf,y.inf)); power.sup := sup(pt_power(x.sup,y.sup)); end else {y.inf < 0 < y.sup} { pos. and neg. exponents } begin power.inf := inf(pt_power(x.sup,y.inf)); power.sup := sup(pt_power(x.sup,y.sup)); end else {x.inf < 1 < x.sup} { ... and 1 in the interior of [x] } if (y.sup <= 0) then { negative exponents } begin power.inf := inf(pt_power(x.sup,y.inf)); power.sup := sup(pt_power(x.inf,y.inf)); end else if (0 <= y.inf) then { positive exponents } begin power.inf := inf(pt_power(x.inf,y.sup)); power.sup := sup(pt_power(x.sup,y.sup)); end else {y.inf < 0 < y.sup} { pos. and neg. exponents } begin power.inf := min( inf(pt_power(x.inf,y.sup)), inf(pt_power(x.sup,y.inf)) ); power.sup := max( sup(pt_power(x.inf,y.inf)), inf(pt_power(x.sup,y.sup)) ); end; power := TempFunc; mpfree(x); mpfree(y); end; {power} {----------------------------------------------------------------------------} { Arg(x,y) computes an enclosure for the angle of every point (x0,y0) with } { x0 in x and y0 in y. The set p = ((x0,y0) : x0 in x, y0 in y) corresponds } { to a rectangle in the complex plane. } {----------------------------------------------------------------------------} global function arg( x, y : mpinterval ) : mpinterval; var long_pi : mpinterval; begin mpvlcp(x); mpvlcp(y); mpinit(long_pi); arg := InitFunc; if (point(x) and point(y)) then { p is a point } arg := pt_arg(x.inf,y.inf ) else if (y = 0) then { p lies on the real axis ... } if (x.inf > 0) then arg:= 0 { ... and is positive } else if (x.sup < 0) then arg:= 4*arctan(ione) { ... and is negative } else begin long_pi := 4*arctan(ione); { ... and contains 0 } arg.inf := -long_pi.sup; arg.sup := long_pi.sup; end else if (x = 0) then { p lies on the imaginary axis ... } if (y.inf > 0) then arg:= 2*arctan(ione) { ... and is positive } else if (y.sup < 0) then arg:= -2*arctan(ione) { ... and is negative } else begin long_pi := 4*arctan(ione); { ... and contains 0 } arg.inf := -long_pi.sup; arg.sup := long_pi.sup; end { p is a rectangle in the plane ... } {-----------------------------------} else if (x.inf >= 0) then { consider right halve plane ... } if (y.inf >= 0) then begin { ... with p in quadrant I } arg.inf := inf( pt_arg(x.sup,y.inf) ); arg.sup := sup( pt_arg(x.inf,y.sup) ); end else if (y.sup <= 0) then begin { ... with p in quadrant IV } arg.inf := inf( pt_arg(x.inf,y.inf) ); arg.sup := sup( pt_arg(x.sup,y.sup) ); end else begin { ... with p in quadrants I and IV } arg.inf := inf( pt_arg(x.inf,y.inf) ); arg.sup := sup( pt_arg(x.inf,y.sup) ); end else if (x.sup <= 0) then { consider left halve plane ... } if (y.inf >= 0) then begin { ... with p in quadrant II } arg.inf := inf( pt_arg(x.sup,y.sup) ); arg.sup := sup( pt_arg(x.inf,y.inf) ); end else if (y.sup <= 0) then begin { ... with p in quadrant III } arg.inf := inf( pt_arg(x.inf,y.sup) ); arg.sup := sup( pt_arg(x.sup,y.inf) ); end else begin { ... and p in quadrants II and III } arg.inf := inf( pt_arg(x.sup,y.sup) ); arg.sup := sup( special_arg(x.sup,y.inf) ); end else {x.inf < 0 < x.sup } { consider both halve planes ... } if (y.inf >= 0) then begin { ... with p in quadrants I and II } arg.inf := inf( pt_arg(x.sup,y.inf) ); arg.sup := sup( pt_arg(x.inf,y.inf) ); end else if (y.sup <= 0) then begin { ... with p in quadrants III and IV } arg.inf := inf( pt_arg(x.inf,y.sup) ); arg.sup := sup( pt_arg(x.sup,y.sup) ); end else begin { ... with p in all quadrants } long_pi := 4*arctan(ione); arg.inf := -long_pi.sup; arg.sup := long_pi.sup; end; arg := TempFunc; mpfree(x); mpfree(y); mpfree(long_pi); end; {arg} {---------------------------------} { Inverse trigonometric functions } {---------------------------------} global function arcsin( x : mpinterval ) : mpinterval; { Arc sine } begin {----------} mpvlcp(x); if (x.inf < -1) or (x.sup > 1) then _math_message(arcsin_range,x,x); arcsin := InitFunc; arcsin := increasing(x,arcsin); arcsin := TempFunc; mpfree(x); end; {arcsin} global function arccos( x : mpinterval ) : mpinterval; { arc cosine } begin {------------} mpvlcp(x); if (x.inf < -1) or (x.sup > 1) then _math_message(arccos_range,x,x); arccos := InitFunc; arccos := decreasing(x,arccos); arccos := TempFunc; mpfree(x); end; {arccos} global function arctan( x : mpinterval ) : mpinterval; { Arc tangent } begin {-------------} mpvlcp(x); arctan := InitFunc; arctan := increasing(x,arctan); arctan := TempFunc; mpfree(x); end; {arctan} global function arccot( x : mpinterval ) : mpinterval; { arc cotangent } begin {---------------} mpvlcp(x); arccot := InitFunc; arccot := decreasing(x,arccot); arccot := TempFunc; mpfree(x); end; {arccot} global function arctan2( x, y : mpinterval ) : mpinterval; { arctan(x/y) } begin {-------------} mpvlcp(x); mpvlcp(y); arctan2 := InitFunc; arctan2 := arg(y,x); arctan2 := TempFunc; mpfree(x); mpfree(y); end; {artan2} {-------------------------} { Trigonometric functions } {-------------------------} global function cos( x : mpinterval ) : mpinterval; { Cosine } var {--------} even_pi, odd_pi : boolean; oldprec : integer; long_pi, lb, ub, lb1, ub1, k1, k2 : mpreal; begin mpvlcp(x); mpinit(long_pi); mpinit(lb); mpinit(ub); mpinit(lb1); mpinit(ub1); mpinit(k1); mpinit(k2); cos := InitFunc; if point(x) then iround(cos(x.inf),lb,ub) else begin oldprec := getprec; setprec(oldprec+2); long_pi := 4*arctan(one); if (diam(x) >= 2*long_pi) then begin lb := -1; ub := +1; end else begin { Check first if x contains an even and/or odd multiple of Pi } {-------------------------------------------------------------} k1 := trunc_mp(x.inf /< long_pi); k2 := trunc_mp(x.sup /> long_pi); if (0 in x) then begin even_pi := true; if (k1 <= -1) then odd_pi := true else if ((k1 = 0) and (k2 = 0)) then odd_pi := false else odd_pi := true; end else {0 not in x} begin if (x.sup < 0) then begin lb := k1; { swap sign and values } k1 := -k2; { of k1 and k2 } k2 := -lb; end; if odd_mp(k1) then { k1 is odd } if (k2 = k1) then {-----------} begin even_pi := false; odd_pi := false; end else if (k2-1 = k1) then begin even_pi := true; odd_pi := false; end else begin even_pi := true; odd_pi := true; end else { k1 is even } if (k2 = k1) then {------------} begin even_pi := false; odd_pi := false; end else if (k2-1 = k1) then begin even_pi := false; odd_pi := true; end else begin even_pi := true; odd_pi := true; end; end; { 0 not in x} { Now we known if x contains an even and/or add multiple of Pi } {--------------------------------------------------------------} if (even_pi and odd_pi) then begin lb := -1; ub := +1; end else begin iround(cos(x.inf),lb,ub); iround(cos(x.sup),lb1,ub1); if (even_pi and not odd_pi) then begin if (lb > lb1) then lb := lb1; ub := 1; end else if (not even_pi and odd_pi) then begin if (ub < ub1) then ub := ub1; lb := -1; end else begin if (lb > lb1) then lb := lb1; if (ub < ub1) then ub := ub1; end; end; end; setprec(oldprec); end; cos.inf := lb; cos.sup := ub; cos := TempFunc; mpfree(x); mpfree(long_pi); mpfree(lb); mpfree(ub); mpfree(lb1); mpfree(ub1); mpfree(k1); mpfree(k2); end; global function sin( x : mpinterval ) : mpinterval; { Sine } var {------} lb, ub : mpreal; half_pi : mpinterval; begin mpvlcp(x); mpinit(lb); mpinit(ub); mpinit(half_pi); sin := InitFunc; if point(x) then begin iround(sin(x.inf),lb,ub); sin.inf := lb; sin.sup := ub; end else begin half_pi := 2*arctan(ione); sin := cos(x - half_pi); end; sin := TempFunc; mpfree(x); mpfree(lb); mpfree(ub); mpfree(half_pi); end; global function tan( x : mpinterval ) : mpinterval; { Tangent } var {---------} k1, k2, oldprec : integer; lb, ub, half_pi, dummy : mpreal; begin mpvlcp(x); mpinit(lb); mpinit(ub); mpinit(half_pi); mpinit(dummy); tan := InitFunc; if point(x) then iround(tan(x.inf),lb,ub) else begin oldprec := getprec; setprec(oldprec+2); half_pi := 2*arctan(one); if ( (diam(x) >= 2 * half_pi) or (x.sup > maxint*half_pi) or (x.inf < -maxint*half_pi) ) then _math_message(tan_range,x,x); k1 := trunc(x.inf /< half_pi); k2 := trunc(x.sup /> half_pi); if (x.inf < 0) then k1 := k1 - 1; if (x.sup < 0) then k2 := k2 - 1; if (not odd(k1)) and (k1 <> k2) then _math_message(tan_range,x,x); iround(tan(x.inf),lb,dummy); iround(tan(x.sup),dummy,ub); setprec(oldprec); end; tan.inf:= lb; tan.sup:= ub; tan := TempFunc; mpfree(x); mpfree(lb); mpfree(ub); mpfree(half_pi); mpfree(dummy); end; global function cot( x : mpinterval ) : mpinterval; { Cotangent } var {-----------} k1, k2, oldprec : integer; lb, ub, long_pi, dummy : mpreal; begin mpvlcp(x); mpinit(lb); mpinit(ub); mpinit(long_pi); mpinit(dummy); cot := InitFunc; if point(x) then iround(cot(x.inf), lb, ub) else begin oldprec := getprec; setprec(oldprec+2); long_pi := 4*arctan(one); if ( (diam(x) >= long_pi) or (x.sup > maxint*long_pi) or (x.inf < -maxint*long_pi) ) then _math_message(cot_range,x,x); k1 := trunc(x.inf /< long_pi); k2 := trunc(x.sup /> long_pi); if (x.inf < 0) then k1 := k1 - 1; if (x.sup < 0) then k2 := k2 - 1; if (k1 <> k2) then _math_message(cot_range,x,x); iround(cot(x.inf),dummy,ub); iround(cot(x.sup),lb,dummy); setprec(oldprec); end; cot.inf:= lb; cot.sup:= ub; cot := TempFunc; mpfree(x); mpfree(lb); mpfree(ub); mpfree(long_pi); mpfree(dummy); end; {----------------------} { Hyperbolic functions } {----------------------} global function sinh( x : mpinterval ) : mpinterval; { Hyperbolic sine } begin {-----------------} mpvlcp(x); sinh := InitFunc; sinh := increasing(x,sinh); sinh := TempFunc; mpfree(x); end; {sinh} global function cosh( x : mpinterval ) : mpinterval; { Hyperbolic cosine } var {-------------------} lb, ub : mpreal; begin mpvlcp(x); mpinit(lb); mpinit(ub); cosh := InitFunc; if point(x) then begin iround(cosh(x.inf),lb,ub); cosh.inf := lb; cosh.sup := ub; end else if (x.inf >= 0) then begin iround(cosh(x.inf),lb,ub); cosh.inf := lb; iround(cosh(x.sup),lb,ub); cosh.sup := ub; end else if (x.sup <= 0) then begin iround(cosh(x.sup),lb,ub); cosh.inf := lb; iround(cosh(x.inf),lb,ub); cosh.sup := ub; end else {x.inf < 0 < x.sup} begin cosh.inf := 1; if (-x.inf > x.sup) then iround(cosh(x.inf),lb,ub) else iround(cosh(x.sup),lb,ub); cosh.sup := ub; end; cosh := TempFunc; mpfree(x); mpfree(lb); mpfree(ub); end; {cosh} global function tanh( x : mpinterval ) : mpinterval; { Hyperbolic tangent } begin {--------------------} mpvlcp(x); tanh := InitFunc; tanh := increasing(x,tanh); tanh := TempFunc; mpfree(x); end; {tanh} global function coth( x: mpinterval ) : mpinterval; { Hyperbolic cotangent } var {----------------------} lb, ub : mpreal; begin mpvlcp(x); mpinit(lb); mpinit(ub); coth := InitFunc; if point(x) and (x.inf <> 0) then begin iround(coth(x.inf),lb,ub); coth.inf := lb; coth.sup := ub; end else if (x.sup < 0) then begin iround(coth(x.sup),lb,ub); coth.inf := lb; iround(coth(x.inf),lb,ub); coth.sup := ub; end else if (x.inf > 0) then begin iround(coth(x.sup),lb,ub); coth.inf := lb; iround(coth(x.inf),lb,ub); coth.sup := ub; end else {0 in x} _math_message(coth_range,x,x); coth := TempFunc; mpfree(x); mpfree(lb); mpfree(ub); end; {coth} {------------------------------} { Inverse hyperbolic functions } {------------------------------} global function arsinh( x : mpinterval ) : mpinterval; { Inv. hyp. sine } begin {----------------} mpvlcp(x); arsinh := InitFunc; arsinh := increasing(x,arsinh); arsinh := TempFunc; mpvlcp(x); end; {arsinh} global function arcosh( x : mpinterval ) : mpinterval; { Inv. hyp. cosine } var {------------------} lb, ub : mpreal; begin mpvlcp(x); mpinit(lb); mpinit(ub); if (x.inf < 1) then _math_message(arcosh_range,x,x); arcosh := InitFunc; arcosh := increasing(x,arcosh); arcosh := TempFunc; mpvlcp(x); end; {arcosh} global function artanh( x : mpinterval ) : mpinterval; { Inv. hyp. tangent } begin {-------------------} mpvlcp(x); if (x.inf <= -1) or (x.sup >= 1) then _math_message(artanh_range,x,x); artanh := InitFunc; artanh := increasing(x,artanh); artanh := TempFunc; mpvlcp(x); end; {artanh} global function arcoth( x : mpinterval ) : mpinterval; { Inv. hyp. cotangent } begin {---------------------} mpvlcp(x); if not ((x.sup < -1) or (x.inf > 1)) then _math_message(arcoth_range,x,x); arcoth := InitFunc; arcoth := decreasing(x,arcoth); arcoth := TempFunc; mpvlcp(x); end; {arcoth} {============================================================================} {========== Module Initalization Part ===================================} {============================================================================} begin mpinit(one); mpinit(ione); one := 1; ione := 1; end. {============== Last line of module mpi_ari: 2052 =========================}