81916684
1/20/2005
1/6
Best Linear Interpolator
bli.wpj
TBLI.FOR
bli.for
bli2.for
cbli.wpj
tbli.c
bli.c
The code bli2.for is the same as bli.for. Bli saves
temporary results. These will not be unique if a
function called by BLI also calls BLI. When this
happens, make the second one BLI2 and all will be
well. The parameters passed in common by tBli are
given in definitions\LennardJones\Lennard Jones
Potential.htm
The routine starts with the 4 red points.
Points 1 and 3 are interpolated to find a value for
point 2. Points 2 and 4 are interpolated to find a
value for point 3. The region with the largest value
of d times delta x has a point placed in the middle of
it. This continues until the maximum number of
points is reached or until the maximum
interpolation error falls below some tolerance.
The object is to use exactly N function
evaluations to get the best estimate of a function
possible with N function calls. - The assumption is
that each call is relatively time consuming.
Figure 1 Region of a curve showing linear interpolations
for points 3 and 6.
The BLI code
The code begins with a small number of
points as shown in figure 1. Each point is assigned
a relative error based on the difference between its
value and a linear interpolation between the
neighboring points. The error at the beginning and
ending points are taken to be those at the second
and second to last points. Each interval is assigned
an error based on the absolute value of the sum of
the end points of the interval times the size of the
interval to a power. The interval with the largest
error has a value of the underlying function
evaluated at its mid point. In figure 1, this would
involve placing a new point in the interval from 2 to
3. The new point changes the error estimates for
points 1, 2, new, and 3. All others remain the same.
Ide’s
bli.wpj
cbli.wpj
81916684
1/20/2005
2/6
Full debugging is an art of its own. The line
number of the error almost always is sufficient to
correct the problem.
TBLI.FOR
The FORTRAN and C ide’s superficially differ in
that the Lennard-Jones potential is accessed directly
in FORTRAN, but is coded into tbli.c.
Set the options to those shown below.
Compilation and running can check for everything.
IMPLICIT REAL*8 (A-H,O-Z) single
precision is almost never adequate for
physics
DIMENSION XI(:),YI(:),ERR(:) watcom
has extended f77 to allocatable arrays,
f90
code
requires allocatable:: XI,YI,ERR –
produces error in watcom
CHARACTER*1 ANS
will be used
to finally stop the code
EXTERNAL ALJ tells the compiler
that ALJ is a function outside this
routine
COMMON/PLJ/EPS,SIGMA named
common is used here to pass parameters to
ALJ
RMIN=1.4D0 these three lines are
described in
SIGMA=RMIN/2**(1D0/6)
..\definitions\LennardJones\Lennard Jones
Potential.htm
EPS=0.174
PRINT*,'ENTER NP,NP2'
READ(*,*)NP,NP2
IF(NP2.LT.NP)NP2=NP
ALLOCATE(XI(NP2),YI(NP2),ERR(NP2))
PRINT*,' ENTER B,E'
READ(*,*)XI(1),XI(2)
NDO=2 This uses half of the first
Np values in a uniform grid
CALL BLI(XI,YI,ERR,NP,NDO,ALJ)
IF(NP2.GT.NP)CALL
BLI(XI,YI,ERR,NP2,NP,ALJ)
NP2 can
fill in many more values
OPEN(1,FILE='BLI.OUT')
WRITE(1,'(2G14.6)')(XI(I),YI(I),I=1,NP2)
This is the results file.
CLOSE(1)
CALL FSYSTEM('GPLOT BLI.OUT')
Always make it easy to look at the data
READ(*,'(A)')ANS
END
tbli.c
#include <stdio.h>
#include <math.h>
81916684
double sigma;
1/20/2005
names outside
the function are the C version of common
double rmin=1.4,eps=0.174;
void *calloc( size_t n, size_t size );
int system(const char *command);
int bli(double xi[],double fi[],double err[],
int np,int ndo,double (*fext)(double));
the Cversion of the
Lennard-Jones potential
double alj(double xt)
{double xi,xi6,xi12,retval;
extern double sigma,eps; tells the code
that these are as defined in the file
if(xt < 0.01)xt=0.01;
xi=sigma/xt;
xi=xi*xi*xi;
xi6=xi*xi;
xi12=xi6*xi6;
retval=4*eps*(xi12-xi6);
return retval;}
void main(void)
{double *xi,*fi,*err;
char c1;
extern double sigma,rmin;
int np,np2,ndo=2,i,ibli,itest;
FILE *fp; fopen vs open fp points to a
structure with information about the file
sigma=rmin/pow(2.0,1.0/6.0);
fp=fopen("blic.out","w"); the File fp
contains information about the file
(fopen has open inside it)
if(fp ==NULL){printf(" cannot open bli.out
file\n");
scanf(" %d ",&itest);
return;}
printf("np np2 \n");
scanf("%d %d",&np,&np2);
if(np2<np)np2=np;
xi = (double *) calloc(np2, sizeof(double));
allocating arrays
fi = (double *) calloc(np2, sizeof(double));
err = (double *) calloc(np2, sizeof(double));
printf("enter ndo \n");
scanf("%d",&ndo);
if(ndo < 2){printf(" ndo must be at least 2
%d",ndo);
scanf(" %d ",&itest);
return;}
3/6
else if(ndo == 2){printf(" enter the beginning and
ending x values \n");
scanf(" %lg %lg",&xi[0],&xi[1]);}
ibli=bli(xi,fi,err,np,ndo,alj);
if(np2>np){ibli=bli(xi,fi,err,np2,np,alj);}
for(i=0;i<ibli;i++)fprintf(fp,"%14.6lg
%14.6lg\n",xi[i],fi[i]);
fclose(fp);
system("gplot blic.out"); look at the data
c1=getc(stdin);
return;}
bli.for
FUNCTION FERRC(I,XI,FI,NDO) the
interpolation routine
IMPLICIT REAL*8 (A-H,O-Z)
DIMENSION XI(NDO),FI(NDO)
C INTERPOLATES TO X(I)
IF(I.EQ.1)THEN the spacing and endif
statement make this programmable
IF(XI(3).EQ.XI(2))THEN
FERRC=ABS(FI(3)-FI(2)) might be
better set to 0
ELSE
FP=(FI(3)-FI(2))/(XI(3)-XI(2))
FINT=FI(2)+(XI(1)-XI(2))*FP
FERRC=ABS(FI(1)-FINT)
ENDIF
ELSEIF(I.EQ.NDO)THEN
IF(XI(NDO-1).EQ.XI(NDO-2))THEN
FERRC=ABS(FI(NDO)-FI(NDO-1))
ELSE
FP=(FI(NDO-1)-FI(NDO-2))/(XI(NDO-1)XI(NDO-2))
FINT=FI(NDO-1)+(XI(I)-XI(NDO-1))*FP
FERRC=ABS(FI(NDO)-FINT)
ENDIF
ELSE
IF(XI(I+1).EQ.XI(I-1))THEN
FERRC=ABS(FI(I+1)-FI(I))
ELSE
FP=(FI(I+1)-FI(I-1))/(XI(I+1)-XI(I-1))
FINT=FI(I-1)+(XI(I)-XI(I-1))*FP
FERRC=ABS(FI(I)-FINT)
ENDIF
ENDIF
RETURN
END
81916684
1/20/2005
SUBROUTINE
BLI(XI,FI,ERR,NP,NDO,FEXT) keeps the
terms in order
IMPLICIT REAL*8 (A-H,O-Z)
DIMENSION ERR(NP),XI(NP),FI(NP)
C *** NDO.EQ.2 makehalf of the point evenly
spaced
C *** FI values need to found externally for
NDO.NE.2
IF(NDO.EQ.2)THEN if NDO != to 2,
the FI’s must be defined in the calling
routine
NDO=NP/2
H=(XI(2)-XI(1))/(NDO-1)
DO I=1,NDO
XI(I)=XI(1)+(I-1)*H
FI(I)=FEXT(XI(I))
ENDDO
ENDIF
C *** ERR(I) is the interpolation error at X(I)
DO I=1,NDO
ERR(I)=FERRC(I,XI,FI,NDO)
ENDDO
C *** finding the region with the largest error
50 CONTINUE
ERRM=(ERR(1)+ERR(2))*ABS(XI(2)-XI(1))
ILE=1
DO I=2,NDO-1
ERRT=(ERR(I)+ERR(I+1))*ABS(XI(I+1)XI(I))
IF(ERRT.GT.ERRM)THEN
ERRM=ERRT
ILE=I
ENDIF
ENDDO
C *** POINT TO BE INSERTED WILL BE
ILE+1, THUS CURRENT ILE+1 BECOMES
C *** ILE+2
XI(NDO+1)=XI(NDO)
FI(NDO+1)=FI(NDO)
DO I=NDO-1,ILE+1,-1 the loop steps
down, values are moved up
XI(I+1)=XI(I)
FI(I+1)=FI(I)
ERR(I+1)=ERR(I)
ENDDO
NDO=NDO+1
IADD=ILE+1
XI(IADD)=(XI(ILE)+XI(ILE+1))/2
FI(IADD)=FEXT(XI(IADD))
C *** The error at IADD-1 depends on FI(IADD)
4/6
C *** the error at IADD+1 depends on FI(IADD)
IB=MAX(1,IADD-1)
IE=MIN(NDO,IADD+1)
DO I=IB,IE calculatesthe changed err
values
ERR(I)=FERRC(I,XI,FI,NDO)
ENDDO
IF(NP.GT.NDO)GOTO 50
RETURN
END
bli.c
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
double fabs( double x ); beware abs is an
integer in C
double ferrc(int i,double xi[],double fi[],int ndo)
{double ftemp,fp,fint;
if(i==0){
the beginning of a multiline
if is {
the triple segment USED IN
FORTRAN did not easily work
if(xi[2]==xi[1])ftemp=fabs(fi[2]-fi[1]);
else {fp=(fi[2]-fi[1])/(xi[2]-xi[1]);
fint=fi[1]+(xi[0]-xi[1])*fp;
ftemp=fabs(fi[0]-fint);}} }} ends the
two if segments
if(i==ndo-1){
if(xi[ndo-2]==xi[ndo-3])ftemp=fabs(fi[ndo-2]fi[ndo-3]); fabs is double, abs is integer
else {fp=(fi[ndo-3]-fi[ndo-2])/(xi[ndo-3]-xi[ndo2]);
fint=fi[ndo-2]+(xi[i]-xi[ndo-2])*fp;
ftemp=fabs(fi[ndo-1]-fint);}}
if(i!=0 && i!= ndo-1){ftemp=0;
if(xi[i+1]==xi[i-1])ftemp=fabs(fi[i+1]-fi[i-1]);
else {fp=(fi[i+1]-fi[i-1])/(xi[i+1]-xi[i-1]);
fint=fi[i-1]+(xi[i]-xi[i-1])*fp;
ftemp=fabs(fi[i]-fint);}}
return ftemp;}
int bli(double xi[],double fi[],double err[],int np,
int ndo, double (*fext)(double)) *fext is the
external function
{int i,ib,ie,ile,iadd;
// int itest;
double h,errt,errm;
81916684
1/20/2005
if(ndo == 2) if not the values of fi[0 to
5/6
ndo-1] need to be set in calling code
{ndo=np/2;
h=(xi[1]-xi[0])/(ndo-1);
for (i=0;i < ndo;++i)
{xi[i]=xi[0]+h*i;
fi[i]=(*fext)(xi[i]);}}
for (i=0;i < ndo;++i)err[i]=ferrc(i,xi,fi,ndo);
much more compact than in FORTRAN
f_largest_err:
errm=(err[0]+err[1])*fabs(xi[1]-xi[0]);
ile=0;
for (i=1;i<ndo-1;++i)
{errt=(err[i]+err[i+1])*fabs(xi[i+1]-xi[i]);
if(errt>errm){
errm=errt;
ile=i;}}
xi[ndo]=xi[ndo-1];
fi[ndo]=fi[ndo-1];
// move points up to //is a
Figure 2 This is the screen brought up by clicking on the
running figure.
watcomextension to ansi C
for (i=ndo-2;i>=ile+1;--i)
{xi[i+1]=xi[i];
fi[i+1]=fi[i];
err[i+1]=err[i];}
ndo=ndo+1;
iadd=ile+1;
xi[iadd]=(xi[ile]+xi[ile+1])/2;
fi[iadd]=(*fext)(xi[iadd]);
ib=iadd-1;
if(ib<0)ib=0;
ie=iadd+1;
if(ie>ndo-1)ie=ndo-1;
// udating err
for(i=ib;i<=ie;++i)err[i]=ferrc(i,xi,fi,ndo);
if(np > ndo)goto f_largest_err;
return ndo;}
making the execuatbale required recompiling both files, options, make, make
all files.
Figure 3 Initial screen from gplot
Enter the command <alt>vf
Enter m for a menu
81916684
1/20/2005
6/6
Figure 4 gplot showing the menu
Enter 9, then 1 P to get the points. The command
PrtScr will copy this to the clip board. Esc will
shrink it down to a window from which select all,
followed by copy will also copy this to the
clipboard.
Figure 5 Lennard Jones potential represented by 27
points.
The plots for bli.out and blic.out are of course the
same.
© Copyright 2026 Paperzz