home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Current Shareware 1994 January
/
SHAR194.ISO
/
engineer
/
ksprob21.zip
/
KSMISC.EXE
/
KSUTILS.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-05-19
|
10KB
|
378 lines
unit ksutils;
{these are procedures and functions used by the small programs in
the ksmisc archive. }
{copyright (C) 1993 Joseph C. Hudson 4903 Algonquin Blvd.
Clarkston MI 48348}
{$B-,D+,E+,F+,L+,N+,R-,V-}
interface
uses dos;
type
real = double;
const
ksFuzz : real = 1.0E-13; {used in comparing reals}
var
rstack : array [0..123] of longint;
s2pi : real;
rptr1 : byte;
ksmissing : real;
function iseq(x,y : real) : boolean;
function isne(x,y : real) : boolean; {is x <> y?}
function isge(x,y : real) : boolean; {is x >= y?}
function isgt(x,y : real) : boolean; {is x > y?}
function isle(x,y : real) : boolean; {is x <= y?}
function islt(x,y : real) : boolean; {is x < y?}
function isfile(filn : pathstr) : boolean;
procedure initrand1;
function randnum1 : real;
function pexp(x : real) : real;
function zinv(cdf : real; sigD : byte) : real;
function lngamma(x : real) : real; {yields about 13 sig digits}
function poispdf(x : integer; mu : real) : real;
function poiscdf(x : integer; mu : real) : real;
function poisinv(cdf, mu : real; var cdflo, cdfhi : real) : integer;
implementation
var
a : array[0..7] of byte;
b : array[0..5] of real;
i : byte;
function iseq(x,y : real) : boolean;
var
max : real;
begin
if (x = ksmissing) and (y = ksmissing) then begin iseq := true; exit end;
if ((x = ksmissing) and (y <> ksmissing)) or
((x <> ksmissing) and (y = ksmissing)) then begin iseq := false; exit end;
if abs(x) < abs(y) then max := abs(y) else max := abs(x);
if abs(x - y) <= ksFuzz * max then iseq := true else iseq := false
end; {iseq}
function isne(x,y : real) : boolean; {is x <> y?}
begin
isne := not iseq(x,y)
end; {iseq}
function isge(x,y : real) : boolean; {is x >= y?}
begin
if x - y >= - ksFuzz * abs(0.5 * x + 0.5 * y)
then isge := true else isge := false
end; {isge}
function isgt(x,y : real) : boolean; {is x > y?}
begin
if x - y > ksFuzz * abs(0.5 * x + 0.5 * y)
then isgt := true else isgt := false
end; {isgt}
function isle(x,y : real) : boolean; {is x <= y?}
begin
if x - y <= ksFuzz * abs(0.5 * x + 0.5 * y)
then isle := true else isle := false
end; {isle}
function islt(x,y : real) : boolean; {is x < y?}
begin
if x - y < - ksFuzz * abs(0.5 * x + 0.5 * y)
then islt := true else islt := false
end; {islt}
function isfile(filn : pathstr) : boolean;
var
dirname,curdir : dirstr;
fname : namestr;
ext : extstr;
sname,result : pathstr;
begin
fsplit(filn,dirname,fname,ext);
if (length(dirname) > 3) and (dirname[length(dirname)] = '\')
then dirname := copy(dirname,1,length(dirname) - 1);
getdir(0,curdir);
{$I-} chdir(dirname); {$I+}
if ioresult <> 0 then begin chdir(curdir); isfile := false; exit end;
sname := fname + ext;
result := fsearch(sname,dirname);
if result = '' then isfile := false
else isfile := true;
chdir(curdir)
end; {isfile}
{the randnum1 generator is from an outline provided by Greg Hasshold. It is
fast and appears to have a very long cycle and nice randomness properties}
procedure initrand1;
var
i,j : byte;
dword : array[1..4] of byte;
rnum : longint absolute dword;
begin
randomize;
for i := 0 to 123 do
begin
for j := 1 to 4 do dword[j] := random(256);
rstack[i] := rnum
end;
rptr1 := 36
end; {initrand1}
function randnum1 : real;
var
rptr2 : byte;
begin
inc(rptr1);
if rptr1 = 124 then rptr1 := 0;
if rptr1 > 36 then rptr2 := rptr1 - 37 else rptr2 := 87 + rptr1;
randnum1 := rstack[rptr2] / 4294967295.0 + 0.5;
rstack[rptr2] := rstack[rptr2] xor rstack[rptr1]
end; {randnum1}
function pexp(x : real) : real; {exp protected from underflow and overflow}
begin
if x < -1419 then pexp := 0.0
else if x > 709 then pexp := ksmissing
else pexp := exp(x)
end; {pexp}
procedure setSigD(var sigD : byte);
begin
if sigD = 0 then sigD := 12
else if sigD < 14 then sigD := sigD + 2
else sigD := 16
end; {setSigD}
function zpdf(z : real) : real;
begin
if z = ksmissing then begin zpdf := ksmissing; exit end;
zpdf := pexp(-z * z / 2.0) / s2pi
end; {zpdf}
function zcdf(z : real; sigD : byte) : real;
var
cdf, errTol : real;
zisNeg : boolean;
procedure useSeries;
var
sum,term,zz : real;
kount : word;
begin
zz := z * z; term := z; sum := z; kount := 2;
while abs(term) > errTol * sum do
begin
term := - (term * zz / kount) * ((kount - 1) / (kount + 1));
sum := sum + term;
kount := kount + 2
end;
cdf := 0.5 + sum / s2pi;
if zisNeg then cdf := 1.0 - cdf;
end ; {useSeries}
procedure useConFrac;
var
kount : word;
lnq,term,sum,zz,beta,lnerr,tmpr : real;
begin
zz := z * z; term := 1.0; sum := 1.0; kount := 1; beta := 1.0;
while abs(term) > errtol * sum do
begin
beta := 1.0 / (1.0 + kount * beta / zz);
term := (beta - 1.0) * term;
sum := sum + term;
inc(kount)
end;
lnq := ln(sum) - zz / 2.0 - ln(s2pi) - ln(z);
if zisNeg
then cdf := pexp(lnq)
else
begin
tmpr := pexp(lnq);
if tmpr = ksmissing then cdf := ksmissing
else cdf := 1.0 - tmpr
end
end; {useConFrac}
begin {zcdf}
if z = ksmissing then begin zcdf := ksmissing; exit end;
setSigD(sigD);
errTol := 0.5 * pexp(-sigD * ln(10.0));
zisNeg := false; if z < 0.0 then begin zisNeg := true ; z := -z end;
if z = 0.0 then cdf := 0.5 else if z < 2.25 then useSeries else useConFrac;
zcdf := cdf
end; {zcdf}
function zinvest(cdf : real) : real;
var
reversed : boolean;
t, num, den : real;
begin
if cdf > 0.5 then begin cdf := 1 - cdf; reversed := false end else reversed := true;
t := sqrt(-2.0 * ln(cdf));
num := 2.515517 + t * (0.802853 + t * 0.010328);
den := 1.0 + t * (1.432788 + t * (0.189269 + t * 0.001308));
t := t - num / den; {pr(Z > t) = cdf}
if reversed then zinvest := -t else zinvest := t
end; {zinvest}
function zinv(cdf : real; sigD : byte) : real;
var
errTol, z1, z2, p1, p2 : real;
zisNeg : boolean;
begin
if isle(cdf,0.0) or isge(cdf,1.0) then begin zinv := ksMissing; exit end;
setSigD(sigD);
errTol := 0.5 * pexp(-sigD * ln(10.0));
zisNeg := false;
if cdf < 0.5 then begin zisNeg := true; cdf := 1.0 - cdf end;
if iseq(cdf,0.5) then begin zinv := 0.0; exit end
else
begin
z2 := zinvest(cdf); p2 := zcdf(z2,sigD);
repeat
z1 := z2; p1 := p2;
z2 := z1 - (p1 - cdf) / zpdf(z1);
p2 := zcdf(z2,sigD)
until abs(p2 - cdf) < errTol;
z1 := z2 + (z2 - z1) * (cdf - p2) / (p2 - p1);
if zisneg then zinv := -z1 else zinv := z1
end
end; {zinv}
function lngamma(x : real) : real;
var
i : word;
j,intx : longint;
y,lngam,y2,tmp1,tmp2 : real;
begin
if isle(x,0.0) or isgt(x,65535.0) then begin lngamma := ksMissing; exit end;
if iseq(x,round(x)) then
begin
intx := round(x);
tmp1 := 0.0;
for i := 2 to intx - 1 do tmp1 := tmp1 + ln(i);
lngamma := tmp1;
exit
end;
intx := trunc(x);
if iseq((2.0 * x),2 * intx + 1) then
begin
tmp1 := 0.0;
for j := 2 to intx do tmp1 := tmp1 + ln(2 * j - 1);
lngamma := tmp1 + 0.5 * ln(pi) - intx * ln(2.0);
exit
end;
if intx < 12 then y := 12.0 + frac(x) else y := x;
y2 := 1.0 / sqr(y);
tmp1 := (y - 0.5) * ln(y) - y + 0.5 * ln(2.0 * pi);
tmp2 := b[5]; for i := 4 downto 0 do tmp2 := b[i] + y2 * tmp2;
lngam := tmp1 + tmp2 * (1.0 / (12.0 * y));
if intx < 12 then for i := 0 to 11 - intx do lngam := lngam - ln(x + i);
lngamma := lngam
end; {lngamma}
function poispdf(x : integer; mu : real) : real;
begin
if isle(mu,0.0) or (mu = ksmissing) then begin poispdf := ksmissing; exit end;
poispdf := pexp( x * ln(mu) - mu - lngamma(x+1.0))
end; {poispdf}
function poiscdf(x : integer; mu : real) : real;
var
lnmu, lnpdf, pdf, cdf : real;
k : word;
begin
if isle(mu,0.0) or (mu = ksmissing) then begin poiscdf := ksMissing; exit end;
lnmu := ln(mu);
lnpdf := -mu;
pdf := pexp(lnpdf);
cdf := pdf;
for k := 1 to x do
begin
lnpdf := lnpdf + lnmu - ln(k);
pdf := pexp(lnpdf);
cdf := cdf + pdf;
end;
poiscdf := cdf
end; {poiscdf}
function poisinv(cdf, mu : real; var cdflo, cdfhi : real) : integer;
var
templ : longint;
x : integer;
cdfold, cdfx, pdfx : real;
begin
if isle(mu,0.0) or (mu = ksmissing) or islt(cdf,0.0) or isge(cdf,1.0) then
begin
cdflo := ksMissing;
cdfhi := ksMissing;
poisinv := 32767;
exit
end;
if iseq(cdf,0.0) then
begin
cdflo := 0.0;
cdfhi := pexp(-mu);
poisinv := -1;
exit
end;
templ := round(mu + sqrt(mu) * zinv(cdf,4));
if templ < 0 then x := 0 else if templ < 32767 then x := templ else
begin poisinv := 32767; cdflo := ksMissing; cdfhi := ksMissing; exit end;
cdfx := poiscdf(x,mu);
pdfx := poispdf(x,mu);
if iseq(cdf,cdfx) then
begin
poisinv := x;
cdflo := cdfx;
cdfhi := cdfx + poispdf(x + 1,mu);
end
else
if cdfx < cdf then
begin
repeat
inc(x);
cdfold := cdfx;
pdfx := pdfx * mu / x;
cdfx := cdfx + pdfx;
until cdfx > cdf;
poisinv := x - 1;
cdflo := cdfold;
cdfhi := cdfx
end
else
begin
repeat
dec(x);
cdfold := cdfx;
cdfx := cdfx - pdfx;
pdfx := pdfx * (x + 1.0) / mu
until cdfx <= cdf;
poisinv := x;
cdflo := cdfx;
cdfhi := cdfold
end
end; {poisinv}
begin
s2pi := sqrt(2.0 * pi);
b[0] := 1.0;
b[1] := -1.0 / 30.0;
b[2] := 1.0 / 105.0;
b[3] := -1.0 / 140.0;
b[4] := 1.0 / 99.0;
b[5] := -691.0 / 30300.0;
for i := 0 to 5 do a[i] := 0; a[6] := $f0; a[7] := $7f;
ksmissing := real(a)
end.