/*
*/
//
var polsol={versione:"20170221",tartaglia:1};
//
polsol.polinomio=function(p,z){
//
// z rappresenta la variabile indipendente e
// puo' essere sia un numero che una Array,
// z[0] rappresenta la parte reale del numero complesso
// e z[1], se c'e' rappresenta la parte immaginaria.
//
// Il risultato e' sempre una Array di due elementi,
// con l'elemento 0 parte reale e l'elemento 1 parte
// immaginaria.
//
// Qui il polinomio ha come termine di grado 0 il
// primo elemento, e l'ultimo elemento e' quello
// di grado piu' elevato.
//
var x,y,rx,ry,rn,j;
if(Array.isArray(z)){x=z[0];
if(z.length>1)y=z[1];
else{y=0}}
else{x=z;y=0;}
rx=1;ry=0;
for(j=p.length-1;j>-1;j--){
if(Array.isArray(p[j])){rn=rx*x-ry*y+p[j][0];
if(p[j].length>1){ry=rx*y+ry*x+p[j][1];}
else{ry=rx*y+ry*x;}}
else{rn=rx*x-ry*y+p[j];ry=rx*y+ry*x;}
rx=rn;
}
//
// Un numero complesso e' indicato con [a,b] dove
// a e b sono numeri reali e dunque e' una Array di
// due elementi: l'elemento 0 e' la parte reale e
// l'elemento 1 e' la parte immaginaria.
//
return [rx,ry];
};
//
// Crea un polinomio di quarto grado di cui sa anche
// le sue quattro radici e fa in modo che il termine
// noto non possa mai essere esattamente nullo,
// anche se piccolissimo.
// Dati quattro argomenti reali calcola il polinomio
// di quarto grado con 1 sottinteso come fattore
// della quarta potenza.
//
polsol.perverifiche=function(a,bb,c,dd){
var b,d,pp,r1,r2,r3,r4,det;
if(Math.abs(bb)==0)b=1.e-5;
else b=bb;
if(Math.abs(dd)==0)d=1.e-5;
else d=dd;
pp=[[b*d,0],[2*(a*d+b*c),0],
[b+d+4*a*c,0],[2*(a+c),0]];
det=a*a-b;
if(0>det){r1=[-a,Math.sqrt(-det)];r2=[-a,-Math.sqrt(-det)]}
else{ r1=[-a+Math.sqrt(det),0];r2=[-a-Math.sqrt(det),0]}
det=c*c-d;
if(0>det){r3=[-c,Math.sqrt(-det)];r4=[-c,-Math.sqrt(-det)]}
else{r3=[-c+Math.sqrt(det),0];r4=[-c-Math.sqrt(det),0]}
return [pp,[r1,r2,r3,r4]]; }
//
// Equazione di secondo grado
//
polsol.secondogrado=function(r){
//
// Radici equaz. di secondo grado a coeff. complessi:
// (y + r[1] )*y + r[0] = 0
//
// r[0][0] rappresenta la parte reale del termine noto.
// r[0][1] e' la parte immaginaria del termine noto.
// Se r[0] non e' una Array, r[0] e' il termine noto reale.
// r[1][0] e' la parte reale del termine di primo grado.
// r[1][1] e' la parte immaginaria del termine di primo grado.
// Se r[1] non e' una Array r[1] e' il termine di primo grado reale.
// Il termine di secondo grado e' sottinteso e vale 1.
//
var p,q,s,t,x,a,b;
if(Array.isArray(r[0]))b=r[0];
else{b=[r[0],0]};
if(Array.isArray(r[1]))a=r[1];
else{a=[r[1],0]};
//
if(0>=b[0]*b[0]+b[1]*b[1]) return [ [0,0],[-a[0],-a[1]] ];
p=a[0]*a[0]-a[1]*a[1]-4*b[0];
q=2*a[0]*a[1]-4*b[1];
with(Math) {
if(p>0){
s=sqrt((sqrt(p*p+q*q)+p)*0.5);
t=0.5*q/s;
}
else {
t=sqrt((sqrt(p*p+q*q)-p)*0.5);
// radici coincidenti
if(0 >= t) return [[-a[0]/2,-a[1]/2],[-a[0]/2,-a[1]/2]];
s=0.5*q/t;
}
// Fa direttamente la radice di maggior modulo
if(a[0]*s+a[1]*t>0) x=[-0.5*(a[0]+s), -0.5*(a[1]+t)];
else x=[-0.5*(a[0]-s), -0.5*(a[1]-t)];
// Deduce l'altra dal termine noto.
p=1/( x[0]*x[0] + x[1]*x[1] );
}
return [ x, [p*(b[0]*x[0]+b[1]*x[1]), p*(-b[0]*x[1]+b[1]*x[0])] ];
};
//
// Equazione cubica.
//
polsol.cubica=function(poli){
//
// radici di polinomio di terzo grado con
// coefficienti reali.
// Se il polinomio ha coefficienti con parte immaginaria la
// parte immaginaria viene ignorata.
//
var p,q,r,a,b,d,aa,bb,rd,nr,psi;
var an,sn,qn,pn,segno;
if(3>poli.length) return [ [0,1],[0,1],[0,1] ];
if(Array.isArray(poli[2]))p=poli[2][0];
else{p=poli[2]};
if(Array.isArray(poli[1]))q=poli[1][0];
else{q=poli[1]};
if(Array.isArray(poli[0]))r=poli[0][0];
else{r=poli[0]};
a=(p*p-3*q)/9;
b=(p*(9*q-2*p*p)-27*r)/54;
d=b*b-a*a*a;
//
sn=p/3;
qn=r-sn*(q-sn*(p-sn));
pn=q-sn*(2*p-3*sn);
if(0>=pn*pn){
// cubo perfetto, tre radici coincidenti !
if(qn>0) segno=1;
else if(0>qn) segno=-1;
else segno=0;
an=segno*Math.pow(Math.abs(qn),1/3)-sn;
return [[an,0],[an,0],[an,0]];};
with(Math){
if(0>=d) { // Tre radici reali
rd=sqrt(-d);
nr=sqrt(-d+b*b);
if(abs(b)>=rd) {
psi=asin(rd/nr);
if(0>b) psi=PI-psi;
}
else psi=acos(b/nr);
aa=pow(nr,1/3);
bb=aa*sin(psi/3);
aa=aa*cos(psi/3);
return [ [ 2*aa-p/3,0],
[ bb*sqrt(3)-aa-p/3,0],
[-bb*sqrt(3)-aa-p/3,0] ];
}
else { // Una sola radice reale
if(b>0) {
aa = pow(sqrt(d)+b,1/3);
bb = a/aa;
}
else {
bb = -pow(sqrt(d)-b,1/3);
aa = a/bb;
}
return [ [aa+bb-p/3,0],
[-0.5*(aa+bb)-p/3,-0.5*sqrt(3)*(aa-bb)],
[-0.5*(aa+bb)-p/3, 0.5*sqrt(3)*(aa-bb)] ];
};
};
};
//
// Se la variabile tartaglia vale -1...
//
polsol.cubicabis=function(poli){
//
// radici di polinomio di terzo grado con
// coefficienti reali e calcolati con
// algoritmo basato su funzioni trigonometriche
// ed esponenziali
var pp0,pp1,pp2;
var a,p,q,s,am,bm,cm, dm, ca,sina,cosa,expa,segno,sqrt3;
sqrt3=Math.sqrt(3);
if(3>poli.length) return[ [0,1],[0,1],[0,1] ];
// Lo faccio uscire se il polinomio e' mal fatto.
if(Array.isArray(poli[2]))pp2=poli[2][0];
else{pp2=poli[2]};
if(Array.isArray(poli[1]))pp1=poli[1][0];
else{pp1=poli[1]};
if(Array.isArray(poli[0]))pp0=poli[0][0];
else{pp0=poli[0]};
s=pp2/3;
q=pp0-s*(pp1-s*(pp2-s));
p=pp1-s*(2*pp2-3*s);
if(0>=p*p){
// cubo perfetto, tre radici coincidenti !
if(q>0) segno=1;
else if(0>q) segno=-1;
else segno=0;
a=segno*Math.pow(Math.abs(q),1/3)-s;
return [[a,0],[a,0],[a,0]];};
if(p>0){
bm=Math.sqrt(4*p/3);
dm=-q*Math.sqrt(27/(4*p))/p;
a=Math.log(dm+Math.sqrt(dm*dm+1))/3;
expa=Math.exp(a);
sina=bm*(expa-1/expa)/2;
cosa=bm*(expa+1/expa)/2;
return [[sina-s,0],
[-sina/2-s,sqrt3*cosa/2],
[-sina/2-s,-sqrt3*cosa/2]];};
//
am=Math.sqrt(-4*p/3);
cm=-q*Math.sqrt(-27/(4*p))/p;
ca=Math.abs(cm);
if(ca>1){
if(cm>0) segno=1;
else if(0>cm) segno=-1;
else segno=0;
a=Math.log(ca+Math.sqrt(ca*ca-1))/3;
expa=Math.exp(a);
sina=segno*am*(expa-1/expa)/2;
cosa=segno*am*(expa+1/expa)/2;
return [[-cosa-s,0],
[cosa/2-s,-sqrt3*sina/2],
[cosa/2-s,sqrt3*sina/2]];};
// tre radici reali
a=Math.asin(cm)/3;
sina=am*Math.sin(a);
cosa=am*Math.cos(a);
return [[sina-s,0],
[-sina/2+sqrt3*cosa/2-s,0],
[-sina/2-sqrt3*cosa/2-s,0]];
};
//
polsol.cubicarobusta=function(poli){
// radici di polinomio di terzo grado con
// coefficienti reali. Calcolo preciso anche con
// termine noto molto piccolo.
var p,q,r,a,b,d,aa,bb,x1,x2,x3,rd,nr,psi;
var an,sn,qn,pn,segno;
if(3>poli.length) return [ [0,1],[0,1],[0,1] ];
if(Array.isArray(poli[2]))p=poli[2][0];
else{p=poli[2]};
if(Array.isArray(poli[1]))q=poli[1][0];
else{q=poli[1]};
if(Array.isArray(poli[0]))r=poli[0][0];
else{r=poli[0]};
// alert("In cubicarobusta"+" p= "+p+" q= "+q+" r= "+r);
a=(p*p-3*q)/9;
b=(p*(9*q-2*p*p)-27*r)/54;
d=b*b-a*a*a;
//
sn=p/3;
qn=r-sn*(q-sn*(p-sn));
pn=q-sn*(2*p-3*sn);
if(0>=pn*pn){
// cubo perfetto, tre radici coincidenti !
if(qn>0) segno=1;
else if(0>qn) segno=-1;
else segno=0;
an=segno*Math.pow(Math.abs(qn),1/3)-sn;
return [[an,0],[an,0],[an,0]];};
with(Math){
if(0>d) { // Tre radici reali
rd=sqrt(-d);
nr=sqrt(-d+b*b);
if(abs(b)>rd) {
psi=asin(rd/nr);
if(0>b) psi=PI-psi;
}
else psi=acos(b/nr);
aa=pow(nr,1/3);
bb=aa*sin(psi/3);
aa=aa*cos(psi/3);
x1=2*aa-p/3;
x2=bb*sqrt(3)-aa-p/3;
x3=-bb*sqrt(3)-aa-p/3;
//
if(!(!abs(x2)>abs(x1)
|| !abs(x3)>abs(x1))){
if(x2*x3!=0)x1=-r/(x2*x3);}
//
else if(!(!abs(x3)>abs(x2)
|| !abs(x1)>abs(x2))){
if(x1*x3!=0)x2=-r/(x1*x3);}
//
else if(!(!abs(x1)>abs(x3)
|| !abs(x2)>abs(x3))){
if(x1*x2!=0)x3=-r/(x1*x2);}
// alert("Tre radici reali:\n"+x1+"\n"+x2+"\n"+x3);
return [ [x1,0], [x2,0], [x3,0] ]
}
else { // Una sola radice reale
if(b>0) {
aa = pow(sqrt(d)+b,1/3);
bb = a/aa;
}
else {
bb = -pow(sqrt(d)-b,1/3);
aa = a/bb;
}
x1=aa+bb-p/3;
x2=-0.5*(aa+bb)-p/3;
x3=-0.5*sqrt(3)*(aa-bb);
if(x2*x2+x3*x3>x1*x1) x1=-r/(x2*x2+x3*x3);
// alert("La radice reale e' una sola: "+x1);
return [ [x1, 0], [x2, x3], [x2,-x3] ];
};
};
};
//
// Equazione di quarto grado.
//
polsol.tetra=function(p){
// radici di polinomio di quarto grado con
// coefficienti reali.
var a,b,c,d,q,u,s,t,v,w,e,f,g,h,m,n;
if(Array.isArray(p[3]))a=p[3][0];
else{a=p[3]};
if(Array.isArray(p[2]))b=p[2][0];
else{b=p[2]};
if(Array.isArray(p[1]))c=p[1][0];
else{c=p[1]};
if(Array.isArray(p[0]))d=p[0][0];
else{d=p[0]};
q=[[4*d*b-c*c-d*a*a,0],[c*a-4*d,0],[-b,0]];
if(polsol.tartaglia >0)u=polsol.cubica(q);
else u=polsol.cubicabis(q);
s=a*a/4+u[0][0]-b;
t=u[0][0]*u[0][0]/4-d;
with(Math){
v=abs(s); w=abs(t);
if(w>v) {
w=sqrt(w);
v=(a*u[0][0]-2*c)/(4*w);
}
else if(v>w) {
t=s;
v=sqrt(v);
w=(a*u[0][0]-2*c)/(4*v);
}
}
if(t >= 0) {
e=[u[0][0]/2-w,0];
f=[u[0][0]/2+w,0];
g=[a/2-v,0];
h=[a/2+v,0];
}
else {
e=[u[0][0]/2,w];
f=[u[0][0]/2,-w];
g=[a/2,-v];
h=[a/2,v];
}
m=polsol.secondogrado([e,g]);
n=polsol.secondogrado([f,h]);
return [n[0],n[1],m[0],m[1]];
};
//
polsol.tetrarobusta=function(p){
//
// radici di polinomio di quarto grado con
// coefficienti reali. Tratta bene il caso
// del termine noto quasi nullo.
//
var a,b,c,d,q,r,s,t,u,v,w,e,f,g,h,m,n;
if(Array.isArray(p[3]))a=p[3][0];
else{a=p[3]};
if(Array.isArray(p[2]))b=p[2][0];
else{b=p[2]};
if(Array.isArray(p[1]))c=p[1][0];
else{c=p[1]};
if(Array.isArray(p[0]))d=p[0][0];
else{d=p[0]};
//
// Correzione empirica per evitare situazioni critiche.
// Se d valesse esattamente 0 l'equazione sarebbe di
// terzo grado e una radice nulla e se d valesse
// esattamente 1 potrebbe essere una quarta potenza
// della equazione z=1 cioe' quattro radici coincidenti
// e problema simile se d valesse esattamente -1.
// COMUNQUE IN QUESTI CASI SI OTTENGONO PRECISIONI PESSIME...
// LE SOLUZIONI ANDREBBERO RAFFINATE ITERATIVAMENTE...
//
if(1.e-16>Math.abs(d))d=1.e-16;
if(5.e-16>Math.abs(d-1))d=1+5.e-16;
if(5.e-16>Math.abs(d+1))d=-1+5.e-16;
//
q=[[4*d*b-c*c-d*a*a,0],[c*a-4*d,0],[-b,0]];
if(polsol.tartaglia >0)u=polsol.cubicarobusta(q);
else u=polsol.cubicabis(q);
// alert("Trovo prima radice "+u[0]);
r=u[0][0];
with(Math){
if(!(!(0>=abs(u[1][1]))
|| !(abs(u[1][0]) > abs(r)) )) r=u[1][0];
if(!(!(0>=abs(u[2][1]))
|| !(abs(u[2][0]) > abs(r)) )) r=u[2][0];
//
s=a*a/4+r-b;
t=r*r/4-d;
v=abs(s); w=abs(t);
if(w>v) {
w=sqrt(w);
v=(a*r-2*c)/(4*w);
}
else if(v>w) {
v=sqrt(v);
w=(a*r-2*c)/(4*v);
}
if( abs(r/2-w) > abs(r/2+w) ) {
e=[r/2-w,0];
f=[d/e[0],0];
}
else if( abs(r/2+w) > abs(r/2-w) ) {
f=[r/2+w,0];
e=[d/f[0],0];
}
else {
e=[r/2-w,0];
f=[r/2+w,0];
}
g=[a/2-v,0];
h=[a/2+v,0];
}
m=polsol.secondogrado([e,g]);
n=polsol.secondogrado([f,h]);
return [n[0],n[1],m[0],m[1]];
};
//
// Se si usa questa funzione fa prove a caso delle varie funzioni della libreria polsol
//
polsol.provacaso=function(){
var j,n,z,xbr,poli=[],zeri=[];
var casi=[[2,polsol.secondogrado],
[3,polsol.cubica],[3,polsol.cubicabis],
[3,polsol.cubicarobusta],[4,polsol.tetra],
[4,polsol.tetrarobusta]];
xbr="\u003cbr/\u003e";
n=Math.round(100*Math.random())%casi.length;
for(j=0;casi[n][0]>j;j++)poli[j]=
[Math.round(2000*Math.random()-1000),0];
if(n==0)poli[0][1]=Math.round(2000*Math.random()-1000);
polsol.tartaglia=1-2*(Math.round(100*Math.random())%2);
z=casi[n][1](poli);
for(j=0;casi[n][0]>j;j++){
zeri[j]=polsol.polinomio(poli,z[j])
}
return (xbr+"Esempio "+n+xbr+
"Polinomio: "+poli.join(";"+xbr)+
xbr+"Radici: "+z.join("; "+xbr)+
xbr+"Primo Zero: "+
zeri.join(xbr+"Altro Zero: ") );
}
//
//