2298 lines
55 KiB
C
Executable file
2298 lines
55 KiB
C
Executable file
/* quartic.c
|
|
version 54
|
|
|
|
a test of relative accuracy of various quartic routines.
|
|
|
|
use:
|
|
quartic [-a] [-c n] [-q n] [-d n]
|
|
(no parameters) : a loop through 10,000 prechosen quartic coefficients
|
|
-a : improve cubic roots (default: no iteration)
|
|
-c n : keep reading n cubic roots from standard input
|
|
(if n=0 read coefficients), terminate with 'q'.
|
|
-d n : set debug value to 'n' (default: 5)
|
|
-q n : keep reading n quartic roots from standard input
|
|
(if n=0 read coefficients), terminate with 'q'.
|
|
|
|
debug <= 1 : print cases used
|
|
|
|
method-
|
|
http://linus.socs.uts.edu.au/~don/pubs/solving.html
|
|
|
|
4 Apr 2004 bringing yacfraid notation into line with solving.html
|
|
4 Apr 2004 fixed bug in final root calculation in yacfraid
|
|
8 Mar 2004 corrected modified yacfraid algorithm
|
|
8 Mar 2004 modified yacfraid algorithm
|
|
31 Jan 2004 printing results when number of roots vary
|
|
30 Jan 2004 printing error of chosen cubic if debug<1
|
|
27 Jan 2004 seeking worst coefficients for each algorithm
|
|
27 Jan 2004 choosing best route for k in chris
|
|
26 Jan 2004 conforming variables to solving.html
|
|
26 Jan 2004 fixed bug in yacfraid for multiplicity 3
|
|
25 Jan 2004 speeding up chris
|
|
24 Jan 2004 fixed chris error (A <-> B)
|
|
23 Jan 2004 use debug<1 for diagnostics
|
|
21 Jan 2004 solve cubic in neumark, yacfraid and chris if d=0
|
|
20 Jan 2004 3 roots to cubic in chris if e1=0
|
|
19 Jan 2004 debugging Christianson routine
|
|
14 Jan 2004 adding Christianson, cut determinant in quadratic call
|
|
5 Jan 2004 improving cubic roots by Newton-Raphson iteration
|
|
23 Dec 2003 seeking snag in yacfraid
|
|
21 Dec 2003 putting diagnostic printout in yacfraid
|
|
18 Dec 2003 allowing input of equation coefficients
|
|
18 Dec 2003 recording cubic root giving least worst error
|
|
17 Dec 2003 recording cubic root giving the most quartic roots
|
|
16 Dec 2003 using the cubic root giving the most quartic roots
|
|
16 Dec 2003 trying consistency of 3 cubic roots where available
|
|
15 Dec 2003 trying all 3 cubic roots where available
|
|
13 Dec 2003 trying to fix Neumark
|
|
13 Dec 2003 cleaning up diagnostic format
|
|
12 Dec 2003 initialising n,m,po3 in cubic
|
|
12 Dec 2003 allow cubic to return 3 zero roots if p=q=r=0
|
|
10 Dec 2003 added setargs
|
|
2 Dec 2003 finding worst cases
|
|
2 Dec 2003 negating j if p>0 in cubic
|
|
1 Dec 2003 changing v in cubic from (sinsqk > doub0) to (sinsqk >= doub0)
|
|
1 Dec 2003 test changing v in cubic from po3sq+po3sq to doub2*po3sq
|
|
30 Nov 2003 counting cases in all solving routines
|
|
29 Nov 2003 testing wsq >= doub0
|
|
29 Nov 2003 mult by doub2 for v in cubic
|
|
29 Nov 2003 cut po3cu from cubic
|
|
29 Nov 2003 better quadratic
|
|
29 Nov 2003 count agreements
|
|
17 Nov 2003 count special cases
|
|
16 Nov 2003 option of loop or read coefficients from input
|
|
15 Nov 2003 fixed cubic() bug
|
|
11 Nov 2003 added Brown and Yacoub & Fraidenraich's algorithms
|
|
21 Jan 1989 quartic selecting Descartes, Ferrari, or Neumark algorithms
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
"Solving Quartics and Cubics for Graphics", D. Herbison-Evans,
|
|
Graphics Gems V (ed.: A. Paeth) Academic Press (Chesnut Hill), pp. 3-15 (1995).
|
|
|
|
"Solving Quartics and Cubics for Graphics", D. Herbison-Evans,
|
|
Research Report CS-86-56, Department of Computer Science, University of Waterloo (1986)
|
|
|
|
"Caterpillars and the Inaccurate Solution of Cubic and Quartic Equations",
|
|
D. Herbison-Evans, Australian Computer Science Communications,
|
|
Vol. 5, No. 1, pp. 80-90 (1983)
|
|
|
|
subroutines:
|
|
setcns - set constants
|
|
setargs - determine which equations to test
|
|
looptest - test 10000 coefficient combinations
|
|
cases - print statistics
|
|
docoeffs - read coefficients of a particular equation to solve
|
|
cubictest - test cubic solutions
|
|
quartictest - test quartic solutions
|
|
compare - check accuracy of results
|
|
errors - find errors in a set of roots
|
|
acos3 - find arcos(x/3)
|
|
curoot - find cube root
|
|
quadratic - solve a quadratic
|
|
cubic - solve a cubic
|
|
cubnewton - improve cubic roots by iteration
|
|
quartic - solve a quartic
|
|
descartes - use Descartes' algorithm to solve a quartic
|
|
ferrari - use Ferrari's algorithm to solve a quartic
|
|
neumark - use Neumark's algorithm to solve a quartic
|
|
yacfraid - use Yacoub & Fraidenraich's algorithm to solve a quartic
|
|
chris - use Christianson's algorithm to solve a quartic
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#define NCASES 40
|
|
|
|
double a,b,c,d; /* quartic coefficients */
|
|
double cc[4],cd[4],cf[4],cn[4],cy[4];
|
|
double d3o8,d3o256; /* double precision constants */
|
|
double doub0;
|
|
double doub1,doub2;
|
|
double doub3,doub4;
|
|
double doub5,doub6;
|
|
double doub8,doub9,doub12;
|
|
double doub16,doub24;
|
|
double doub27,doub64;
|
|
double doubmax; /* approx square root of max double number */
|
|
double doubmin; /* smallest double number */
|
|
double doubtol; /* tolerance of double numbers */
|
|
double errq;
|
|
double inv2,inv3,inv4;
|
|
double inv8,inv16,inv32,inv64,inv128;
|
|
double maxc,maxd,maxf,maxn,maxy;
|
|
double p,q,r; /* cubic coefficients */
|
|
double qrts[4][3]; /* quartic roots for each cubic root */
|
|
double rt3; /* square root of 3 */
|
|
double rtsc[4],rtsd[4],rtsf[4],rtsn[4],rtsq[4],rtsy[4]; /* roots given by each algorithm */
|
|
double rterc[4],rterd[4],rterf[4],rtern[4],rterq[4],rtery[4]; /* errors of roots */
|
|
double worstc,worstd,worstf,worstn,worsty; /* worst error for each algotithm */
|
|
double worst3[3]; /* worst error for a given cubic root */
|
|
double x0,x1,x2,x3;
|
|
|
|
int agr,dis,zer;
|
|
int agreecd,agreecf,agreecn,agreecy;
|
|
int agreedf,agreedn,agreedy;
|
|
int agreefn,agreefy,agreeny;
|
|
int debug; /* <1 for lots of diagnostics, >5 for none */
|
|
int docubic,doquartic;
|
|
int iterate;
|
|
int j3;
|
|
int n1,n2,n3,n4[3];
|
|
int n,nc,nd,nf,nn,ny;
|
|
int nrtsc,nrtsd,nrtsf,nrtsn,nrtsq,nrtsy;
|
|
int nt3,nt2,nt2sq,nden,nm4,ndet1,ndet2,ndet3,ndet4,ndet5,nn;
|
|
int nqud[NCASES];
|
|
int ncub[NCASES];
|
|
int nchr[NCASES];
|
|
int ndes[NCASES];
|
|
int nfer[NCASES];
|
|
int nneu[NCASES];
|
|
int nyac[NCASES];
|
|
int nzc,nzd,nzf,nzn,nzy;
|
|
int zerodf,zerodn,zerody,zerofn,zerofy,zerony;
|
|
int zerodfn,zerodfy,zerodny,zerofny;
|
|
int tot;
|
|
|
|
double exp(),log(),sqrt(),cos(),acos(),fabs(),errors();
|
|
int cubic() ;
|
|
int descartes(),ferrari(),neumark(),yacfraid();
|
|
|
|
/***********************************/
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
double fabs();
|
|
|
|
printf("quartic version 54\n");
|
|
debug = 5;
|
|
setcns();
|
|
setargs(argc,argv);
|
|
|
|
more: if (argc > 1)
|
|
{
|
|
docoeffs();
|
|
if ((fabs(x0)+fabs(x1)+fabs(x2)+fabs(x3)) != doub0)
|
|
goto more;
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
looptest();
|
|
exit(0);
|
|
}
|
|
} /* main */
|
|
/****************************************/
|
|
|
|
setcns()
|
|
/*
|
|
set up constants.
|
|
|
|
called by main, quartictest.
|
|
*/
|
|
{
|
|
int j;
|
|
|
|
doub0 = (double)0;
|
|
doub1 = (double)1;
|
|
doub2 = (double)2;
|
|
doub3 = (double)3;
|
|
doub4 = (double)4;
|
|
doub5 = (double)5;
|
|
doub6 = (double)6;
|
|
doub8 = (double)8;
|
|
doub9 = (double)9;
|
|
doub12 = (double)12;
|
|
doub16 = (double)16;
|
|
doub24 = (double)24;
|
|
doub27 = (double)27;
|
|
doub64 = (double)64;
|
|
inv2 = doub1/doub2;
|
|
inv3 = doub1/doub3;
|
|
inv4 = doub1/doub4;
|
|
inv8 = doub1/doub8;
|
|
inv16 = doub1/doub16;
|
|
inv32 = doub1/(double)32;
|
|
inv64 = doub1/doub64;
|
|
inv128 = doub1/(double)128;
|
|
d3o8 = doub3/doub8;
|
|
d3o256 = doub3/(double)256;
|
|
rt3 = sqrt(doub3);
|
|
|
|
doubtol = doub1;
|
|
for (j = 1; doub1+doubtol > doub1; ++ j)
|
|
{
|
|
doubtol *= inv2;
|
|
}
|
|
doubtol = sqrt(doubtol);
|
|
|
|
doubmin = inv2;
|
|
for (j = 1; j <= 100; ++ j)
|
|
{
|
|
doubmin=doubmin*doubmin;
|
|
if ((doubmin*doubmin) <= (doubmin*doubmin*inv2))
|
|
break;
|
|
}
|
|
doubmax=doub1/sqrt(doub2*doubmin);
|
|
|
|
} /* setcns */
|
|
/***********************************/
|
|
|
|
setargs(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
/*
|
|
determine whether to do looptest or just individual equation
|
|
|
|
10 Dec 2003 Don Herbison-Evans
|
|
|
|
called by main
|
|
*/
|
|
{
|
|
int j;
|
|
|
|
docubic = FALSE;
|
|
doquartic = FALSE;
|
|
iterate = FALSE;
|
|
for (j = 1; j < argc; ++j)
|
|
{
|
|
if (argv[j][0] == '-')
|
|
{
|
|
if (argv[j][1] == 'a')
|
|
{
|
|
iterate = TRUE;
|
|
printf("iterate cubics\n");
|
|
}
|
|
else
|
|
if (argv[j][1] == 'c')
|
|
{
|
|
docubic = TRUE;
|
|
sscanf(argv[++j],"%d",&n);
|
|
printf("do cubic %d\n",n);
|
|
}
|
|
else
|
|
if (argv[j][1] == 'q')
|
|
{
|
|
doquartic = TRUE;
|
|
sscanf(argv[++j],"%d",&n);
|
|
printf("do quartic %d\n",n);
|
|
}
|
|
else
|
|
if (argv[j][1] == 'd')
|
|
{
|
|
sscanf(argv[++j],"%d",&debug);
|
|
printf("debug %d\n",debug);
|
|
}
|
|
}
|
|
}
|
|
} /* setargs */
|
|
/********************************************************/
|
|
|
|
looptest()
|
|
/*
|
|
loop through a range of coefficient values
|
|
comparing the algorithms
|
|
|
|
called by main.
|
|
calls compare.
|
|
*/
|
|
{
|
|
double ten4,ten8;
|
|
double v[10];
|
|
int j,k,l,m;
|
|
|
|
printf("quartic loop test\n");
|
|
nc = 0;
|
|
nd = 0;
|
|
nf = 0;
|
|
nn = 0;
|
|
ny = 0;
|
|
maxc = doub0;
|
|
maxd = doub0;
|
|
maxf = doub0;
|
|
maxn = doub0;
|
|
maxy = doub0;
|
|
tot = 0;
|
|
zer = 0;
|
|
agr = 0;
|
|
dis = 0;
|
|
agreecd = 0;
|
|
agreecf = 0;
|
|
agreecn = 0;
|
|
agreecy = 0;
|
|
agreedf = 0;
|
|
agreedn = 0;
|
|
agreedy = 0;
|
|
agreefn = 0;
|
|
agreefy = 0;
|
|
agreeny = 0;
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
nqud[j] = 0;
|
|
ncub[j] = 0;
|
|
ndes[j] = 0;
|
|
nfer[j] = 0;
|
|
nneu[j] = 0;
|
|
nyac[j] = 0;
|
|
}
|
|
ten4 = (double)10000;
|
|
ten8 = ten4*ten4;
|
|
j = 0;
|
|
for (a = ten8; a > inv2/ten8; a /= ten4)
|
|
{
|
|
v[j] = a;
|
|
++j;
|
|
}
|
|
for (j = 0; j < 5; ++j)
|
|
v[j+5] = -v[j];
|
|
for (j = 0; j < 10; ++j)
|
|
{
|
|
a = v[j];
|
|
for (k = 0; k < 10; ++k)
|
|
{
|
|
b = v[k];
|
|
for (l = 0; l < 10; ++l)
|
|
{
|
|
c = v[l];
|
|
for (m = 0; m < 10; ++m)
|
|
{
|
|
d = v[m];
|
|
compare();
|
|
} /* for m */
|
|
} /* for l */
|
|
} /* for k */
|
|
} /* for j */
|
|
printf("total cases: %d\n",
|
|
tot);
|
|
printf("number of real roots: five agree %d, disagree %d\n",
|
|
agr,dis);
|
|
printf("two agree: cd %d, cf %d, cn %d, cy %d\n",
|
|
agreecd,agreecf,agreecn,agreecy);
|
|
printf(" df %d, dn %d, dy %d, fn %d, fy %d, ny %d\n",
|
|
agreedf,agreedn,agreedy,agreefn,agreefy,agreeny);
|
|
printf("5 agree on no real roots: %d\n",
|
|
zer);
|
|
printf("no real roots: chris %d, desc %d, ferr %d, neum %d, yacf %d\n",
|
|
nzc,nzd,nzf,nzn,nzy);
|
|
printf("Christianson : best %d, worst %g %g %g %g, error %g\n",
|
|
nc,cc[0],cc[1],cc[2],cc[3],maxc);
|
|
printf("Descartes : best %d, worst %g %g %g %g, error %g\n",
|
|
nd,cd[0],cd[1],cd[2],cd[3],maxd);
|
|
printf("Ferrari : best %d, worst %g %g %g %g, error %g\n",
|
|
nf,cf[0],cf[1],cf[2],cf[3],maxf);
|
|
printf("Neumark : best %d, worst %g %g %g %g, error %g\n",
|
|
nn,cn[0],cn[1],cn[2],cn[3],maxn);
|
|
printf("Yacoub : best %d, worst %g %g %g %g, error %g\n",
|
|
ny,cy[0],cy[1],cy[2],cy[3],maxy);
|
|
cases();
|
|
} /* looptest */
|
|
/********************************************/
|
|
|
|
cases()
|
|
/*
|
|
print statistics
|
|
|
|
2 Dec 2003 Don Herbison-Evans
|
|
|
|
called by looptest, quartictest.
|
|
*/
|
|
{
|
|
int j;
|
|
|
|
printf("quadratic cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,nqud[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("cubic cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,ncub[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("descartes cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,ndes[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("ferrari cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,nfer[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("neumark cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,nneu[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("yacfraid cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,nyac[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
printf("chris cases:\n");
|
|
for (j = 0; j < NCASES; ++j)
|
|
{
|
|
printf(" %2d %d,",j,nchr[j]);
|
|
if (j%5 == 4) printf("\n");
|
|
}
|
|
printf("\n");
|
|
|
|
} /* cases */
|
|
/************************************/
|
|
|
|
docoeffs()
|
|
/*
|
|
read a set of coefficients from standard input
|
|
and compare results of the different algorithms.
|
|
|
|
16 Nov 2003 Don Herbison-Evans
|
|
|
|
called by main.
|
|
calls cubictest, quartictest.
|
|
*/
|
|
{
|
|
char buf[256];
|
|
int ix0,ix1,ix2,ix3;
|
|
int descartes(),ferrari(),neumark(),yacfraid(),chris();
|
|
float fa,fb,fc,fd;
|
|
float fp,fq,fr;
|
|
double fabs();
|
|
|
|
printf("docoeffsa %d\n",n);
|
|
x0 = doub0;
|
|
x1 = doub0;
|
|
x2 = doub0;
|
|
x3 = doub0;
|
|
if (NULL != gets(buf))
|
|
{
|
|
if (buf[0] == 'q')
|
|
exit(0);
|
|
if (n == 0)
|
|
{
|
|
x0 = doub1;
|
|
if (docubic == TRUE)
|
|
{
|
|
sscanf(buf,"%g %g %g",&fp,&fq,&fr);
|
|
p = (double)fp;
|
|
q = (double)fq;
|
|
r = (double)fr;
|
|
}
|
|
else
|
|
{
|
|
sscanf(buf,"%g %g %g %g",&fa,&fb,&fc,&fd);
|
|
printf("\n%g %g %g %g\n",fa,fb,fc,fd);
|
|
a = (double)fa;
|
|
b = (double)fb;
|
|
c = (double)fc;
|
|
d = (double)fd;
|
|
printf("\n%g %g %g %g\n",a,b,c,d);
|
|
}
|
|
}
|
|
else
|
|
if (n == 1)
|
|
{
|
|
sscanf(buf,"%d\n",&ix0);
|
|
x0 = (double)ix0;
|
|
}
|
|
else
|
|
if (n == 2)
|
|
{
|
|
sscanf(buf,"%d %d\n",&ix0,&ix1);
|
|
x0 = (double)ix0;
|
|
x1 = (double)ix1;
|
|
}
|
|
else
|
|
if (n == 3)
|
|
{
|
|
sscanf(buf,"%d %d %d\n",&ix0,&ix1,&ix2);
|
|
x0 = (double)ix0;
|
|
x1 = (double)ix1;
|
|
x2 = (double)ix2;
|
|
}
|
|
else
|
|
if (n == 4)
|
|
{
|
|
sscanf(buf,"%d %d %d %d\n",&ix0,&ix1,&ix2,&ix3);
|
|
x0 = (double)ix0;
|
|
x1 = (double)ix1;
|
|
x2 = (double)ix2;
|
|
x3 = (double)ix3;
|
|
}
|
|
}
|
|
if ((fabs(x0)+fabs(x1)+fabs(x2)+fabs(x3)) != doub0)
|
|
{
|
|
if (docubic == TRUE) cubictest();
|
|
if (doquartic == TRUE) quartictest();
|
|
}
|
|
} /* docoeffs */
|
|
/*****************************************/
|
|
|
|
cubictest()
|
|
/*
|
|
called by docoeffs.
|
|
*/
|
|
{
|
|
int j;
|
|
int nrtsc;
|
|
double rtsc[4];
|
|
|
|
if (n == 1)
|
|
{
|
|
p = -x0;
|
|
q = doub1;
|
|
r = -x0;
|
|
}
|
|
else
|
|
if (n == 3)
|
|
{
|
|
p = -(x0+x1+x2);
|
|
q = x0*x1 + x0*x2 + x1*x2;
|
|
r = -x0*x1*x2;
|
|
}
|
|
printf("\ncubic test: %g %g %g\n",
|
|
x0,x1,x2);
|
|
printf(" x^3 + %gx^2 + %gx + %g\n",
|
|
p,q,r);
|
|
nrtsc = cubic(p,q,r,rtsc);
|
|
printf("%d roots\n",nrtsc);
|
|
for (j = 0; j < nrtsc; ++j)
|
|
printf("%g ",rtsc[j]);
|
|
printf("\n");
|
|
} /* cubictest */
|
|
/******************************************/
|
|
|
|
quartictest()
|
|
/*
|
|
called by docoeffs.
|
|
calls descartes, ferrari, neumark, yacfraid,
|
|
errors, cases, setcns.
|
|
*/
|
|
{
|
|
int j;
|
|
|
|
printf("quartictest %d\n",n);
|
|
if (n == 4)
|
|
{
|
|
a = -(x0 + x1 + x2 + x3);
|
|
b = x0*x1 + x0*x2 + x0*x3 + x1*x2 + x1*x3 + x2*x3;
|
|
c = -(x0*x1*x2 + x0*x1*x3 + x0*x2*x3 + x1*x2*x3);
|
|
d = x0*x1*x2*x3;
|
|
}
|
|
else
|
|
if (n == 2)
|
|
{
|
|
a = -(x0 + x1);
|
|
b = x0*x1;
|
|
c = a;
|
|
d = b;
|
|
}
|
|
printf("\nquartic test: %g %g %g %g\n",
|
|
x0,x1,x2,x3);
|
|
printf("x^4 + %gx^3 + %gx^2 + %gx + %g\n",
|
|
a,b,c,d);
|
|
|
|
setcns();
|
|
printf("\nDescartes\n");
|
|
nrtsd = descartes(a,b,c,d,rtsd);
|
|
worstd = errors(a,b,c,d,rtsd,rterd,nrtsd);
|
|
if (nrtsd > 0)
|
|
for (j = 0; j < nrtsd; ++j)
|
|
printf(" %g %g\n",rtsd[j],rterd[j]);
|
|
else
|
|
printf("no real roots found\n");
|
|
|
|
setcns();
|
|
printf("\nFerrari\n");
|
|
nrtsf = ferrari(a,b,c,d,rtsf);
|
|
worstf = errors(a,b,c,d,rtsf,rterf,nrtsf);
|
|
if (nrtsf > 0)
|
|
for (j = 0; j < nrtsf; ++j)
|
|
printf(" %g %g\n",rtsf[j],rterf[j]);
|
|
else
|
|
printf("no real roots found\n");
|
|
|
|
setcns();
|
|
printf("\nNeumark\n");
|
|
nrtsn = neumark(a,b,c,d,rtsn);
|
|
worstn = errors(a,b,c,d,rtsn,rtern,nrtsn);
|
|
if (nrtsn > 0)
|
|
for (j = 0; j < nrtsn; ++j)
|
|
printf(" %g %g\n",rtsn[j],rtern[j]);
|
|
else
|
|
printf("no real roots found\n");
|
|
|
|
setcns();
|
|
printf("\nYacoub and Fraidenraich\n");
|
|
nrtsy = yacfraid(a,b,c,d,rtsy);
|
|
worsty = errors(a,b,c,d,rtsy,rtery,nrtsy);
|
|
if (nrtsy > 0)
|
|
for (j = 0; j < nrtsy; ++j)
|
|
printf(" %g %g\n",rtsy[j],rtery[j]);
|
|
else
|
|
printf("no real roots found\n");
|
|
|
|
setcns();
|
|
printf("\nChristianson\n");
|
|
nrtsc = chris(a,b,c,d,rtsc);
|
|
worstc = errors(a,b,c,d,rtsc,rterc,nrtsc);
|
|
if (nrtsc > 0)
|
|
for (j = 0; j < nrtsc; ++j)
|
|
printf(" %g %g\n",rtsc[j],rterc[j]);
|
|
else
|
|
printf("no real roots found\n");
|
|
printf("\n x^4 + %gx^3 + %gx^2 + %gx + %g\n",
|
|
a,b,c,d);
|
|
if (debug < 2) cases();
|
|
} /* quartictest */
|
|
/***************************************/
|
|
|
|
compare()
|
|
/*
|
|
called by looptest.
|
|
calls errors, descartes, ferrari, neumark, yacfraid, chris.
|
|
*/
|
|
{
|
|
int n;
|
|
double errors();
|
|
|
|
++tot;
|
|
nrtsd = descartes(a,b,c,d,rtsd);
|
|
worstd = errors(a,b,c,d,rtsd,rterd,nrtsd);
|
|
nrtsf = ferrari(a,b,c,d,rtsf);
|
|
worstf = errors(a,b,c,d,rtsf,rterf,nrtsf);
|
|
nrtsn = neumark(a,b,c,d,rtsn,worstn);
|
|
worstn = errors(a,b,c,d,rtsn,rtern,nrtsn);
|
|
nrtsy = yacfraid(a,b,c,d,rtsy);
|
|
worsty = errors(a,b,c,d,rtsy,rtery,nrtsy);
|
|
nrtsc = chris(a,b,c,d,rtsc);
|
|
worstc = errors(a,b,c,d,rtsc,rterc,nrtsc);
|
|
|
|
if (nrtsd == 0) ++nzd;
|
|
if (nrtsf == 0) ++nzf;
|
|
if (nrtsn == 0) ++nzn;
|
|
if (nrtsy == 0) ++nzy;
|
|
if (nrtsc == 0) ++nzc;
|
|
|
|
if (nrtsc == nrtsd) ++agreecd;
|
|
if (nrtsc == nrtsf) ++agreecf;
|
|
if (nrtsc == nrtsn) ++agreecn;
|
|
if (nrtsc == nrtsy) ++agreecy;
|
|
if (nrtsd == nrtsf) ++agreedf;
|
|
if (nrtsd == nrtsn) ++agreedn;
|
|
if (nrtsd == nrtsy) ++agreedy;
|
|
if (nrtsf == nrtsn) ++agreefn;
|
|
if (nrtsf == nrtsy) ++agreefy;
|
|
if (nrtsn == nrtsy) ++agreeny;
|
|
|
|
if ((nrtsc == nrtsd) && (nrtsc == nrtsf)
|
|
&& (nrtsc == nrtsn) && (nrtsc == nrtsy))
|
|
{
|
|
if (nrtsf == 0) ++zer;
|
|
++agr;
|
|
}
|
|
else
|
|
++dis;
|
|
|
|
|
|
if ((nrtsc == nrtsd) && (nrtsc == nrtsf)
|
|
&& (nrtsc == nrtsn) && (nrtsc == nrtsy) && (nrtsc != 0))
|
|
{
|
|
if ((worstd < worstf) && (worstd < worstn)
|
|
&& (worstd < worsty) && (worstd < worstc)) ++nd;
|
|
|
|
if ((worstf < worstd) && (worstf < worstn)
|
|
&& (worstf < worsty) && (worstf < worstc)) ++nf;
|
|
|
|
if ((worstn < worstd) && (worstn < worstf)
|
|
&& (worstn < worsty) && (worstn < worstc)) ++nn;
|
|
|
|
if ((worsty < worstd) && (worsty < worstf)
|
|
&& (worsty < worstn) && (worsty < worstc)) ++ny;
|
|
|
|
if ((worstc < worstd) && (worstc < worstf)
|
|
&& (worstc < worstn) && (worstc < worsty)) ++nc;
|
|
|
|
if (maxd < worstd)
|
|
{
|
|
maxd = worstd;
|
|
cd[0]=a; cd[1]=b; cd[2]=c; cd[3]=d;
|
|
}
|
|
if (maxf < worstf)
|
|
{
|
|
maxf = worstf;
|
|
cf[0]=a; cf[1]=b; cf[2]=c; cf[3]=d;
|
|
}
|
|
if (maxn < worstn)
|
|
{
|
|
maxn = worstn;
|
|
cn[0]=a; cn[1]=b; cn[2]=c; cn[3]=d;
|
|
}
|
|
if (maxy < worsty)
|
|
{
|
|
maxy = worsty;
|
|
cy[0]=a; cy[1]=b; cy[2]=c; cy[3]=d;
|
|
}
|
|
if (maxc < worstc)
|
|
{
|
|
maxc = worstc;
|
|
cc[0]=a; cc[1]=b; cc[2]=c; cc[3]=d;
|
|
}
|
|
|
|
} /* nrts agree */
|
|
} /* compare */
|
|
/****************************************************/
|
|
|
|
double errors(a,b,c,d,rts,rterr,nrts)
|
|
double a,b,c,d,rts[4],rterr[4];
|
|
int nrts;
|
|
/*
|
|
find the errors
|
|
|
|
called by quartictest, docoeff, compare,
|
|
chris, descartes, ferrari, neumark, yacfraid.
|
|
*/
|
|
{
|
|
int k;
|
|
double deriv,test,worst;
|
|
double fabs(),sqrt(),curoot();
|
|
|
|
worst = doubmax;
|
|
if (nrts > 0)
|
|
{
|
|
worst = doub0;
|
|
for ( k = 0 ; k < nrts ; ++ k )
|
|
{
|
|
test = (((rts[k]+a)*rts[k]+b)*rts[k]+c)*rts[k]+d;
|
|
if (test == doub0) rterr[k] = doub0;
|
|
else
|
|
{
|
|
deriv =
|
|
((doub4*rts[k]+doub3*a)*rts[k]+doub2*b)*rts[k]+c;
|
|
if (deriv != doub0)
|
|
rterr[k] = fabs(test/deriv);
|
|
else
|
|
{
|
|
deriv = (doub12*rts[k]+doub6*a)*rts[k]+doub2*b;
|
|
if (deriv != doub0)
|
|
rterr[k] = sqrt(fabs(test/deriv));
|
|
else
|
|
{
|
|
deriv = doub24*rts[k]+doub6*a;
|
|
if (deriv != doub0)
|
|
rterr[k] = curoot(fabs(test/deriv));
|
|
else
|
|
rterr[k] = sqrt(sqrt(fabs(test)/doub24));
|
|
}
|
|
}
|
|
}
|
|
if (rts[k] != doub0) rterr[k] /= rts[k];
|
|
if (rterr[k] < doub0) rterr[k] = -rterr[k];
|
|
if (rterr[k] > worst) worst = rterr[k];
|
|
}
|
|
}
|
|
return(worst);
|
|
} /* errors */
|
|
/**********************************************/
|
|
|
|
double acos3(x)
|
|
double x ;
|
|
/*
|
|
find cos(acos(x)/3)
|
|
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
called by cubic .
|
|
*/
|
|
{
|
|
double value;
|
|
double acos(),cos();
|
|
|
|
value = cos(acos(x)*inv3);
|
|
return(value);
|
|
} /* acos3 */
|
|
/***************************************/
|
|
|
|
double curoot(x)
|
|
double x ;
|
|
/*
|
|
find cube root of x.
|
|
|
|
30 Jan 1989 Don Herbison-Evans
|
|
|
|
called by cubic .
|
|
*/
|
|
{
|
|
double exp(),log();
|
|
double value;
|
|
double absx;
|
|
int neg;
|
|
|
|
neg = 0;
|
|
absx = x;
|
|
if (x < doub0)
|
|
{
|
|
absx = -x;
|
|
neg = 1;
|
|
}
|
|
if (absx != doub0) value = exp( log(absx)*inv3 );
|
|
else value = doub0;
|
|
if (neg == 1) value = -value;
|
|
return(value);
|
|
} /* curoot */
|
|
/****************************************************/
|
|
|
|
int quadratic(b,c,rts)
|
|
double b,c,rts[4];
|
|
/*
|
|
solve the quadratic equation -
|
|
|
|
x**2 + b*x + c = 0
|
|
|
|
14 Jan 2004 cut determinant in quadratic call
|
|
29 Nov 2003 improved
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
called by cubic,quartic,chris,descartes,ferrari,neumark.
|
|
*/
|
|
{
|
|
int j,nquad;
|
|
double dis,rtdis ;
|
|
double ans[2] ;
|
|
|
|
dis = b*b - doub4*c;
|
|
rts[0] = doub0;
|
|
rts[1] = doub0;
|
|
if (b == doub0)
|
|
{
|
|
if (c == doub0)
|
|
{
|
|
nquad = 2;
|
|
++nqud[0];
|
|
}
|
|
else
|
|
{
|
|
if (c < doub0)
|
|
{
|
|
nquad = 2;
|
|
rts[0] = sqrt(-c);
|
|
rts[1] = -rts[0];
|
|
++nqud[1];
|
|
}
|
|
else
|
|
{
|
|
nquad = 0;
|
|
++nqud[2];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (c == doub0)
|
|
{
|
|
nquad = 2;
|
|
rts[0] = -b;
|
|
++nqud[3];
|
|
}
|
|
else
|
|
if (dis >= doub0)
|
|
{
|
|
nquad = 2 ;
|
|
rtdis = sqrt(dis);
|
|
if (b > doub0)
|
|
{
|
|
rts[0] = ( -b - rtdis)*inv2;
|
|
++nqud[4];
|
|
}
|
|
else
|
|
{
|
|
rts[0] = ( -b + rtdis)*inv2;
|
|
++nqud[5];
|
|
}
|
|
if (rts[0] == doub0)
|
|
{
|
|
rts[1] = -b;
|
|
++nqud[6];
|
|
}
|
|
else
|
|
{
|
|
rts[1] = c/rts[0];
|
|
++nqud[7];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nquad = 0;
|
|
++nqud[8];
|
|
}
|
|
if (debug < 1)
|
|
{
|
|
printf("quad b %g c %g dis %g\n",
|
|
b,c,dis);
|
|
printf(" %d %g %g\n",
|
|
nquad,rts[0],rts[1]);
|
|
}
|
|
return(nquad);
|
|
} /* quadratic */
|
|
/**************************************************/
|
|
|
|
int cubic(p,q,r,v3)
|
|
double p,q,r,v3[4];
|
|
/*
|
|
find the real roots of the cubic -
|
|
x**3 + p*x**2 + q*x + r = 0
|
|
|
|
12 Dec 2003 initialising n,m,po3
|
|
12 Dec 2003 allow return of 3 zero roots if p=q=r=0
|
|
2 Dec 2003 negating j if p>0
|
|
1 Dec 2003 changing v from (sinsqk > doub0) to (sinsqk >= doub0)
|
|
1 Dec 2003 test changing v from po3sq+po3sq to doub2*po3sq
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
input parameters -
|
|
p,q,r - coeffs of cubic equation.
|
|
|
|
output-
|
|
the number of real roots
|
|
v3 - the roots.
|
|
|
|
global constants -
|
|
rt3 - sqrt(3)
|
|
inv3 - 1/3
|
|
doubmax - square root of largest number held by machine
|
|
|
|
method -
|
|
see D.E. Littlewood, "A University Algebra" pp.173 - 6
|
|
|
|
15 Nov 2003 output 3 real roots: Don Herbison-Evans
|
|
Apr 1981 initial version: Charles Prineas
|
|
|
|
called by cubictest,quartic,chris,yacfraid,neumark,descartes,ferrari.
|
|
calls quadratic,acos3,curoot,cubnewton.
|
|
*/
|
|
{
|
|
int j,n3;
|
|
double po3,po3sq,qo3,po3q;
|
|
double uo3,u2o3,uo3sq4,uo3cu4;
|
|
double v,vsq,wsq;
|
|
double m1,m2,mcube;
|
|
double muo3,s,scube,t,cosk,rt3sink,sinsqk;
|
|
double ans;
|
|
double curoot();
|
|
double acos3();
|
|
double sqrt(),fabs();
|
|
int quadratic();
|
|
|
|
m1=doub0; m2=doub0; po3=doub0;
|
|
v=doub0; uo3=doub0; cosk=doub0;
|
|
if (r == doub0)
|
|
{
|
|
++ncub[0];
|
|
n3 = quadratic(p,q,v3);
|
|
v3[n3++] = doub0;
|
|
goto done;
|
|
}
|
|
if ((p == doub0) && (q == doub0))
|
|
{
|
|
++ncub[1];
|
|
v3[0] = curoot(-r);
|
|
v3[1] = v3[0];
|
|
v3[2] = v3[0];
|
|
n3 = 3;
|
|
goto done;
|
|
}
|
|
n3 = 1;
|
|
if ((p > doubmax) || (p < -doubmax))
|
|
{
|
|
v3[0] = -p;
|
|
++ncub[2];
|
|
goto done;
|
|
}
|
|
if ((q > doubmax) || (q < -doubmax))
|
|
{
|
|
if (q > doub0)
|
|
{
|
|
v3[0] = -r/q;
|
|
++ncub[3];
|
|
goto done;
|
|
}
|
|
else
|
|
if (q < doub0)
|
|
{
|
|
v3[0] = -sqrt(-q);
|
|
++ncub[4];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
v3[0] = doub0;
|
|
++ncub[5];
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
if ((r > doubmax)|| (r < -doubmax))
|
|
{
|
|
v3[0] = -curoot(r);
|
|
++ncub[6];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
po3 = p*inv3;
|
|
po3q = po3*q;
|
|
po3sq = po3*po3;
|
|
if (po3sq > doubmax)
|
|
{
|
|
v3[0] = -p;
|
|
++ncub[7];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
v = r + po3*(po3sq+po3sq - q);
|
|
if ((v > doubmax) || (v < -doubmax))
|
|
{
|
|
v3[0] = -p;
|
|
++ncub[8];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
vsq = v*v;
|
|
qo3 = q*inv3;
|
|
uo3 = qo3 - po3sq;
|
|
u2o3 = uo3 + uo3;
|
|
if ((u2o3 > doubmax) || (u2o3 < -doubmax))
|
|
{
|
|
if (p == doub0)
|
|
{
|
|
if (q > doub0)
|
|
{
|
|
v3[0] = -r/q;
|
|
++ncub[9];
|
|
goto done;
|
|
}
|
|
else
|
|
if (q < doub0)
|
|
{
|
|
v3[0] = -sqrt(-q);
|
|
++ncub[10];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
v3[0] = doub0;
|
|
++ncub[11];
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v3[0] = -q/p;
|
|
++ncub[12];
|
|
goto done;
|
|
}
|
|
}
|
|
uo3sq4 = u2o3*u2o3;
|
|
if (uo3sq4 > doubmax)
|
|
{
|
|
if (p == doub0)
|
|
{
|
|
if (q > doub0)
|
|
{
|
|
v3[0] = -r/q;
|
|
++ncub[13];
|
|
goto done;
|
|
}
|
|
else
|
|
if (q < doub0)
|
|
{
|
|
v3[0] = -sqrt(-q);
|
|
++ncub[14];
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
v3[0] = doub0;
|
|
++ncub[15];
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v3[0] = -q/p;
|
|
++ncub[16];
|
|
goto done;
|
|
}
|
|
}
|
|
uo3cu4 = uo3sq4*uo3;
|
|
wsq = uo3cu4 + vsq;
|
|
if (wsq > doub0)
|
|
{
|
|
/*
|
|
cubic has one real root -
|
|
*/
|
|
if (v <= doub0)
|
|
{
|
|
mcube = ( -v + sqrt(wsq))*inv2;
|
|
++ncub[17];
|
|
}
|
|
else
|
|
{
|
|
mcube = ( -v - sqrt(wsq))*inv2;
|
|
++ncub[18];
|
|
}
|
|
m1 = curoot(mcube);
|
|
if (m1 != doub0)
|
|
{
|
|
m2 = -uo3/m1;
|
|
++ncub[19];
|
|
}
|
|
else
|
|
{
|
|
m2 = doub0;
|
|
++ncub[20];
|
|
}
|
|
v3[0] = m1 + m2 - po3;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
cubic has three real roots -
|
|
*/
|
|
if (uo3 < doub0)
|
|
{
|
|
muo3 = -uo3;
|
|
if (muo3 > doub0)
|
|
{
|
|
s = sqrt(muo3);
|
|
++ncub[21];
|
|
if (p > doub0)
|
|
{
|
|
s = -s;
|
|
++ncub[22];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s = doub0;
|
|
++ncub[23];
|
|
}
|
|
scube = s*muo3;
|
|
if (scube == doub0)
|
|
{
|
|
v3[0] = m1 + m2 - po3;
|
|
n3 = 1;
|
|
++ncub[24];
|
|
}
|
|
else
|
|
{
|
|
t = -v/(scube+scube);
|
|
cosk = acos3(t);
|
|
v3[0] = (s+s)*cosk - po3;
|
|
n3 = 1 ;
|
|
sinsqk = doub1 - cosk*cosk;
|
|
if (sinsqk >= doub0)
|
|
{
|
|
rt3sink = rt3*sqrt(sinsqk);
|
|
v3[1] = s*(-cosk + rt3sink) - po3;
|
|
v3[2] = s*(-cosk - rt3sink) - po3;
|
|
n3 = 3;
|
|
++ncub[25];
|
|
}
|
|
else ++ncub[26];
|
|
}
|
|
}
|
|
else
|
|
/*
|
|
cubic has multiple root -
|
|
*/
|
|
{
|
|
++ncub[27];
|
|
v3[0] = curoot(v) - po3;
|
|
v3[1] = v3[0];
|
|
v3[2] = v3[0];
|
|
n3 = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
if (debug < 1)
|
|
{
|
|
printf("cubic %d %g %g %g\n",n3,p,q,r);
|
|
for (j = 0; j < n3; ++j)
|
|
printf(" %d %13g %13g\n",j,v3[j],r+v3[j]*(q+v3[j]*(p+v3[j])));
|
|
printf("v %g, uo3 %g, m1 %g, m2 %g, po3 %g, cosk %g\n",
|
|
v,uo3,m1,m2,po3,cosk);
|
|
for (j = 0; j < 28; ++j)
|
|
{
|
|
printf(" %d",ncub[j]);
|
|
if ((j%10) == 9) printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (iterate == TRUE) cubnewton(p,q,r,n3,v3);
|
|
return(n3) ;
|
|
} /* cubic */
|
|
/****************************************************/
|
|
|
|
cubnewton(p,q,r,n3,v3)
|
|
int n3;
|
|
double p,q,r,v3[4];
|
|
/*
|
|
improve roots of cubic by Newton-Raphson iteration
|
|
|
|
5 Jan 2004 Don Herbison-Evans
|
|
|
|
called by cubic.
|
|
*/
|
|
{
|
|
int j,k;
|
|
double corr,deriv,err,root;
|
|
|
|
if (debug < 2) printf("cubnewtona %d %g\n",
|
|
n3,v3[0]);
|
|
for (j = 0; j < n3; ++j)
|
|
{
|
|
for (k = 0; k < 4; ++k)
|
|
{
|
|
root = v3[j];
|
|
err = ((root + p)*root + q)*root + r;
|
|
deriv = (doub3*root + doub2*p)*root + q;
|
|
if (deriv != doub0) corr = err/deriv; else corr = doub0;
|
|
v3[j] -= corr;
|
|
if (debug < 1) printf("cubnewtonb %d %d %g %g %g %g %g\n",
|
|
j,k,root,err,deriv,corr,v3[j]);
|
|
}
|
|
}
|
|
} /* cubnewton */
|
|
/****************************************************/
|
|
|
|
int quartic(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
Solve quartic equation using either
|
|
quadratic, Ferrari's or Neumark's algorithm.
|
|
|
|
called by
|
|
calls descartes, ferrari, neumark, yacfraid.
|
|
|
|
15 Dec 2003 added yacfraid
|
|
10 Dec 2003 added descartes with neg coeffs
|
|
21 Jan 1989 Don Herbison-Evans
|
|
*/
|
|
{
|
|
int quadratic(),ferrari(),neumark(),yacfraid();
|
|
int j,k,nq,nr;
|
|
double odd, even;
|
|
double roots[4];
|
|
double fabs();
|
|
|
|
if (fabs(a) > doubmax)
|
|
nr = yacfraid(a,b,c,d,rts);
|
|
else
|
|
if ((a == doub0) && (c == doub0))
|
|
{
|
|
nq = quadratic(b,d,roots);
|
|
nr = 0;
|
|
for (j = 0; j < nq; ++j)
|
|
{
|
|
if (roots[0] >= doub0)
|
|
{
|
|
rts[0] = sqrt(roots[0]);
|
|
rts[1] = -rts[0];
|
|
nr = 2;
|
|
}
|
|
if (roots[1] >= doub0)
|
|
{
|
|
rts[nr] = sqrt(roots[1]);
|
|
rts[nr+1] = -rts[nr];
|
|
nr += 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
k = 0;
|
|
if (a < doub0) k += 2;
|
|
if (b < doub0) k += 1;
|
|
if (c < doub0) k += 8;
|
|
if (d < doub0) k += 4;
|
|
switch (k)
|
|
{
|
|
case 0 : nr = neumark(a,b,c,d,rts); break;
|
|
case 1 : nr = neumark(a,b,c,d,rts); break;
|
|
case 2 : nr = neumark(a,b,c,d,rts); break;
|
|
case 3 : nr = ferrari(a,b,c,d,rts); break;
|
|
case 4 : nr = neumark(a,b,c,d,rts); break;
|
|
case 5 : nr = descartes(a,b,c,d,rts); break;
|
|
case 6 : nr = neumark(a,b,c,d,rts); break;
|
|
case 7 : nr = neumark(a,b,c,d,rts); break;
|
|
case 8 : nr = neumark(a,b,c,d,rts); break;
|
|
case 9 : nr = ferrari(a,b,c,d,rts); break;
|
|
case 10 : nr = neumark(a,b,c,d,rts); break;
|
|
case 11 : nr = neumark(a,b,c,d,rts); break;
|
|
case 12 : nr = neumark(a,b,c,d,rts); break;
|
|
case 13 : nr = neumark(a,b,c,d,rts); break;
|
|
case 14 : nr = neumark(a,b,c,d,rts); break;
|
|
case 15 : nr = descartes(-a,b,-c,d,rts); break;
|
|
}
|
|
if (k == 15)
|
|
for (j = 0; j < nr; ++j)
|
|
rts[j] = -rts[j];
|
|
}
|
|
return(nr);
|
|
} /* quartic */
|
|
/*****************************************/
|
|
|
|
int descartes(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
Solve quartic equation using
|
|
Descartes-Euler-Cardano algorithm
|
|
|
|
called by quartic, compare, quartictest.
|
|
|
|
Strong, T. "Elemementary and Higher Algebra"
|
|
Pratt and Oakley, p. 469 (1859)
|
|
|
|
16 Jul 1981 Don Herbison-Evans
|
|
*/
|
|
{
|
|
double errors();
|
|
int quadratic(),cubic();
|
|
|
|
int j;
|
|
double v1[4],v2[4],v3[4];
|
|
double k,y;
|
|
double dis;
|
|
double p,q,r;
|
|
double e0,e1,e2;
|
|
double g,h;
|
|
double asq;
|
|
double ainv4;
|
|
double e1invk;
|
|
|
|
asq = a*a;
|
|
e2 = b - asq*d3o8;
|
|
e1 = c + a*(asq*inv8 - b*inv2);
|
|
e0 = d + asq*(b*inv16 - asq*d3o256) - a*c*inv4;
|
|
|
|
p = doub2*e2;
|
|
q = e2*e2 - doub4*e0;
|
|
r = -e1*e1;
|
|
|
|
n3 = cubic(p,q,r,v3);
|
|
for (j3 = 0; j3 < n3; ++j3)
|
|
{
|
|
y = v3[j3];
|
|
if (y <= doub0)
|
|
{
|
|
n4[j3] = 0;
|
|
++ndes[0];
|
|
} /* y<0 */
|
|
else
|
|
{
|
|
k = sqrt(y);
|
|
ainv4 = a*inv4;
|
|
e1invk = e1/k;
|
|
g = (y + e2 + e1invk)*inv2;
|
|
h = (y + e2 - e1invk)*inv2 ;
|
|
n1 = quadratic(-k, g, v1);
|
|
n2 = quadratic( k, h, v2);
|
|
qrts[0][j3] = v1[0] - ainv4;
|
|
qrts[1][j3] = v1[1] - ainv4;
|
|
qrts[n1][j3] = v2[0] - ainv4;
|
|
qrts[n1+1][j3] = v2[1] - ainv4;
|
|
n4[j3]= n1 + n2;
|
|
++ndes[1];
|
|
} /* y>=0 */
|
|
donej3:
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
worst3[j3] = errors(a,b,c,d,rts,rterd,n4[j3]);
|
|
} /* j3 loop */
|
|
done:
|
|
j3 = 0;
|
|
if (n3 != 1)
|
|
{
|
|
if ((n4[0] == n4[1]) && (n4[1] == n4[2]))
|
|
++ndes[NCASES-2];
|
|
else
|
|
++ndes[NCASES-1];
|
|
if ((n4[1] > n4[j3]) ||
|
|
((worst3[1] < worst3[j3] ) && (n4[1] == n4[j3]))) j3 = 1;
|
|
if ((n4[2] > n4[j3]) ||
|
|
((worst3[2] < worst3[j3] ) && (n4[2] == n4[j3]))) j3 = 2;
|
|
}
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
if (debug < 1)
|
|
printf("descartes chose cubic %d %g %g\n\n",j3,v3[j3],worst3[j3]);
|
|
++ndes[30+n4[j3]];
|
|
++ndes[35+j3];
|
|
return(n4[j3]);
|
|
} /* descartes */
|
|
/****************************************************/
|
|
|
|
int ferrari(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
solve the quartic equation -
|
|
|
|
x**4 + a*x**3 + b*x**2 + c*x + d = 0
|
|
|
|
called by quartic, compare, quartictest.
|
|
calls cubic, quadratic.
|
|
|
|
input -
|
|
a,b,c,e - coeffs of equation.
|
|
|
|
output -
|
|
n4 - number of real roots.
|
|
rts - array of root values.
|
|
|
|
method : Ferrari - Lagrange
|
|
Theory of Equations, H.W. Turnbull p. 140 (1947)
|
|
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
calls cubic, quadratic
|
|
*/
|
|
{
|
|
double errors();
|
|
int cubic(),quadratic();
|
|
|
|
int j,k;
|
|
double asqinv4;
|
|
double ainv2;
|
|
double d4;
|
|
double yinv2;
|
|
double v1[4],v2[4],v3[4];
|
|
double p,q,r;
|
|
double y;
|
|
double e,f,esq,fsq,ef;
|
|
double g,gg,h,hh;
|
|
|
|
ainv2 = a*inv2;
|
|
asqinv4 = ainv2*ainv2;
|
|
d4 = d*doub4 ;
|
|
|
|
p = b;
|
|
q = a*c-d4;
|
|
r = (asqinv4 - b)*d4 + c*c;
|
|
n3 = cubic(p,q,r,v3);
|
|
for (j3 = 0; j3 < n3; ++j3)
|
|
{
|
|
y = v3[j3];
|
|
yinv2 = y*inv2;
|
|
esq = asqinv4 - b - y;
|
|
fsq = yinv2*yinv2 - d;
|
|
if ((esq < doub0) && (fsq < doub0))
|
|
{
|
|
n4[j3] = 0;
|
|
++nfer[0];
|
|
}
|
|
else
|
|
{
|
|
ef = -(inv4*a*y + inv2*c);
|
|
if ( ((a > doub0)&&(y > doub0)&&(c > doub0))
|
|
|| ((a > doub0)&&(y < doub0)&&(c < doub0))
|
|
|| ((a < doub0)&&(y > doub0)&&(c < doub0))
|
|
|| ((a < doub0)&&(y < doub0)&&(c > doub0))
|
|
|| (a == doub0)||(y == doub0)||(c == doub0))
|
|
/* use ef - */
|
|
{
|
|
if ((b < doub0)&&(y < doub0))
|
|
{
|
|
e = sqrt(esq);
|
|
f = ef/e;
|
|
++nfer[1];
|
|
}
|
|
else if (d < doub0)
|
|
{
|
|
f = sqrt(fsq);
|
|
e = ef/f;
|
|
++nfer[2];
|
|
}
|
|
else
|
|
{
|
|
if (esq > doub0)
|
|
{
|
|
e = sqrt(esq);
|
|
++nfer[3];
|
|
}
|
|
else
|
|
{
|
|
e = doub0;
|
|
++nfer[4];
|
|
}
|
|
if (fsq > doub0)
|
|
{
|
|
f = sqrt(fsq);
|
|
++nfer[5];
|
|
}
|
|
else
|
|
{
|
|
f = doub0;
|
|
++nfer[6];
|
|
}
|
|
if (ef < doub0)
|
|
{
|
|
f = -f;
|
|
++nfer[7];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
/* use esq and fsq - */
|
|
{
|
|
if (esq > doub0)
|
|
{
|
|
e = sqrt(esq);
|
|
++nfer[8];
|
|
}
|
|
else
|
|
{
|
|
e = doub0;
|
|
++nfer[9];
|
|
}
|
|
if (fsq > doub0)
|
|
{
|
|
f = sqrt(fsq);
|
|
++nfer[10];
|
|
}
|
|
else
|
|
{
|
|
f = doub0;
|
|
++nfer[11];
|
|
}
|
|
if (ef < doub0)
|
|
{
|
|
f = -f;
|
|
++nfer[12];
|
|
}
|
|
}
|
|
/* note that e >= doub0 */
|
|
g = ainv2 - e;
|
|
gg = ainv2 + e;
|
|
if ( ((b > doub0)&&(y > doub0))
|
|
|| ((b < doub0)&&(y < doub0)) )
|
|
{
|
|
if ((a > doub0) && (e > doub0)
|
|
|| (a < doub0) && (e < doub0) )
|
|
{
|
|
g = (b + y)/gg;
|
|
++nfer[13];
|
|
}
|
|
else
|
|
if ((a > doub0) && (e < doub0)
|
|
|| (a < doub0) && (e > doub0) )
|
|
{
|
|
gg = (b + y)/g;
|
|
++nfer[14];
|
|
}
|
|
else
|
|
++nfer[15];
|
|
}
|
|
hh = -yinv2 + f;
|
|
h = -yinv2 - f;
|
|
if ( ((f > doub0)&&(y < doub0))
|
|
|| ((f < doub0)&&(y > doub0)) )
|
|
{
|
|
h = d/hh;
|
|
++nfer[16];
|
|
}
|
|
else
|
|
if ( ((f < doub0)&&(y < doub0))
|
|
|| ((f > doub0)&&(y > doub0)) )
|
|
{
|
|
hh = d/h;
|
|
++nfer[17];
|
|
}
|
|
else
|
|
++nfer[18];
|
|
|
|
n1 = quadratic(gg,hh,v1);
|
|
n2 = quadratic(g,h,v2);
|
|
n4[j3] = n1+n2;
|
|
qrts[0][j3] = v1[0];
|
|
qrts[1][j3] = v1[1];
|
|
qrts[n1+0][j3] = v2[0];
|
|
qrts[n1+1][j3] = v2[1];
|
|
}
|
|
donej3:
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
worst3[j3] = errors(a,b,c,d,rts,rterf,n4[j3]);
|
|
} /* j3 loop */
|
|
done:
|
|
j3 = 0;
|
|
if (n3 != 1)
|
|
{
|
|
if ((n4[0] == n4[1]) && (n4[1] == n4[2]))
|
|
++nfer[NCASES-2];
|
|
else
|
|
++nfer[NCASES-1];
|
|
if ((n4[1] > n4[j3]) ||
|
|
((worst3[1] < worst3[j3] ) && (n4[1] == n4[j3]))) j3 = 1;
|
|
if ((n4[2] > n4[j3]) ||
|
|
((worst3[2] < worst3[j3] ) && (n4[2] == n4[j3]))) j3 = 2;
|
|
}
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
if (debug < 1)
|
|
printf("ferrari chose cubic %d %g %g\n\n",j3,v3[j3],worst3[j3]);
|
|
++nfer[30+n4[j3]];
|
|
++nfer[35+j3];
|
|
return(n4[j3]);
|
|
} /* ferrari */
|
|
/*****************************************/
|
|
|
|
int neumark(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
solve the quartic equation -
|
|
|
|
x**4 + a*x**3 + b*x**2 + c*x + d = 0
|
|
|
|
called by quartic, compare, quartictest.
|
|
calls cubic, quadratic.
|
|
|
|
input parameters -
|
|
a,b,c,e - coeffs of equation.
|
|
|
|
output parameters -
|
|
n4 - number of real roots.
|
|
rts - array of root values.
|
|
|
|
method - S. Neumark
|
|
"Solution of Cubic and Quartic Equations" - Pergamon 1965
|
|
|
|
1 Dec 1985 translated to C with help of Shawn Neely
|
|
16 Jul 1981 Don Herbison-Evans
|
|
|
|
*/
|
|
{
|
|
int j,k;
|
|
double y,g,gg,h,hh,gdis,gdisrt,hdis,hdisrt,g1,g2,h1,h2;
|
|
double bmy,gerr,herr,y4,bmysq;
|
|
double v1[4],v2[4],v3[4];
|
|
double asq;
|
|
double d4;
|
|
double p,q,r;
|
|
double hmax,gmax;
|
|
double errors();
|
|
int cubic();
|
|
int quadratic();
|
|
|
|
if (d == doub0)
|
|
{
|
|
n3 = 0;
|
|
n4[0] = cubic(a,b,c,rts);
|
|
for (j = 0; j < n4[0]; ++j)
|
|
qrts[j][0] = rts[j];
|
|
qrts[n4[0]++][0] = doub0;
|
|
goto done;
|
|
}
|
|
asq = a*a;
|
|
d4 = d*doub4;
|
|
p = -b*doub2;
|
|
q = b*b + a*c - d4;
|
|
r = (c - a*b)*c + asq*d;
|
|
if (debug < 3)
|
|
printf("neumarka %g %g %g %g, %g %g %g\n",
|
|
a,b,c,d,p,q,r);
|
|
n3 = cubic(p,q,r,v3);
|
|
for (j3 = 0; j3 < n3; ++j3)
|
|
{
|
|
y = v3[j3];
|
|
bmy = b - y;
|
|
y4 = y*doub4;
|
|
bmysq = bmy*bmy;
|
|
gdis = asq - y4;
|
|
hdis = bmysq - d4;
|
|
if (debug < 3)
|
|
printf("neumarkb %g %g\n",
|
|
gdis,hdis);
|
|
if ((gdis < doub0) || (hdis < doub0))
|
|
{
|
|
n4[j3] = 0;
|
|
++nneu[0];
|
|
}
|
|
else
|
|
{
|
|
g1 = a*inv2;
|
|
h1 = bmy*inv2;
|
|
gerr = asq + y4;
|
|
herr = hdis;
|
|
if (d > doub0)
|
|
{
|
|
herr = bmysq + d4;
|
|
++nneu[1];
|
|
}
|
|
if ((y < doub0) || (herr*gdis > gerr*hdis))
|
|
{
|
|
gdisrt = sqrt(gdis);
|
|
g2 = gdisrt*inv2;
|
|
if (gdisrt != doub0)
|
|
{
|
|
h2 = (a*h1 - c)/gdisrt;
|
|
++nneu[2];
|
|
}
|
|
else
|
|
{
|
|
h2 = doub0;
|
|
++nneu[3];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdisrt = sqrt(hdis);
|
|
h2 = hdisrt*inv2;
|
|
if (hdisrt != doub0)
|
|
{
|
|
g2 = (a*h1 - c)/hdisrt;
|
|
++nneu[4];
|
|
}
|
|
else
|
|
{
|
|
g2 = doub0;
|
|
++nneu[5];
|
|
}
|
|
}
|
|
/*
|
|
note that in the following, the tests ensure non-zero
|
|
denominators -
|
|
*/
|
|
h = h1 - h2;
|
|
hh = h1 + h2;
|
|
hmax = hh;
|
|
if (hmax < doub0)
|
|
{
|
|
hmax = -hmax;
|
|
++nneu[6];
|
|
}
|
|
if (hmax < h)
|
|
{
|
|
hmax = h;
|
|
++nneu[7];
|
|
}
|
|
if (hmax < -h)
|
|
{
|
|
hmax = -h;
|
|
++nneu[8];
|
|
}
|
|
if ((h1 > doub0)&&(h2 > doub0))
|
|
{
|
|
h = d/hh;
|
|
++nneu[9];
|
|
}
|
|
if ((h1 < doub0)&&(h2 < doub0))
|
|
{
|
|
h = d/hh;
|
|
++nneu[10];
|
|
}
|
|
if ((h1 > doub0)&&(h2 < doub0))
|
|
{
|
|
hh = d/h;
|
|
++nneu[11];
|
|
}
|
|
if ((h1 < doub0)&&(h2 > doub0))
|
|
{
|
|
hh = d/h;
|
|
++nneu[12];
|
|
}
|
|
if (h > hmax)
|
|
{
|
|
h = hmax;
|
|
++nneu[13];
|
|
}
|
|
if (h < -hmax)
|
|
{
|
|
h = -hmax;
|
|
++nneu[14];
|
|
}
|
|
if (hh > hmax)
|
|
{
|
|
hh = hmax;
|
|
++nneu[15];
|
|
}
|
|
if (hh < -hmax)
|
|
{
|
|
hh = -hmax;
|
|
++nneu[16];
|
|
}
|
|
|
|
g = g1 - g2;
|
|
gg = g1 + g2;
|
|
gmax = gg;
|
|
if (gmax < doub0)
|
|
{
|
|
gmax = -gmax;
|
|
++nneu[17];
|
|
}
|
|
if (gmax < g)
|
|
{
|
|
gmax = g;
|
|
++nneu[18];
|
|
}
|
|
if (gmax < -g)
|
|
{
|
|
gmax = -g;
|
|
++nneu[19];
|
|
}
|
|
if ((g1 > doub0)&&(g2 > doub0))
|
|
{
|
|
g = y/gg;
|
|
++nneu[20];
|
|
}
|
|
if ((g1 < doub0)&&(g2 < doub0))
|
|
{
|
|
g = y/gg;
|
|
++nneu[21];
|
|
}
|
|
if ((g1 > doub0)&&(g2 < doub0))
|
|
{
|
|
gg = y/g;
|
|
++nneu[22];
|
|
}
|
|
if ((g1 < doub0)&&(g2 > doub0))
|
|
{
|
|
gg = y/g;
|
|
++nneu[23];
|
|
}
|
|
if (g > gmax)
|
|
{
|
|
g = gmax;
|
|
++nneu[24];
|
|
}
|
|
if (g < -gmax)
|
|
{
|
|
g = -gmax;
|
|
++nneu[25];
|
|
}
|
|
if (gg > gmax)
|
|
{
|
|
gg = gmax;
|
|
++nneu[26];
|
|
}
|
|
if (gg < -gmax)
|
|
{
|
|
gg = -gmax;
|
|
++nneu[27];
|
|
}
|
|
|
|
n1 = quadratic(gg,hh,v1);
|
|
n2 = quadratic(g,h,v2);
|
|
n4[j3] = n1 + n2;
|
|
qrts[0][j3] = v1[0];
|
|
qrts[1][j3] = v1[1];
|
|
qrts[n1+0][j3] = v2[0];
|
|
qrts[n1+1][j3] = v2[1];
|
|
}
|
|
donej3:
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
worst3[j3] = errors(a,b,c,d,rts,rtern,n4[j3]);
|
|
} /* j3 loop */
|
|
done:
|
|
j3 = 0;
|
|
if (n3 > 1)
|
|
{
|
|
if ((n4[0] == n4[1]) && (n4[1] == n4[2]))
|
|
++nneu[NCASES-2];
|
|
else
|
|
++nneu[NCASES-1];
|
|
if ((n4[1] > n4[j3]) ||
|
|
((worst3[1] < worst3[j3] ) && (n4[1] == n4[j3]))) j3 = 1;
|
|
if ((n4[2] > n4[j3]) ||
|
|
((worst3[2] < worst3[j3] ) && (n4[2] == n4[j3]))) j3 = 2;
|
|
}
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
if (debug < 1)
|
|
printf("neumark chose cubic %d %g %g\n\n",j3,v3[j3],worst3[j3]);
|
|
++nneu[30+n4[j3]];
|
|
++nneu[35+j3];
|
|
return(n4[j3]);
|
|
} /* neumark */
|
|
/****************************************************/
|
|
|
|
int yacfraid(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
solve the quartic equation -
|
|
|
|
x**4 + a*x**3 + b*x**2 + c*x + d = 0
|
|
|
|
called by quartic, compare, quartictest.
|
|
calls cubic, quadratic.
|
|
|
|
input parameters -
|
|
a,b,c,e - coeffs of equation.
|
|
|
|
output parameters -
|
|
n4 - number of real roots.
|
|
rts - array of root values.
|
|
|
|
method -
|
|
K.S. Brown
|
|
Reducing Quartics to Cubics,
|
|
http://www.seanet.com/~ksbrown/kmath296.htm (1967)
|
|
|
|
Michael Daoud Yacoub & Gustavo Fraidenraich
|
|
"A new simple solution of the general quartic equation"
|
|
Revised 16 Feb 2004
|
|
|
|
14 Nov 2003 Don Herbison-Evans
|
|
*/
|
|
{
|
|
int i,j;
|
|
double y;
|
|
double v1[4],v2[4],v3[4];
|
|
double asq,acu;
|
|
double b4;
|
|
double det0,det1,det2,det3;
|
|
double det0rt,det1rt,det2rt,det3rt;
|
|
double e,f,g,h,k;
|
|
double fsq,gsq,hsq,invk;
|
|
double P,Q,R,U;
|
|
double errors();
|
|
int cubic();
|
|
int quadratic();
|
|
|
|
if (d == doub0)
|
|
{
|
|
n3 = 0;
|
|
n4[0] = cubic(a,b,c,rts);
|
|
for (j = 0; j < n4[0]; ++j)
|
|
qrts[j][0] = rts[j];
|
|
qrts[n4[0]++][0] = doub0;
|
|
goto done;
|
|
}
|
|
asq = a*a;
|
|
acu = a*asq;
|
|
b4 = b*doub4;
|
|
n3 = 0;
|
|
|
|
P = asq*b - b4*b + doub2*a*c + doub16*d ;
|
|
Q = asq*c - b4*c + doub8*a*d;
|
|
R = asq*d - c*c ;
|
|
U = acu - b4*a + doub8*c;
|
|
n4[0] = 0;
|
|
if (U == doub0)
|
|
{
|
|
if (P == doub0)
|
|
{
|
|
det0 = doub3*asq - doub8*b;
|
|
if (det0 < doub0)
|
|
{
|
|
++nyac[0];
|
|
goto done;
|
|
}
|
|
det0rt = sqrt(det0);
|
|
qrts[0][0] = (-a + det0rt)*inv4;
|
|
qrts[1][0] = qrts[0][0];
|
|
qrts[2][0] = (-a - det0rt)*inv4;
|
|
qrts[3][0] = qrts[2][0];
|
|
++nyac[1];
|
|
n4[0] = 4;
|
|
goto done;
|
|
} /* P=0 */
|
|
else
|
|
{
|
|
det1 = asq*asq - doub8*asq*b + doub16*b*b - doub64*d;
|
|
if (det1 < doub0)
|
|
{
|
|
++nyac[2];
|
|
goto done;;
|
|
}
|
|
n4[0] = 0;
|
|
det1rt = sqrt(det1);
|
|
det2 = doub3*asq - doub8*b + doub2*det1rt;
|
|
if (det2 >= doub0)
|
|
{
|
|
det2rt = sqrt(det2);
|
|
qrts[0][0] = (-a + det2rt)*inv4;
|
|
qrts[1][0] = (-a - det2rt)*inv4;
|
|
n4[0] = 2;
|
|
++nyac[3];
|
|
}
|
|
det3 = doub3*asq - doub8*b - doub2*det1rt;
|
|
if (det3 >= doub0)
|
|
{
|
|
det3rt = sqrt(det3);
|
|
qrts[n4[0]++][0] = (-a + det3rt)*inv4;
|
|
qrts[n4[0]++][0] = (-a - det3rt)*inv4;
|
|
++nyac[5];
|
|
}
|
|
if (n4[0] == 0) ++nyac[6];
|
|
goto done;
|
|
} /* P<>0 */
|
|
}
|
|
|
|
n3 = cubic(P/U,Q/U,R/U,v3);
|
|
for (j3 = 0; j3 < n3; ++j3)
|
|
{
|
|
y = v3[j3];
|
|
j = 0;
|
|
k = a + doub4*y;
|
|
if (k == doub0)
|
|
{
|
|
++nyac[9];
|
|
goto donej3;
|
|
}
|
|
invk = doub1/k;
|
|
e = (acu - doub4*c - doub2*a*b + (doub6*asq - doub16*b)*y)*invk;
|
|
fsq = (acu + doub8*c - doub4*a*b)*invk;
|
|
if (fsq < doub0)
|
|
{
|
|
++nyac[10];
|
|
goto donej3;
|
|
}
|
|
f = sqrt(fsq);
|
|
gsq = doub2*(e + f*k);
|
|
hsq = doub2*(e - f*k);
|
|
if (gsq >= doub0)
|
|
{
|
|
++nyac[11];
|
|
g = sqrt(gsq);
|
|
qrts[j++][j3] = (-a - f - g)*inv4;
|
|
qrts[j++][j3] = (-a - f + g)*inv4;
|
|
}
|
|
if (hsq >= doub0)
|
|
{
|
|
++nyac[12];
|
|
h = sqrt(hsq);
|
|
qrts[j++][j3] = (-a + f - h)*inv4;
|
|
qrts[j++][j3] = (-a + f + h)*inv4;
|
|
}
|
|
if (debug < 1)
|
|
{
|
|
printf("j3 %d y %g k %g fsq %g gsq %g hsq %g\n",
|
|
j3,y,k,fsq,gsq,hsq);
|
|
printf("e %g f %g g %g h %g\n",e,f,g,h);
|
|
}
|
|
donej3:
|
|
n4[j3] = j;
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
worst3[j3] = errors(a,b,c,d,rts,rtery,n4[j3]);
|
|
} /* j3 loop */
|
|
done:
|
|
j3 = 0;
|
|
if (n3 > 1)
|
|
{
|
|
if ((n4[0] == n4[1]) && (n4[1] == n4[2]))
|
|
++nyac[NCASES-2];
|
|
else
|
|
{
|
|
++nyac[NCASES-1];
|
|
if ((n4[0] != n4[1]) && (n4[0] != n4[2]) && (n4[1] != n4[2]))
|
|
printf("yace %d %d %d %g %g %g %g\n",
|
|
n4[0],n4[1],n4[2],a,b,c,d);
|
|
}
|
|
if ((n4[1] > n4[j3]) ||
|
|
((worst3[1] < worst3[j3] ) && (n4[1] == n4[j3]))) j3 = 1;
|
|
if ((n4[2] > n4[j3]) ||
|
|
((worst3[2] < worst3[j3] ) && (n4[2] == n4[j3]))) j3 = 2;
|
|
}
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
++nyac[30+n4[j3]];
|
|
++nyac[35+j3];
|
|
if (debug < 1)
|
|
printf("yacfraid chose cubic %d %g %g\n\n",j3,v3[j3],worst3[j3]);
|
|
return(n4[j3]);
|
|
} /* yacfraid */
|
|
/*****************************************/
|
|
|
|
int chris(a,b,c,d,rts)
|
|
double a,b,c,d,rts[4];
|
|
/*
|
|
Solve quartic equation using
|
|
Christianson's algorithm
|
|
|
|
called by compare, quartictest.
|
|
calls errors, quadratic, cubic.
|
|
|
|
Bruce Christianson, Solving Quartics Using Palindromes,
|
|
Mathematical Gazette, Vol. 75, pp. 327-328 (1991)
|
|
|
|
14 Jan 2004 Don Herbison-Evans
|
|
*/
|
|
{
|
|
double errors();
|
|
int quadratic(),cubic();
|
|
|
|
int j;
|
|
int n0,n1,n2;
|
|
double v0[4],v1[4],v2[4],v3[4];
|
|
double y,ysq,ycu;
|
|
double p,q,r;
|
|
double asq,acu,aqu,ao4;
|
|
double e0,e1,e2;
|
|
double k,ksq,kcu,kqu,kquinv,k1,k2;
|
|
double g,h,g1,Z1,Z2;
|
|
|
|
if (d == doub0)
|
|
{
|
|
n3 = 0;
|
|
n4[0] = cubic(a,b,c,rts);
|
|
for (j = 0; j < n4[0]; ++j)
|
|
qrts[j][0] = rts[j];
|
|
qrts[n4[0]++][0] = doub0;
|
|
goto done;
|
|
}
|
|
asq = a*a;
|
|
acu = asq*a;
|
|
aqu = acu*a;
|
|
ao4 = a*inv4;
|
|
e2 = b - d3o8*asq;
|
|
e1 = c - inv2*b*a + inv8*acu;
|
|
e0 = d - inv4*c*a + inv16*b*asq - d3o256*acu*a;
|
|
if (debug < 1)
|
|
printf("chrisa e0 %g e1 %g e2 %g\n",e0,e1,e2);
|
|
if (e1 == doub0)
|
|
{
|
|
n3 = 0;
|
|
n4[0] = 0;
|
|
++nchr[0];
|
|
n3 = 3;
|
|
v3[2] = doub0;
|
|
v3[1] = doub0;
|
|
v3[0] = -inv8*(doub16*e0 - doub4*e2*e2);
|
|
}
|
|
else
|
|
{
|
|
p = (inv2*b*asq - inv2*b*b - inv2*c*a + doub2*d - doub3*inv32*aqu)/e1;
|
|
q = doub3*inv16*asq - inv2*b;
|
|
r = inv16*b*a - inv8*c - inv64*acu;
|
|
if (debug < 1) printf("chrisb %g %g %g\n",p,q,r);
|
|
++nchr[1];
|
|
n3 = cubic(p,q,r,v3);
|
|
}
|
|
for (j3 = 0; j3 < n3; ++j3)
|
|
{
|
|
y = v3[j3];
|
|
n4[j3] = 0;
|
|
ysq = y*y;
|
|
ycu = y*ysq;
|
|
if ((y == doub0) ||
|
|
(( y < doub0) && (e1 <= doub0) && (e0 >= doub0) && (e2 >= doub0)))
|
|
{
|
|
kqu = y*ycu + e2*ysq + e1*y + e0;
|
|
if (kqu <= doub0)
|
|
{
|
|
ksq = doub0;
|
|
++nchr[2];
|
|
goto donej3;
|
|
}
|
|
ksq = sqrt(kqu);
|
|
}
|
|
else
|
|
{
|
|
ksq = ysq + inv2*e2 + inv4*e1/y;
|
|
if (ksq <= doub0)
|
|
{
|
|
kqu = doub0;
|
|
++nchr[3];
|
|
goto donej3;
|
|
}
|
|
kqu = ksq*ksq;
|
|
}
|
|
k = sqrt(ksq);
|
|
kcu = k*ksq;
|
|
kquinv = doub1/kqu;
|
|
g = doub4*y*kcu;
|
|
h = (doub6*ysq + e2)*ksq;
|
|
if (debug < 1)
|
|
{
|
|
k2 = sqrt(sqrt(fabs(y*ycu + e2*ysq + e1*y + e0)));
|
|
if (y == doub0)
|
|
k1 = doub0;
|
|
else
|
|
k1 = sqrt(fabs(ysq + inv2*e2 + inv4*e1/y));
|
|
g1 = (doub4*ycu + doub2* y*e2 + e1)*k;
|
|
printf("chrisc %g %g %g %g %g\n",k,k1,y,g,g1,h);
|
|
}
|
|
n0 = quadratic(g*kquinv,h*kquinv-doub2,v0);
|
|
if (n0 < 1)
|
|
{
|
|
++nchr[4];
|
|
goto donej3;
|
|
}
|
|
Z1 = v0[0];
|
|
Z2 = v0[1];
|
|
n1 = quadratic(-Z1,doub1,v1);
|
|
if (n1 > 0)
|
|
{
|
|
++nchr[5];
|
|
n4[j3] = n1;
|
|
qrts[0][j3] = y + k*v1[0] - ao4;
|
|
qrts[1][j3] = y + k*v1[1] - ao4;
|
|
}
|
|
n2 = quadratic(-Z2,doub1,v2);
|
|
if (n2 > 0)
|
|
{
|
|
++nchr[6];
|
|
n4[j3] += n2;
|
|
qrts[n1][j3] = y + k*v2[0] - ao4;
|
|
qrts[n1+1][j3] = y + k*v2[1] - ao4;
|
|
}
|
|
donej3:
|
|
if (debug < 1)
|
|
printf("chrisd %g %g\n",ksq,kqu);
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
worst3[j3] = errors(a,b,c,d,rts,rterc,n4[j3]);
|
|
} /* j3 loop */
|
|
done:
|
|
j3 = 0;
|
|
if (n3 > 1)
|
|
{
|
|
if ((n4[0] == n4[1]) && (n4[1] == n4[2]))
|
|
++nchr[NCASES-2];
|
|
else
|
|
{
|
|
++nchr[NCASES-1];
|
|
if (debug < 1)
|
|
printf("chrise %d %d %d %g %g %g %g\n",
|
|
n4[0],n4[1],n4[2],a,b,c,d);
|
|
}
|
|
if ((n4[1] > n4[j3]) ||
|
|
((worst3[1] < worst3[j3] ) && (n4[1] == n4[j3]))) j3 = 1;
|
|
if ((n4[2] > n4[j3]) ||
|
|
((worst3[2] < worst3[j3] ) && (n4[2] == n4[j3]))) j3 = 2;
|
|
}
|
|
for (j = 0; j < n4[j3]; ++j)
|
|
rts[j] = qrts[j][j3];
|
|
if (debug < 1)
|
|
printf("chris chose cubic %d %g %g\n\n",j3,v3[j3],worst3[j3]);
|
|
++nchr[30+n4[j3]];
|
|
++nchr[35+j3];
|
|
return(n4[j3]);
|
|
} /* chris */
|
|
|