!
module pi_pezzi
!
! Applica il metodo di estrazione delle cifre, recentemente scoperto
! per calcolare il gruppo di cifre di pi_greco che si desidera.
! Si possono trovare 2**24 ossia circa 16 milioni di cifre di pi_greco,
! un pezzettino alla volta e senza dover calcolare le precedenti....
! Notare che trova l'espressione di pi_greco in cifre esadecimali
! e quindi in cifre binarie. Non e' attualmente nota una formula
! che calcoli le cifre decimali di pi_greco e quindi, per trovare
! la, mettiamo, milionesima cifra decimale di pi_greco occorre tuttora
! conoscere tutte le cifre prima. In esadecimale invece no!
! La milionesima cifra dopo la virgola e' 2 ed e' sia preceduta
! che seguita dalla cifra 6.
!
implicit none
integer,public,parameter:: ntp=25
integer,public,parameter::pr=selected_real_kind(12,300)
real(kind=pr),public,dimension(ntp) :: tp = 0.0_pr
real(kind=pr),public,parameter:: eps = 1.0e-17_pr
character(len=*),public,parameter,dimension(0:15):: hx = (/ "0", "1", &
"2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", &
"D", "E", "F" /)
private:: xexpm
public:: xseries,ihex
!
contains
!
subroutine ihex (x, nhx, chx)
!
! Il risultato e' la stringa chx che contiene nhx cifre
! esadecimali della parte frazionaria di x.
!
real(kind=pr),intent(in) :: x
real(kind=pr) :: y
integer,intent(in) :: nhx
integer :: i
character(len=*),dimension(1:),intent(out):: chx
!
y = abs (x)
do i = 1, nhx
y = 16.0_pr * (y - aint (y))
chx(i) = hx(int(y))
end do
return
end subroutine ihex
!
subroutine xseries ( series, m, ic)
!
! Questa funzione calcola la serie : sommatoria, indice k,
! di 16**(ic-k)/(8*k+m) usando la tecnica di esponentazione
! modulare.
!
real(kind=pr) :: ak, p, s, t
real(kind=pr),intent(out)::series
integer,intent(in) :: ic,m
integer :: k
!
s = 0.0_pr
!
! Somma le serie fino a ic.
!
do k = 0, ic - 1
ak = 8 * k + m
p = ic - k
call xexpm (t, p, ak)
s = modulo (s + t / ak, 1.0_pr)
end do
!
! Calcola un po' di termini dove k.ge.ic.
!
do k = ic, ic + 100
ak = 8 * k + m
t = 16.0_pr ** (ic - k) / ak
if (eps > t ) then
exit
end if
s = modulo (s + t, 1.0_pr)
end do
!
series = s
return
end subroutine xseries
!
subroutine xexpm(expm, p, ak)
!
! expm = mod( 16**p, ak). Questa funzione usa lo schema di
! esponentazione binario da sinistra a destra. E' valida per
! ogni ak non superiore a 2**24.
!
real(kind=pr),intent(in) :: p,ak
integer :: i
real(kind=pr),intent(out):: expm
real(kind=pr) :: p1, pt, r
integer::jexpm,jak !!!!
!
! Se questa e' la prima chiamata di expm, riempie la tabella
! di potenze di due tp.
!
if(0.0_pr >= tp(1)) then
tp(1) = 1.0_pr
do i = 2, ntp
tp(i) = 2.0_pr * tp(i-1)
end do
end if
!
if (0.0_pr >= abs(ak-1.0_pr) ) then
expm = 0.0_pr
return
end if
!
! Trova la piu' grande potenza di due minore o uguale a p.
!
do i = 1, ntp
if (tp(i) > p) then
exit
end if
end do
!
pt = tp(i-1)
p1 = p
r = 1.0_pr
!
! Attua l'algoritmo di esponenziazione binario modulo ak.
!
do
if (p1 >= pt) then
r = modulo(16.0_pr * r, ak)
p1 = p1 - pt
end if
pt = 0.5_pr * pt
if( 1.0_pr>pt) then
exit
end if
r = modulo(r * r, ak)
end do
!
expm = modulo (r, ak)
!
! Controllo che il risultato sia un intero:
!
jexpm=expm
jak=ak
if(abs(ak-jak)>0.0_pr) then
write(unit=*,fmt=*)"Residuo frazionario ak: ",ak,jak
read(unit=*,fmt=*)
end if
if(abs(expm-jexpm)>0.0_pr) then
write(unit=*,fmt=*)"Residuo frazionario expm: ",expm,jexpm
read(unit=*,fmt=*)
end if
return
end subroutine xexpm
!
end module pi_pezzi
!
! ------------------------------------------------------------------
!
program piqp
!
use pi_pezzi
implicit none
real(kind=pr) :: pid, s1, s2, s3, s4
integer :: ic,k
integer,parameter :: nhx = 12
character(len=1),dimension(nhx):: chx
!
! ic rappresenta la posizione della ultima cifra esadecimale considerata
! nota. Il risultato inizia alla cifra esadecimale ic+1_esima.
! Se si assegna ad es 10 si intende che si vuole dalla undicesima
! cifra inclusa in poi, dopo la virgola ossia si deve ottenere A308D...
!
write(unit=*,fmt=*)" Algoritmo di D.Bailey, P.Borwein e Simon Plouffe "
write(unit=*,fmt=*)"Trova le cifre esadecimali di Pi_greco senza dover"
write(unit=*,fmt=*)"conoscere quali sono quelle prima del punto di inizio."
write(unit=*,fmt=*)
do
assegnazione: do
write(unit=*,fmt=*) "Assegna da quale cifra ic (-1 per finire) "
read(unit=*,fmt=*) ic
if(2**24>ic) then
exit assegnazione
end if
end do assegnazione
if(0>ic) then
exit
end if
if(ic>100) then
write(unit=*,fmt=*) &
"Attendi, se hai chiesto un ic grande..."
end if
!
call xseries (s1, 1, ic)
call xseries (s2, 4, ic)
call xseries (s3, 5, ic)
call xseries (s4, 6, ic)
pid = modulo(4.0_pr * s1 - 2.0_pr * s2 - s3 - s4, 1.0_pr) + 1.0_pr
call ihex (pid, nhx, chx)
!
write(unit=*,fmt=*)" "
write(unit=*,fmt=*)"--Calcolo delle cifre esadecimali di Pi_greco--"
write(unit=*,fmt=*)" Le prime cifre esadecimali dovrebbero essere queste..."
write(unit=*,fmt=*)" 3.243F6 A8885 A308D 31319 8A2E0 37073 44A40 93822"
write(unit=*,fmt=*)"Posizione a partire da ",ic," + 1"
! write(unit=*,fmt=*)" ",pid
write(unit=*,fmt="(a)",advance="no")" "
do k=1,nhx
if(modulo(ic+k,5)==1) then
write(unit=*,fmt="(1a)",advance="no") " "
end if
write(unit=*,fmt="(1a)",advance="no") chx(k)
end do
write(unit=*,fmt=*)" "
end do
write(unit=*,fmt=*)"Amen..."
stop
end program piqp ! g95 -std=F pi-plouffe.f03 -o pi-plouffe.exe