Studio di funzioni ellittiche
! ! Mio modo di calcolare le funzioni ellittiche di Jacobi. ! qui lavoro solo con dati reali. I valori con arg. ! complessi sono deducibili da quelli con arg. reali. ! ! I risultati vengono confrontati con la libreria IMSL che, ! mi sembra, AHIME', commettere degli errori quando il ! parametro m e' negativo. ! ! Il caso di m negativo e' piuttosto insolito e questo ! forse giustifica quello che ritengo un baco dell'IMSL. ! Oppure bisogna reputare che le formule dell' Abramowitz ! Stegun siano errate, il che sarebbe un fatto grave ! che incrinerebbe la credibilita' dell glorioso ! "Handbook of mathematical functions". ! ! Un indizio che sia l'IMSL a sbagliare e' il fatto che ! per m prossimo a zero, l'approssimazione in termini ! di funzioni circolari, per m negativo e' in disaccordo ! con quanto si ottiene con l'IMSL mentre e' in buon ! accordo con quanto si ottiene dalle formule ! dell' Abramowitz. ! ! Per u ed m piccoli infatti, approssimativamente: ! ! sn(u,m) = sin(u)-m*(u-sin(u)*cos(u))*cos(u)/4 ! cn(u,m) = cos(u)+m*(u-sin(u)*cos(u))*sin(u)/4 ! dn(u,m) = 1 - m*sin(u)*sin(u)/2 ! ! E le formule dell'Abramowitz concordano bene sia ! per m piccolo negativo che positivo.... ! ! Comunque ho realizzato anche una subroutine che ! calcola le funzioni ellittiche usando formule integrali ! canoniche ed anche essa conferma che l'errore e' nella ! libreria IMSL. ! ! Prendo l'occasione per evidenziare la formula che ho ! usato per integrare. Divido l'intervallino in 12 ! parti e calcolo la funzione integranda solo nei ! punti dispari. Poi sommo con pesi opportuni ossia ! uso la formula ! ! I = (247*f(1)+139*f(3)+254*f(5)+254*f(7)+ ! 139*f(9)+247*f(11))*delta/1280 ! ! Se la funzione e' regolare questa formula fornisce ! ottimi risultati numerici ed inoltre ha il pregio ! di non richiedere il calcolo della funzione ! integranda negli estremi dell'intervallo e pertanto ! possono essere integrate funzioni che vanno ! anche all'infinito negli estremi, purche' le ! funzioni siano veramente integrabili... ! module xscd implicit none contains subroutine agm(n,a,b,c,p) integer,intent(out)::n real(8),intent(in out),dimension(0:)::a,b,c real(8),optional,intent(in)::p real(8)::prec integer::j,ns ns=size(a,1) if(present(p)) then prec=abs(p) else prec=1.0d-14 end if passo: do j=0,ns-2 n=j+1 a(n)=a(j)+b(j) b(n)=sqrt(4.d0*a(j)*b(j)) c(n)=a(j)-b(j) if(prec>abs(c(n))) then exit passo end if end do passo return end subroutine agm ! recursive subroutine scd(snr,cnr,dnr,unr,pm) real(8),intent(in)::unr,pm real(8),intent(out)::snr,cnr,dnr real(8),dimension(0:100)::a,b,c real(8):: f,fh,se,cs,upm,pmm,sqm integer:: j,n if(1.d-9>abs(pm-1.d0)) then f=1.0d0-pm se=sinh(unr) cs=cosh(unr) snr= se/cs +0.25d0*f*(se*cs-unr)/(cs*cs) cnr=1.d0/cs-0.25d0*f*(se*cs-unr)*se/(cs*cs) dnr=1.d0/cs+0.25d0*f*(se*cs+unr)*se/(cs*cs) return else if(1.d-10>abs(pm)) then se=sin(unr) cs=cos(unr) snr=se-0.25d0*pm*(unr-se*cs)*cs cnr=cs+0.25d0*pm*(unr-se*cs)*se dnr=1.d0-0.5d0*pm*se*se return else if(pm>1.0d0) then upm=1.0/pm sqm=sqrt(pm) call scd (snr,cnr,dnr,unr*sqm,upm) snr=snr/sqm f=dnr dnr=cnr cnr=f return else if (0.d0>pm) then pmm=-pm upm=1.0d0/(1.0d0+pmm) sqm=sqrt(upm) call scd (snr,cnr,dnr,unr/sqm,pmm*upm) dnr=1.0d0/dnr cnr=cnr*dnr snr=snr*dnr*sqm return end if a(0)=1.0d0 b(0)=sqrt(a(0)-pm) c(0)=sqrt(pm) call agm(n,a,b,c) f=a(n)*unr if(n > 10) then write(*,*) "n=",n end if do j=n,1,-1 fh=f f=0.5d0*(asin(c(j)*sin(f)/a(j))+f) end do snr=sin(f) cnr=cos(f) dnr=cnr/cos(fh-f) return end subroutine scd end module xscd ! module integro implicit none ! ! Applica il modo INTEGRALE per calcolare le ! funzioni ellittiche. ! contains ! subroutine trova_u(s,c,d,u,fi,pm,nstep) ! ! s=sn(u,pm) ; c=cn(u,pm) ; d=dn(u,pm) ! ! ma u, a sua volta non e' indipendente ma ! dipende da fi. ! real(8),intent(out)::s,c,d,u integer,intent(in):: nstep real(8),intent(in):: fi,pm real(8):: delta,delta6,delta12,t integer::j if(0.d0>=abs(fi)) then u=0.d0 return end if delta=fi/nstep u=0.d0 delta12=delta/12.d0 delta6=2.0d0*delta12 ! ! Passi di integrazione... ! do j=0,nstep-1 t=j*delta +delta12 u= u+ 247.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) t=t+delta6 u= u+ 139.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) t=t+delta6 u= u+ 254.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) t=t+delta6 u= u+ 254.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) t=t+delta6 u= u+ 139.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) t=t+delta6 u= u+ 247.0d0*delta/sqrt(1.d0-pm*sin(t)*sin(t)) end do u=u/1280.0d0 s=sin(fi) c=cos(fi) d=sqrt(1-pm*s*s) return end subroutine trova_u ! end module integro ! program testscd use msimsl use xscd use integro implicit none real(8):: snr,cnr,dnr,unr,pm,fi real(8):: s,c,d,vmax=1.0d-2 real(8)::imsl_sn,imsl_cn,imsl_dn integer::j,k write(unit=*,fmt=*) & "Verifica delle formule dell'Abramowitz-Stegun sulle" write(unit=*,fmt=*) & "funzioni ellittiche jacobiane." write(unit=*,fmt=*) & "Viene usata anche la libreria IMSL che pero' risulta" write(unit=*,fmt=*) & "errata !!!! quando il valore del parameto pm e' negativo" write(unit=*,fmt=*) " " studio:do write(unit=*,fmt=*) & "Assegna pm (parametro delle sn(u,pm) etc...: 0==fine) " read(unit=*,fmt=*) pm if(0.d0>= abs(pm) ) then exit studio end if write(unit=*,fmt=*) "Lavora con",pm do j=1,20 fi=j*0.1d0 if(1.0d0 -pm > vmax) then call trova_u(s,c,d,unr,fi,pm,50) else unr=fi d=0.0 end if call scd (snr,cnr,dnr,unr,pm) imsl_sn=dejsn(unr,pm) imsl_cn=dejcn(unr,pm) imsl_dn=dejdn(unr,pm) write(unit=*,fmt="(1x,g12.5,a,g12.5,a)") & unr," == u ; ",dnr-dejdn(unr,pm)," == diff. da IMSL" if(1.0d0 - pm > vmax) then write(unit=*,fmt="(1x,g12.5,a,g12.5,a,g12.5,a)") & snr," == sn(u); ",s," == test; ",snr-s," == sn(u)-test " end if end do end do studio write(unit=*,fmt=*) "Le funzioni dejsn(x,m), dejcn(x,m), dejdn(x,m)" write(unit=*,fmt=*) "della libreria IMSL acclusa al Digital Visual" write(unit=*,fmt=*) "Fortran. versione 5, per m negativo.... sono" write(unit=*,fmt=*) "dunque bacate !!!!! :-( " write(unit=*,fmt=*) " " write(unit=*,fmt=*) "Amen. Invia...." read(unit=*,fmt=*) stop end program testscd ! !E-mail: Johan' PaĆlo Butonoj,
gpbottoni[chiocciola]gmail.com
Ultima modifica: 18/Feb/109