home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
games
/
leastq.zip
/
LEASTQ.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-02-17
|
42KB
|
1,197 lines
Program LEASTQ; { This program is for TURBO PASCAL 5.0 }
{Copywrite (c) July 1989
John D. Fox
309 N. W. 24th St.
Gainesville, Florida 32607 }
{$N+,E+} { simulate 80x87 if not available }
{$D+,L+,S+,V+} { turn these on when changing code }
uses Crt,Dos,Graph,Printer,Drivers;
type float = double;
const bombthreshold = 1.0E-16;
const epsilon = 1.0E-10;
const copywt = 'Copywrite (c) 07/24/89, John D. Fox';
const
max = 11; maxpts = 1024; { change these if you like }
size: array[1..19] of float = (0.01,0.02,0.05,0.1,0.2,0.5,1.0,2.0,5.0,
10.0,20.0,50.0,100.0,200.0,500.0,1000.0,2000.0,5000.0,10000.0);
{ This program uses some (shudder . . gasp . . gurgle . .) LABELS!!! }
label datinput,start,xlimits,terms;
type matrx = array[0..max] of array[0..max] of float;
species =
(powers,sines,cosines,fourier,oddsines,cheby,legendre,bessels,expon,gauss);
vector = array[1..maxpts] of float;
coeff = array[0..max] of float;
cpoint = ^coeff;
textline = string[80];
phrase = string[14];
var H,HINV,TEMP : matrx;
x,y,yc,err,sigsq,ysave: vector;
a,T,P,JJ,errc,pct : coeff;
funct : species;
fudged : array[1..maxpts] of boolean;
fpoint : array[1..maxpts] of cpoint;
dsource,fname,inpt,
pswitch : phrase;
filename : array[1..20] of phrase;
data : text;
grDriver,grMode,
ErrorCode : integer; {initialize grapics mode}
dd : string[4]; {for goof proof data input}
xd,yd : word; {number of decimal points}
caption : textline;
chisq, {what we are trying to mininmize}
xmax,ymax,xmin,ymin, {limits of plot}
xtick, {spacing of horiz tics}
yleast, {smallest data point}
asave1,asave2,asave0, {restore a[i] for Gaussian fudge}
confid, {confidence level of fit }
len,cy,lmin,lmax,cent : float;
ix1,ix2,iy1,iy2, { coordinates on plot }
nticks, { for frame }
code,DOF,yscale : integer;
bombed,logplt,plotted,
filefound : boolean;
i, {row}
j, {column}
k, {data point index}
Npts,Dim,N,nfiles : word;
ch : char;
Function YN: boolean;
begin
repeat ch := ReadKey; ch := Upcase(ch) until ch in['Y','N'];
if ch = 'Y' then YN := True else YN := False;
end;
Procedure ABORT(Msg : string);
begin
Writeln(msg, ':',GraphErrorMsg(ErrorCode));
Halt(1);
end;
Procedure CWRITE(caption:textline); { Highlight capital letters}
var ch : char; k : integer;
begin
for k := 1 to length(caption) do begin
ch := caption[k];
if ch in ['A'..'Z'] then begin
Textcolor(14); write(ch); Textcolor(7); end
else write(ch);
end;
end;
Procedure CAPITALIZE(var upword : phrase);
begin
for j := 1 to length(upword) do upword[j] := Upcase(upword[j]);
end;
Procedure DATAFILES; { find the available data files }
const datafl = '*.DAT'; { and select one }
var
Filerecord : SearchRec;
i,j : word;
begin
TextColor(7);
TextBackground(0);
ClrScr;
writeln('Files on this directory with extension ".DAT" are:'); writeln;
j := 0;
FindFirst(datafl,AnyFile, Filerecord);
if (DosError = 0) then begin
Inc(j); filename[j] := Filerecord.name end;
while (DosError = 0) and (j < 20) do begin
FindNext(Filerecord);
if DosError = 0 then begin
Inc(j); filename[j] := Filerecord.name end;
end;
nfiles := j;
if nfiles > 0 then
for j := 1 to nfiles do writeln
(' ',j:2,' ',filename[j]);
writeln(' ',nfiles+1:2,' . . None of the above . . . .');
writeln;
repeat
write('Enter number of data file to use: ');
readln(dd);
Val(dd,i,code);
until (code = 0) and (i in [1..nfiles + 1]);
if i = nfiles + 1 then dsource := 'NONAME' else dsource := filename[i];
end; { of DATAFILES }
Procedure SORT; { sort data points in order of ascending x }
var xtemp,ytemp,errtemp : float;
begin
for k:= 2 to Npts do begin
xtemp := x[k]; ytemp := y[k]; errtemp := err[k];
j := k;
while (x[j-1] > xtemp) and (j > 1) do begin { point out of place ? }
x[j] := x[j-1]; { then move the }
y[j] := y[j-1]; { other points up }
err[j] := err[j-1]; { like a deck of cards }
j := j-1; { to make a hole for it }
end;
x[j] := xtemp; y[j] := ytemp; err[j] := errtemp; { and insert point }
end;
end;
Procedure LIMITS; { Finds values of xmax,ymax,xmin,ymin }
var xmost,xleast,ymost,span : float;
ispan : word;
begin
(****** find x limits ******)
xleast := x[1]; xmost := x[Npts]; { data has been sorted on x }
span := xmost - xleast;
while span > 100.0 + epsilon do span := span/10.0;
while span < (10.0 - epsilon) do span := 10.0*span; { 10 < span < 100 }
ispan := Trunc(span);
if ispan mod 5 = 0 then begin {perfect fit to 5 tics?}
xmin := xleast; xmax := xmost end
else begin { nope, then fit with standard sizes }
k := 0;
repeat inc(k) until size[k] > (xmost-xleast)/20.0 - epsilon;
xmin := 0;
if (xleast + epsilon) < 0 then
repeat xmin := xmin - size[k] until xmin < xleast - epsilon
else begin
repeat xmin := xmin + size[k] until xmin > xleast + epsilon;
xmin := xmin - size[k];
end;
xmax := xmin;
repeat xmax := xmax + size[k] until xmax > xmost - epsilon
end;
(****** find y limits *****)
ymost := -100000.0;
yleast := 100000.0; { y s not sorted, so find yleast,ymost }
for k := 1 to Npts do begin
ysave[k] := y[k];
if y[k] > ymost then ymost := y[k];
if y[k] < yleast then yleast := y[k];
end;
k := 0;
repeat inc(k) until size[k] > (ymost - yleast)/10.0 - epsilon;
ymin := 0;
if (yleast + epsilon) < 0 then
repeat ymin := ymin - size[k] until ymin < yleast - epsilon
else begin
repeat ymin := ymin + size[k] until ymin > yleast + epsilon;
ymin := ymin - size[k]
end;
ymax := ymin;
repeat ymax := ymax + size[k] until ymax > (ymost + epsilon);
end; { of LIMITS }
Procedure READFILE; {Read in the selected file; must be on the same disk}
begin
filefound := True;
Assign(data,dsource);
{$I-} Reset(data); {$I+}
if IOresult = 0 then begin
Npts := 0;
k := 0;
while not EOF(data) and (k < maxpts) do begin
Inc(k); readln(data,x[k],y[k],err[k]);
if err[k] = 0 then k := k-1; {no points with zero error allowed}
sigsq[k] := err[k]*err[k];
end;
Npts := k;
SORT; LIMITS;
Close(data);
end else filefound := False;
end;
Procedure WRITEFILE; { Save data entered from keyboard }
var DFILE : phrase;
begin
repeat
write('Name of File (no extension): '); readln(dsource);
until length(dsource) in [1..8];
CAPITALIZE(dsource);
DFILE := dsource + '.DAT';
Assign(data,DFILE);
Rewrite(data);
writeln('Writing data to disk as ',DFILE);
for k := 1 to Npts do writeln(data,x[k]:12:xd,y[k]:12:yd,err[k]:12:yd);
Close(data);
end;
Procedure ERASE(nn:integer); { Blank out previous text}
var xx,yy :integer;
begin
xx := GetX; yy := GetY;
SetFillStyle(1,1);
Bar(xx,yy,xx+nn,yy+8);
MoveTo(xx,yy);
end;
Procedure BLINK; { Graphics equiv of blinking cursor }
var x,y : integer;
begin
x := GetX; y := GetY;
SetFillStyle(1,1);
repeat
OutText('_');
Delay(150);
MoveTo(x,y);
Bar(x,y,x+10,y+10);
Delay(150);
until KeyPressed;
end;
Procedure REALIN(var xx:float); { Graphics equiv of Readln }
begin
inpt := '';
repeat
BLINK;
ch := ReadKey;
if ch in ['+'..'9'] then begin
inpt := inpt + ch;
OutText (ch);
end;
if ch = #8 then begin
MoveTo(Getx-8,Gety);
Delete(inpt,length(inpt),1);
ERASE(8)
end;
until ch = #13;
if inpt <> '' then Val(inpt,xx,code);
end;
Procedure WORDIN(var kk:word); { Input word }
begin
inpt := '';
repeat
BLINK;
ch := ReadKey;
if ch in ['-','0'..'9'] then begin
inpt := inpt + ch;
OutText (ch)
end;
if ch = #8 then begin
MoveTo(GetX-8,Gety);
Delete(inpt,length(inpt),1);
ERASE(8)
end;
until ch = #13;
if inpt <> '' then Val(inpt,kk,code);
end;
Procedure OUTWR(x:float); {graphics equivalent of Write(x)}
var msg : string[5];
begin
if x > 100.0 then Str(x:5:1,msg) { e.g. 182.0 }
else if x > 10.0 then Str(x:5:2,msg) { e.g. 18.2 }
else if x > 1.0 then Str(x:5:3,msg) { e.g. 1.82 }
else Str(x:5:4,msg); { e.g. 0.182 }
OutText(msg);
end;
Procedure XTICS; { calculate horizontal spacing for 4 or 5 tics }
var xscale : float;
iscale : integer;
begin { calculate iscale between 10 and 100 }
xscale := xmax - xmin;
while xscale > 100.001 do xscale := xscale/10.0;
while xscale < 9.9999 do xscale := xscale*10.0;
iscale := Trunc(xscale +0.001);
if (iscale mod 10 = 0) and (iscale > 30) then nticks := iscale div 10 else
if iscale mod 5 = 0 then nticks := 5
else if iscale mod 4 = 0 then nticks := 4
else if iscale mod 4 < iscale mod 5 then nticks := 4
else nticks := 5;
xtick := 500.0*(iscale div nticks)/xscale;
end;
Procedure DECIMALS; {Calculate number of decimals for output}
var xxd,yyd : float;
begin
if abs(xmax) > abs(xmin) then xxd := abs(xmax) else xxd := abs(xmin);
if xxd > 10000.0 then xd := 0
else if xxd > 100.0 then xd := 1
else if xxd > 10.0 then xd := 2
else xd := 3;
if abs(ymax) > abs(ymin) then yyd := abs(ymax) else yyd := abs(ymin);
if yyd > 10000.0 then yd := 0
else if yyd > 100.0 then yd := 1
else if yyd > 10.0 then yd := 2
else if yyd > 0.1 then yd := 3
else yd := 4;
end;
Procedure LOGTICS; { make semi-log graph paper}
var ii : integer;
logsize : float;
begin
for k := 1 to 19 do begin
logsize := ln(size[k]);
if (logsize > ymin) and (logsize < ymax) then begin
ii := 10 + Round(yscale*(ymax - logsize)/(ymax - ymin));
Line(100,ii,110,ii); Line(590,ii,600,ii); { draw tics }
MoveTo(70,ii); OUTWR(size[k]); { label tics }
end;
end;
MoveTo(70,10); OUTWR(exp(ymax));
MoveTo(70,yscale + 10); OUTWR(exp(ymin));
SetTextStyle(0,1,0);
MoveTo(25,yscale div 2); OutText('L O G A R I T M I C S C A L E');
SetTextStyle(0,0,0);
end;
Procedure DRAWFRAME;
var vtick,itick : integer;
xlabel,ylabel : float;
begin
XTICS; DECIMALS;
SetGraphMode(GetGraphMode);
SetBkColor(1); SetColor(7);
SetTextJustify(CenterText,CenterText);
Rectangle(100,10,600,(yscale+10)); { draw frame }
for j := 0 to nticks do begin
itick := 100 + Round(j*xtick); { draw horizontal tics }
Line(itick,yscale,itick,yscale+10);
Line(itick,10,itick,20);
xlabel := xmin +j*(xmax-xmin)*xtick/500.0;
Moveto(itick,yscale+18); OUTWR(xlabel); { label horizontal tics }
end;
if logplt then LOGTICS else begin
if ymax/(ymin+0.001) > 2.6 then ymin := 0.0;
for i := 0 to 4 do begin { draw vertical tics }
vtick := 10 + ((4-i)*yscale div 4);
Line(100,vtick,110,vtick);
Line(590,vtick,600,vtick);
ylabel := ymin + i*(ymax-ymin)/4.0;
MoveTo(70,vtick); OUTWR(ylabel); { label vertical tics }
end;
end;
MoveTo(350,5); SetColor(12); OutText(dsource); { lable picture }
SetTextJustify(LeftText,TopText);
end; { of DRAWFRAME }
Procedure PLOTPOINT(pcolor:integer); { data point is a little square }
begin { with error flag }
SetColor(pcolor);
ix1 := Round(500.0*(x[k] - xmin)/(xmax-xmin)) + 100; ix2 := ix1;
iy1 := 10 + Round(yscale*(ymax - y[k] - err[k])/(ymax - ymin));
iy2 := 10 + Round(yscale*(ymax - y[k] + err[k])/(ymax - ymin));
Line(ix1,iy1,ix2,iy2); { Draw error flag }
ix1 := ix1 - 1; iy1 := 1 + (iy1 + iy2) div 2; { fatten flag in the middle }
for i := 0 to 2 do Putpixel(ix1,iy1-i,pcolor); { to make point }
ix1 := ix1 + 2;
for i := 0 to 2 do Putpixel(ix1,iy1-i,pcolor);
end;
Procedure PLOTPOINTS;
var pcolor : integer;
begin
for k := 1 to Npts do begin
if fudged[k] then pcolor := 10 else pcolor := 12;
PLOTPOINT(pcolor);
end;
end;
Procedure NEATWR(xx:float); {write floating point number in 7 spaces}
begin
if abs(xx) >= 1000.0 then write(xx:7:1) { e. g. -1234.5 }
else if abs(xx) >= 100 then write(xx:7:2) { e. g. -123.45 }
else if abs(xx) >= 10.0 then write(xx:7:3) { e. g. -12.345 }
else if abs(xx) >= 1.0 then write(xx:7:4) { e. g. -1.2345 }
else write(xx:7:4); { e. g. -0.1234 }
end;
Procedure READIN(var xx:float); { goof proof data input }
var x,y : integer; {input terminated by <CR> or arrow keys}
begin
x := WhereX; y := WhereY;
repeat
code := 0;
inpt := '';
repeat
ch := Readkey;
if (ch = #0) and Keypressed then ch := Readkey;
if ch in ['-'..'9'] then inpt := inpt + ch;
if ch = #8 then Delete(inpt,Length(inpt),1);
gotoXY(x,y); write(inpt)
until ch in [#13,#27,#72,#75,#77,#80];
if inpt <> '' then begin
Val(inpt,xx,code);
if code <> 0 then begin
gotoXY(x,y); write (' '); write(#7); gotoXY(x,y) end;
end;
until code = 0;
gotoXY(x,y); NEATWR(xx);
end; { of READIN }
Procedure REPAIR; { view data on screen and correct points }
label Start; { <===== yet another loathesome LABEL! }
var xnew,ynew,errnew : float;
begin
Setcolor(12);
Start:
repeat
MoveTo(150,yscale+26); ERASE(300);
OutText('Point to fix: ');
WORDIN(k);
if (k < 1) or (k > Npts) then begin { not a possible point }
OutText(' No such point');
write(#7);
Delay(400);
end;
until k in [1..Npts];
PLOTPOINT(15);
MoveTo(300,yscale + 26); OutText('This it? ');
repeat PLOTPOINT(1); Delay(150); PLOTPOINT(15); delay(150) until Keypressed;
if not YN then begin PLOTPOINT(12); goto Start end; { wrong point }
{ point accepted for alteration; now adjust its values}
PLOTPOINT(15);
if plotted then fudged[k] := true; { henceforth, will be plotted in green }
xnew := x[k]; ynew := y[k]; errnew := err[k];
MoveTo(150,yscale + 38); ERASE(300); OutText('x[k] now =');
OUTWR(x[k]); OutText(' set to: ');
REALIN(xnew);
MoveTo(150,yscale + 38); ERASE(300); OutText('y[k] now =');
if logplt then OUTWR(exp(y[k])) else OUTWR(y[k]);
OutText(' set to: ');
REALIN(ynew);
MoveTo(150,yscale + 38); ERASE(300);
OutText('err[k] now ='); OUTWR(err[k]); OutText(' set to: ');
REALIN(errnew);
PLOTPOINT(1); {erase old point by plotting it in the background color }
x[k] := xnew; ysave[k] := ynew; err[k] := errnew;
if logplt then y[k] := ln(ynew) else y[k] := ynew;
PLOTPOINT(10);
SetColor(13);
MoveTo(450,yscale + 38); OutText('More?'); BLINK;
if YN then begin
MoveTo(150,yscale+38); ERASE(380); goto Start end;
RestoreCrtMode;
end; { of REPAIR }
Procedure KEYBOARD; { read data from keyboard }
var steps,count : boolean;
x0,step,numbin : float;
i,j,ix,iy,kk,top : word;
begin
ClrScr;
writeln(' OK, Input from Keyboard');
steps := False; count := False;
write('Uniform steps in x ? ');
if YN then begin
writeln('Yes');
x0 := 0; step := 1.0; { default values }
steps := True;
write(' First x = '); READIN(x0);
write(' step = '); READIN(step);
writeln(' Program will supply the x coodinates');
writeln
end
else writeln('No');
write('Is y a count? ');
if YN then begin
write(' Yes ');
writeln(' Program will supply the errors');
count := True
end;
k := 1;
gotoXY(1,8);
writeln(' Use cursor keys to correct mistakes, <Esc> to exit');
Textbackground(4);
gotoXY(4,9); write(' Point # x[k] y[k] err[k] ');
Window(4,10,52,24);
for i := 1 to 16 do begin gotoxY(1,i); ClrEol end;
k := 1; Npts := 1; top := 1;
if not steps then j := 1 else
begin x[k] := x0; gotoXY(12,1); NEATWR(x[k]); j := 2 end;
repeat
ix := 12 + 12*(j-1); iy := k-top+1;
if k < Npts then begin
case j of
1 : numbin := x[k];
2 : numbin := y[k];
3 : numbin := err[k];
end;
gotoXY(ix,iy); Textbackground(0); NEATWR(numbin);
gotoXY(ix,iy); Textbackground(4);
end
else numbin := 0;
gotoXY(ix,iy);
READIN(numbin);
case j of
1: begin
x[k] := numbin;
case ch of
#13,#77 : inc(j);
#72 : if k > 1 then dec(k);
#80 : if k < Npts then inc(k);
#75 : WRITE(#7);
end;
end;
2 : begin
y[k] := numbin;
if count and (ch = #13) then begin
if (numbin > 1.0 - epsilon) then begin
err[k] := sqrt(numbin); gotoXY(36,iy); NEATWR(err[k]); end
else begin
ch := #20;
write(#7);
gotoXY(18,iy); write('*** NEG COUNT NOT ALLOWED ***');
Delay(1000); gotoXY(18,iy); ClrEOL;
end;
end;
case ch of
#13,#77 : if not count then inc(j) else begin
inc(k); if not steps then dec(j) end;
#80 : begin
if not count then err[k] := err[k-1];
gotoXY(36,iy); NEATWR(err[k]);
inc(k);
end;
#72 : if k > 1 then dec(k) else WRITE(#7);
#75 : if not steps then dec(j) else WRITE(#7);
end;
end;
3 : begin
if numbin > epsilon then err[k] := numbin else begin
err[k] := err[k-1]; gotoXY(ix,iy); NEATWR(err[k]); end;
case ch of
#13,#77 : begin if steps then j := 2 else j := 1; inc(k) end;
#80 : if k < Npts then inc(k);
#72 : if k > 1 then dec(k);
#75 : dec(j);
end;
end;
end; {case j}
if k > Npts then begin
Npts := k;
top := 1; if k > 15 then top := k - 14;
for kk := top to k-1 do begin
iy := kk - top + 1;
gotoXY(5,iy); write(kk);
gotoXY(12,iy); NEATWR(x[kk]);
gotoXY(24,iy); NEATWR(y[kk]);
gotoXY(36,iy); NEATWR(err[kk]);
end;
gotoXY(1,iy+1); ClrEOL;
if steps then begin
x[k] := x0 + (k-1)*step; gotoXY(12,iy+1); NEATWR(x[k]); end;
err[k] := err[k-1];
end;
until ch = #27;
npts := npts-1;
(*repeat { start entering data points }
write('Point #',k:2,' x = ');
if steps then begin
x[k] := x0 + (k-1)*step;
gotoXY(16,whereY); write(x[k]:7:3);
end
else READIN(x[k]);
gotoXY(28,whereY); ClrEol; write('y = ');
repeat
READIN(y[k]);
if count and (y[k] < 0) then begin
write('***NEG COUNT NOT ALLOWED***');
write(#7);
Delay(1000);
gotoXY(32,whereY); ClrEol;
end;
until not count or (y[k] > 0);
gotoXY(44,whereY);
write('error = ');
if count then begin
err[k] := sqrt(y[k]);
gotoXY(52,whereY);
writeln(err[k]:8:4);
end
else begin err[k] := err[k-1]; READIN(err[k]); writeln end;
write('More? (<CR>=Yes)');
ch := ReadKey; ch := Upcase(ch);
gotoXY(1,whereY); ClrEol;
if (ch = #13) or (ch = 'Y') and (err[k] > 0) then inc(k);
until (k > maxpts) or (Upcase(ch) = 'N') or (Upcase(ch) = 'Q');
Npts := k;*)
Window(1,1,80,25);
Textbackground(0);
{ plot data and correct mistakes }
if Npts > 2 then begin
SORT; LIMITS; DRAWFRAME; PLOTPOINTS;
MoveTo(250,yscale+ 26); OutText('Is this data OK?'); BLINK;
if not YN then REPAIR;
RestoreCrtMode; Textcolor(7);
for k := 1 to Npts do sigsq[k] := err[k]*err[k];
writeln; write(' Save input data to disk? ');
if YN then WRITEFILE;
filefound := True;
end;
end; { of KEYBOARD }
Procedure LEGEND(xx:float; nn:word); { Legendre polynomials }
var m : word; { by forward recursion }
begin
P[0] := 1;
P[1] := xx;
P[2] := (3.0*xx*xx - 1.0)/2.0;
if nn > 2 then
for m := 3 to nn do P[m] := ((2*m-1)*xx*P[m-1] - (m-1)*P[m-2])/m;
end;
Procedure CHEB(xx: float; nn:word); { Chebychev polynomials }
var m : word; { by forward recursion }
begin
T[0] := 1;
T[1] := xx;
T[2] := 2.0*xx*xx - 1;
if nn > 2 then for m := 3 to nn do T[m] := 2.0*xx*T[m-1] - T[m-2];
end;
Procedure BESSY(xx:float; nn:word); { Bessel functions }
var n,nmax : word; { by backward recursion }
J : array[0..50] of float;
sum : float;
begin
for n := 0 to nn do JJ[n] := 0;
if xx > 0.001 then begin
nmax := Trunc(9.0*sqrt(xx+1.0));
J[nmax] := 1.0;
J[nmax+1] := 0.0;
sum := 0;
for n := nmax downto 1 do begin
J[n-1] := (2.0*n/xx)*J[n] - J[n+1];
if n mod 2 = 0 then sum := sum + 2.0*J[n];
end;
sum := sum + J[0];
for n := 0 to nn do JJ[n] := J[n]/sum;
end
else JJ[0] := 1.0;
end;
Procedure RANGE; { set range in x over which functions will operate }
begin
Textcolor(7);
writeln;
if funct in [powers,cheby,legendre,expon] then begin
lmin := xmin; lmax := xmax; {Default values}
write('xmin,',xmin:8:2,' equivalent to: ');
if funct in [cheby,legendre] then write('(must be >= -1.0 )');
Textcolor(14); READIN(lmin); Textcolor(7); writeln;
write('xmax,',xmax:8:2,' equivalent to: ');
if funct in [cheby,legendre] then write('(must be <= +1.0 )');
Textcolor(14); READIN(lmax); Textcolor(7); writeln;
len := (xmax - xmin)/(lmax - lmin);
end;
if funct in [sines..oddsines] then begin
lmin := 0; cy := 1.0; {default values}
write('x range represents how many cycles? ');
Textcolor(14); READIN(cy); Textcolor(7); writeln;
len := (xmax-xmin)/(2*Pi*cy);
end;
if funct = bessels then begin { special treatment for Bessels}
lmin := 0; lmax := 1.0; {default}
repeat
write('xmin, ',xmin:8:2,' equivalent to: (must be >= 0)');
Textcolor(14); READIN(lmin); Textcolor(7); writeln;
write('xmax, ',xmax:8:2,' equivalent to: ');
Textcolor(14); READIN(lmax); Textcolor(7); writeln;
if lmax > 25.0 then writeln
('Program can"t calculate Bessel funct for arguments this big');
until (lmax > lmin) and (lmax < 25.0);
len := (xmax-xmin)/(lmax-lmin);
end;
if funct = gauss then begin
lmin := 0; len := 1.0 end; {start at 1st data point}
end; { of RANGE }
Procedure DIMENSION; { Input number of terms in fit }
begin
if logplt then begin
if funct = expon then Dim := 2;
if funct = gauss then Dim := 3
end
else repeat
writeln; write(' Number of terms: ');
TextColor(14);
Readln(Dim);
if (Dim < 2) or (Dim > 12) or (Dim >= Npts) then write(#7);
if Dim < 2 then writeln('***** MUST HAVE AT LEAST TWO TERMS *****');
if Dim > 12 then writeln('***** NO MORE THAN 12 TERMS, PLEASE *****');
if Dim >= Npts then writeln('*****TOO MANY TERMS, NOT ENOUGH DATA *****');
TextColor(7);
until (Dim < Npts) and (Dim in [2..max+1]);
N := Dim-1; DOF := Npts - Dim;
end;
Function FUNC(x:float; nn:word):float; { Calculate f[nn](x) according to }
var f,xx : float; m: word; { species of function }
begin
f := 1.0;
xx := lmin + (x - xmin)/len;
case funct of
powers,expon,gauss : for m := 1 to nn do f := f*xx;
fourier : begin m := (nn+1) div 2;
if nn mod 2 = 0 then f := cos(m*xx) else f := sin(m*xx); end;
sines : if nn > 0 then f := sin(nn*xx);
cosines : f := cos(nn*xx);
oddsines : begin m := 2*nn+1; f := sin(m*xx); end;
cheby : begin CHEB(xx,nn); f := T[nn]; end;
legendre: begin LEGEND(xx,nn); f := P[nn]; end;
bessels : begin BESSY(xx,nn); f := JJ[nn]; end;
end;
FUNC := f;
end;
Procedure CONVERT; { Convert data to log of data for expon and gauss fit }
begin
for k := 1 to Npts do begin
ysave[k] := y[k];
err[k] := err[k]/y[k];
sigsq[k] := err[k]*err[k];
y[k] := ln(y[k]);
end;
ymax := ln(ymax);
ymin := ln(yleast); { subroutine LIMITS may have altered ymin }
end;
Procedure RESTORE; { Undo CONVERT }
begin
for k := 1 to Npts do begin
y[k] := ysave[k];
err[k] := err[k]*y[k];
sigsq[k] := err[k]*err[k];
end;
ymax := exp(ymax);
ymin := exp(ymin);
end;
Procedure GETFUN; { input species of function to fit}
const name : array[1..11] of phrase = ('Powerseries','Sines','Cosines',
'Fourier','Oddsines','Bessels','Tchebychev','Legendre',
'Exponential','Gaussian','View . . .');
var ii : word;
capt : array[0..11] of textline;
Procedure VIEWPOINTS; { choose function species from graphics display}
begin
DRAWFRAME; PLOTPOINTS;
SetColor(2);
for i := 1 to 10 do begin
MoveTo(5,21+i*10); ERASE(8*length(name[i]));
OutTextXY(5,20+i*10,name[i]);
Setcolor(10); OutTextXY(5,20+10*i,name[i,1]);
Setcolor(2);
end;
MoveTo(5,yscale div 2 + 30); OutText('your choice?');
SetColor(10); BLINK;
ch := ReadKey; ch := Upcase(ch);
RestoreCrtMode;
end;
begin
capt[1] := ' y = a0 + a1*x/len + a2*(x/len)^2 + . . . ';
capt[2] := ' y = a0 + a1*sin(x/len) + a2*sin(2*x/len) + . . . ';
capt[3] := ' y = a0 + a1*cos(x/len) + a2*cos(2*x/len) + . . . ';
capt[4] := ' y = a0 + a1*sin(x/len) + a2*cos(x/len) + . . . ';
capt[5] := ' y = a0*sin(x/len) + a1*sin(3*x/len) + . . .';
capt[6] := ' y = a0*J0(x/len) + a1*J1(x/len) + . . . ';
capt[7] := ' y = a0*T0(x/len) + a1*T1(x/len) + . . . ';
capt[8] := ' y = a0*P0(x/len) + a1*P1(x/len) + . . . .';
capt[9] := ' y = a0*exp(x/a1) ';
capt[10] := ' y = a0*exp[-(x-a1)^2/2*a2^2] ';
capt[11] := 'a plot of the data';
repeat
ClrScr; logplt := False;
writeln('Source file: ',dsource); writeln;
writeln(' Catalog of Functions'); writeln;
for i := 1 to 11 do begin
write(' '); CWRITE(name[i]);
gotoXY(22,whereY); writeln(capt[i]);
end;
writeln; Textcolor(14); write(' your choice: ');
ch := ReadKey; ch := Upcase(ch);
if ch = 'V' then VIEWPOINTS;
until ch in ['P','S','C','F','O','T','L','B','E','G'];
case ch of
'P' : begin funct := powers; ii := 1 end;
'S' : begin funct := sines; ii := 2 end;
'C' : begin funct := cosines; ii := 3 end;
'F' : begin funct := fourier; ii := 4 end;
'O' : begin funct := oddsines; ii := 5 end;
'B' : begin funct := bessels; ii := 6 end;
'T' : begin funct := cheby; ii := 7 end;
'L' : begin funct := legendre; ii := 8 end;
'E' : begin funct := expon; ii := 9; logplt := true; end;
'G' : begin funct := gauss; logplt := true; ii := 10 end;
end;
fname := name[ii]; caption := capt[ii];
if logplt and (yleast < 0.001) then begin
writeln('There are negative or zero values of y in your data.');
writeln('Can"t use this species of function with your data');
write(#7);
Delay(2000);
GETFUN
end;
Textcolor(14); writeln(' ',fname); writeln;
end; { of GETFUN }
Procedure PRECALC; { to save time, calculate f[n](x) at all x[k] }
var xx : float;
begin; { put precalculated functions on the heap}
{ to save space in data segment}
for n := 1 to Npts do GetMem(fpoint[n],sizeof(coeff));
writeln('Wait . . precalculating functions');
if funct = bessels then begin { save time }
for k := 1 to Npts do begin { do them 10 at a time}
xx := lmin + (x[k]-xmin)/len;
BESSY(xx,max);
for n := 0 to max do fpoint[k]^[n] := JJ[n];
end;
end
else for k := 1 to Npts do
for n := 0 to max do fpoint[k]^[n] := FUNC(x[k],n);
end;
Function YCALC(x:float):float; { with recursive functions save time }
var xx,y: float; { by calculating a bunch of them at once }
begin
y := 0;
xx := lmin + (x-xmin)/len;
case funct of
cheby : begin CHEB(xx,N); for i := 0 to N do y := y + a[i]*T[i]; end;
legendre : begin LEGEND(xx,N); for i := 0 to N do y := y + a[i]*P[i]; end;
bessels : begin BESSY(xx,N); for i := 0 to N do y := y + a[i]*JJ[i]; end;
else for i := 0 to N do y := y + a[i]*FUNC(x,i);
end;
YCALC := y;
end;
Procedure CHISQUARE;
begin
for k := 1 to Npts do yc[k] := YCALC(x[k]);
chisq := 0;
for k := 1 to Npts do chisq := chisq + sqr(y[k] - yc[k])/sigsq[k]
end;
Procedure INVERSE; { by Gauss-Jordan elimination }
var fact: float;
begin
bombed := False;
for i := 0 to N do for j := 0 to N do temp[i,j] := 0;
for i := 0 to N do temp[i,i] := 1.0;
for i := 0 to N do begin
if abs(h[i,i]) > bombthreshold then begin
if i > 0 then begin
for j := 0 to i-1 do begin {zero terms below the diagonal}
fact := h[j,i]/h[i,i];
for k := 0 to N do h[j,k] := h[j,k] - fact*h[i,k];
for k := 0 to N do temp[j,k] := temp[j,k] -fact*temp[i,k];
end;
end;
if i < N then begin
for j := i+1 to N do begin {zero terms above the diagonal}
fact := h[j,i]/h[i,i];
for k := 0 to N do h[j,k] := h[j,k] -fact*h[i,k];
for k := 0 to N do temp[j,k] := temp[j,k] - fact*temp[i,k];
end;
end;
end
else bombed := True;
end;
if bombed then writeln('MATRIX INVERSION BOMBED') else
for i := 0 to N do
for j := 0 to N do hinv[i,j] := temp[i,j]/h[i,i];
end; { of INVERSE }
Procedure MATRIX; { this procedure finds the a[i] }
var wy : vector;
begin
writeln('Building matrix');
for i := 0 to N do begin { build matrix on }
for j := i to N do begin { diagonal and above }
h[i,j] := 0;
for k := 1 to Npts do
h[i,j] := h[i,j] + fpoint[k]^[i]*fpoint[k]^[j]/sigsq[k];
h[j,i] := h[i,j]; { to save time, since matrix is symmetric }
end;
end;
writeln('Inverting matrix');
INVERSE;
if not bombed then begin
writeln('Calculating coefficients');
for k := 1 to Npts do wy[k] := y[k]/sigsq[k];
for i := 0 to N do begin
a[i] := 0;
for j := 0 to N do
for k := 1 to Npts do
a[i] := a[i] + wy[k]*fpoint[k]^[j]*hinv[j,i];
end;
end; {if not bombed}
end; { Procedure MATRIX }
Procedure PLOTCURVE;
var x2,y2,delta : float;
begin
Setcolor(10);
ix2 := 100; x2 := xmin;
delta := (xmax - xmin)/125.0;
y2 := YCALC(xmin); iy2 := 10 + Round(yscale*(ymax - y2)/(ymax - ymin));
for k := 1 to 125 do begin;
ix1 := ix2; iy1 := iy2;
ix2 := 4*k + 100;
x2 := x2 + delta; y2 := YCALC(x2);
iy2 := 10 + Round(yscale*(ymax - y2)/(ymax - ymin));
Line(ix1,iy1,ix2,iy2);
end;
Str(Dim,dd); dd := ', ' + dd;
MoveTo(250,yscale + 26); OutText(fname); OutText(dd); OutText(' terms');
end;
Procedure QUERY;
var caption : textline;
begin
plotted := true;
if logplt then OutTextXY(250,yscale+35,'Press any key to continue ')
else begin
MoveTo(120,yscale+38); OutText('Chisq = '); OUTWR(chisq);
Str(DOF,dd);
caption := ' for ' + dd + ' degrees of freedom. Accept fit? ';
OutText(caption); BLINK
end;
ch := ReadKey;
RestoreCrtMode;
Textcolor(7); ClrScr;
end;
Procedure FUDGE;
begin
if funct = expon then begin
a[0] := ln(a[0]); a[1] := 1/a[1]; CONVERT end;
if funct = gauss then begin
a[0] := asave0; a[1] := asave1; a[2] := asave2; CONVERT end;
{could have saved the plot image and restored here; this way uses less memory}
DRAWFRAME; PLOTPOINTS; PLOTCURVE; REPAIR;
if logplt then RESTORE;
end;
Function CL(Chisq:float; DOF:integer):float; { find confidence level }
var pchi,h,twoexph,gammah,x,y,step,sum : float;
begin
if chisq/DOF > 12.0 then begin CL := 0.0; Exit end;
if DOF/(chisq +0.0001) > 12.0 then begin CL := 1.0; Exit end;
h := DOF/2.0; { h for half }
if (chisq < 50.0) and (h <= 20.0) then begin
twoexph := exp(h*ln(2.0)); { = 2^h }
gammah := 2.507*exp((h-0.5)*ln(h))*(1.0+0.0833/h)/exp(h); { Gamma(h) by }
step := Chisq/100.0; { Stirling's approx }
x := 0; sum := 0;
for i := 1 to 100 do begin { Simpson's rule integration }
x := x + step;
pchi := exp((h-1.0)*ln(x))/exp(x/2.0);
sum := sum + 2.0*step*pchi;
if (i mod 2) > 0 then sum := sum + 2.0*step*pchi;
end;
CL := 1.0 - (sum - step*pchi)/(3.0*twoexph*gammah);
end
else begin { DOF > 40, assume p(chisq) normally distributed }
x := sqrt(2.0*chisq) - sqrt(4.0*h - 1.0);
y := abs(x);
{power series approx to integrated error funct calculated by LEASTQ }
{this expression apparently does not (quite) overflow the 8087 stack }
sum := 5000.16 + y*(3978.21 + y*(73.0309 -y*(824.04 -y*(135.194 +
y*(75.357 - y*(28.247 -2.73*y))))));
if x < 0 then CL := sum/10000.0 else CL := 1.0 - sum/10000.0;
if x > 3.5 then CL := 0.0;
if x < -3.5 then CL := 1.0;
end;
end; { of CL }
Procedure COMPARE;
var
column,k1,k2,k3 : word;
begin
if logplt then begin {convert yc[k] back to arithmetic and recalc chisq}
chisq := 0;
for k := 1 to Npts do begin
yc[k] := exp(yc[k]);
chisq := chisq + Sqr(y[k]-yc[k])/sigsq[k];
end;
DECIMALS;
end;
writeln;
writeln
(' ',dsource,': COMPARISON OF DATA WITH CALCULATED VALUES (* = fudged) ');
for k := 1 to 3 do write(' x ydata ycalc '); writeln;
column := Npts div 3;
Window(1,Dim+6,80,22);
gotoXY(1,1);
if Npts mod 3 > 0 then Inc(column); { write in snake format }
for k := 1 to column do begin
k1 := k; k2 := column + k; k3 := 2*column + k;
write(x[k1]:6:xd,y[k1]:8:yd,yc[k1]:8:yd);
if fudged[k1] then write('* ') else write (' ');
write(x[k2]:6:xd,y[k2]:8:yd,yc[k2]:8:yd);
if fudged[k2] then write('* ') else write (' ');
if k3 <= Npts then begin
write(x[k3]:6:xd,y[k3]:8:yd,yc[k3]:8:yd);
if fudged[k3] then write('*')
end;
writeln;
if k mod (16-Dim) = 0 then begin
write('. . . . hit <CR> for more . . . . ');
readln; gotoXY(1,WhereY-1) end;
end;
Window(1,1,80,25);
end;
Procedure GAUSSCONV;
var del0,del1,del2 : float;
b : coeff;
begin
b[0] := a[0] - a[1]*a[1]/(4*a[2]); { convert to parabola }
b[1] := -a[1]/(2*a[2]); { centered on b[1] }
b[2] := -a[2];
del0 := errc[0]; del1 := errc[1]; del2 := errc[2];
errc[0] := sqrt(del0*del0 +sqr(del1*b[1]) + sqr(del2*b[1]*b[1]));
errc[1] := sqrt(sqr(del1/(2*a[2]))+ sqr(del2*a[1]/(2*a[2]*a[2])));
errc[2] := del2/(4*sqrt(b[2]*b[2]*b[2]));
asave0 := a[0]; asave1 := a[1]; asave2 := a[2]; { save for FUDGE}
a[0] := exp(b[0]); errc[0] := exp(errc[0]); { to fit standard }
a[1] := xmin + b[1]; { definition }
a[2] := 1.0/sqrt(2.0*b[2]); { of a Gaussian }
end;
Procedure OUTWRITE; { display coefficents, a[i] and calculate CL }
begin
ClrScr; Textcolor(7);
for i := 0 to N do errc[i] := sqrt(hinv[i,i]);
if funct = gauss then GAUSSCONV;
if funct = expon then begin
a[0] := exp(a[0]); a[1] := 1.0/a[1];
errc[0] := a[0]*errc[0];
errc[1] := a[1]*a[1]*errc[1]
end;
write('a[i] for ',caption);
if funct = gauss then writeln( ' center (a1) = ',a[1]:7:3)
else writeln(' len =',len:7:4);
writeln;
for i := 0 to N do begin
pct[i] := 100*errc[i]/abs(a[i]+0.0001*errc[i]);
writeln
(' a',i,' = ',a[i]:13,' +/- ',errc[i]:10,' (',pct[i]:5:1,' % )');
end;
COMPARE;
gotoXY(1,22);
write('Chisq = ',chisq:7:3,' for ',DOF,' degrees of freedom. ');
write('Calculating CL, wait . . .');
confid := CL(chisq,DOF);
gotoXY(42,whereY); writeln(' Confidence level = ',confid:6:4);
end; { of OUTWRITE }
Procedure PRINTOUT;
var column,k1,k2,k3 : word;
year,month,day,dayofweek,hour,minute,second,sec100 : word;
begin
Write(Lst,' Data file: ',dsource,' fitted at ');
GetDate(year,month,day,dayofweek);
getTime(hour,minute,second,sec100);
writeln(Lst,hour:2,':',minute:2,' on ', month:2,'/',day:2,'/',(year-1900):2);
writeln(Lst,' function ',fname);
writeln(Lst);
write(Lst,'a[i] for ',caption);
if funct = gauss then writeln(Lst,' center (a1) = ',a[1]:7:3)
else writeln(Lst,' len =',len:7:3);
writeln(Lst);
for i := 0 to N do writeln(Lst,
' a',i,' = ',a[i]:13,' +/- ',errc[i]:10,' (',pct[i]:5:1,' % )');
writeln(Lst);
writeln(Lst,' COMPARISON OF DATA WITH CALCULATED VALUES ');
for k := 1 to 3 do write(Lst,' x ydata ycalc '); writeln(Lst);
column := Npts div 3;
if Npts mod 3 > 0 then Inc(column); { write in snake format }
for k := 1 to column do begin
k1 := k; k2 := column + k; k3 := 2*column + k;
write(Lst,x[k1]:6:xd,y[k1]:8:yd,yc[k1]:8:yd);
if fudged[k1] then write(Lst,'* ') else write(Lst,' ');
write(Lst,x[k2]:6:xd,y[k2]:8:yd,yc[k2]:8:yd);
if fudged[k2] then write(Lst,'* ') else write(Lst,' ');
if k3 <= Npts then write(Lst,x[k3]:6:xd,y[k3]:8:yd,yc[k3]:8:yd);
if fudged[k3] then writeln(Lst,'*') else writeln(Lst);
end;
writeln(Lst,' points marked "*" are fudged');
writeln(Lst);
write(Lst,'Chisq = ',chisq:7:3,' for ',DOF,' degrees of freedom. ');
writeln(Lst,' Confidence level = ',confid:6:4);
end;
begin { MAIN PROGRAM }
if copywt = '' then;
if length(paramstr(1)) > 2 then begin
dsource := paramstr(1); pswitch := paramstr(2) end
else begin dsource := ''; pswitch := paramstr(1) end;
(* makes EXE file with built in BGI driver for EGA/VGA *)
if RegisterBGIdriver(@EGAVGADriverProc) < 0 then ABORT('EGA/VGA');
(* you can compile without this, and without 'drivers' in the uses
statement. You will then need the EGAVGA.BGI file in the same
directory for LEASTQ.EXE to run *)
GrDriver := Detect;
if (pswitch = '/e') or (pswitch = '/E') then begin
GrDriver := EGA; GrMode := 1 end; { To force EGA }
InitGraph(GrDriver, GrMode, '');
ErrorCode := GraphResult; { Check for errors }
if ErrorCode <> grOK then ABORT('No Graphics');
yscale := GetMaxY - 50; {Vertical scale factor = 300 for EGA, 430 for VGA}
RestoreCrtMode;
datinput: { new Data option starts here }
plotted := false; logplt := False;
for k := 1 to 255 do fudged[k] := false;
if dsource = '' then DATAFILES else CAPITALIZE(dsource);
if dsource = 'NONAME' then KEYBOARD else READFILE;
if not filefound then begin
writeln('******* file not found *******');
write(#7);
Delay(1000);
dsource := '';
goto datinput
end;
if Npts < 3 then begin
write('Not enough valid points');
write(#7);
Delay(1000);
goto datinput
end;
start: { new Species option starts here }
logplt := False;
GETFUN;
xlimits: { new Range option starts here }
if logplt then CONVERT;
RANGE; PRECALC;
terms: { choose number of terms in fit }
DIMENSION;
MATRIX; { calculate coefficients }
if bombed then
if Dim = 2 then goto start { else no way out of program }
else goto terms;
CHISQUARE;
DRAWFRAME; PLOTPOINTS; PLOTCURVE; QUERY; { display curve fit }
if logplt then RESTORE
else if UpCase(ch) = 'N' then goto terms; { user dissatisfied, try again}
OUTWRITE; { record coefficients }
CWRITE
('new Data new function Species new Range in x Fudge data Quit program ');
writeln; Textcolor(14); write('your choice:'); Textcolor(7);
repeat
ch := Readkey; ch := Upcase(ch);
until ch in ['D','S','R','F','Q'];
case ch of
'D' : begin dsource := ''; goto datinput end;
'S' : goto start;
'R' : goto xlimits;
'F' : begin FUDGE; goto start end;
end;
CloseGraph;
Write(' Do you want a printed record of your last fit?');
if YN then PRINTOUT;
end.