!Microlibreria di algebra modulare

Microlibreria di algebra modulare programmata in Fortran 95

Attenzione: questo è un sorgente Fortran compilabile senza modifiche con il gratuito Fortran Silverfrost o con l'altrettanto gratuito G95 ma anche non il non gratuito ma molto professionale compilatore INTEL Visual Fortran

Vedere: http://www.elegio.it/doc/tn/ ed in particolare la pagina http://www.elegio.it/doc/tn/altaprecisione_modulare.html
module algebramodulare
    implicit none
    !
    integer,parameter::cifre=4   ! == elementi del vettore usato
    integer,parameter::cifrx=9   ! == potenza del 10 della base (il max e' 15)
    !
    integer,parameter::q=selected_real_kind(15,300)
    real(kind=q),parameter::basecifre=10.0_q**min(cifrx,15)
    type,public::zahlen
        !private
        real(kind=q),dimension(0:cifre-1)::z
    end type zahlen
    type(zahlen):: zahlenmod
    !
    interface assignment(=)
        module procedure zahlcost,zahlvet,zahlivet,stringazahlen,numerone
    end interface
    interface operator(+)
        module procedure fisomcomod,fi2somcomod,frsomcomod,fr2somcomod
        module procedure fsommamod
    end interface
    interface operator(-)
        module procedure fidifcomod,fi2difcomod,frdifcomod,fr2difcomod
        module procedure fdiffemod
    end interface
    interface operator(*)
        module procedure prodotto
    end interface
    interface operator(**)
        module procedure potenza
    end interface
    !
    private:: zahlcost,zahlvet,zahlivet,stringazahlen,numerone, &
              fisomcomod,fi2somcomod,frsomcomod,fr2somcomod, &
              fsommamod, &
              fidifcomod,fi2difcomod,frdifcomod,fr2difcomod, &
              fdiffemod,prodotto,potenza
              !
    public:: inizahlen,somcomod,sommamod,difcomod,diffemod,nonzero,nonuno, &
             menuno,dimezzo,numeropari,trascrivo
    !
contains
    subroutine inizahlen()
        zahlenmod%z=0.0_q
        zahlenmod%z(cifre-1)=1.0_q
        return
    end subroutine inizahlen
    !
    subroutine zahlcost(z,j)
        integer,intent(in)::j
        type(zahlen),intent(out)::z
        z%z(0:)=0.0_q
        z%z(0)=j
        z%z(0)=modulo(z%z(0),basecifre)
        return
    end subroutine zahlcost
    !
    subroutine zahlvet(z,v)
        real(kind=q),dimension(0:),intent(in)::v
        type(zahlen),intent(out)::z
        integer::j       
        z%z(0:)=0.0_q
        do j=0,size(v,1)-1
            z%z(j)=modulo(v(j),basecifre)
        end do
        return
    end subroutine zahlvet
    !
    subroutine zahlivet(z,iv)
        integer,dimension(0:),intent(in)::iv
        type(zahlen),intent(out)::z
        integer::j       
        z%z(0:)=0.0_q
        do j=0,size(iv,1)-1
            z%z(j)=iv(j)
            z%z(j)=modulo(z%z(j),basecifre)
        end do
        return
    end subroutine zahlivet
    !
    subroutine numerone(z,str)
        character(len=*),intent(in)::str
        type(zahlen),intent(out)::z
        real(kind=q)::qe
        integer::j,m,n,kk
        character(len=len(str))::s
        do j=0,cifre-1
            z%z(j)=0
        end do
        n=0
        s=" "
        do j=1,len(str)
            m=ichar(str(j:j))
            if(m>32) then
                n=n+1
                s(n:n)=char(m)
            end if
        end do
        if(n==0) return
        qe=1.0_q
        kk=0
        do j=n,1,-1
            z%z(kk)=z%z(kk)+modulo(ichar(s(j:j))+2,10)*qe
            qe=qe*10.0_q
            if(qe>=basecifre) then
                qe=1.0_q
                kk=min(kk+1,cifre-1)
            end if
        end do
        return
    end subroutine numerone
    !
    subroutine stringazahlen(str,z)
        type(zahlen),intent(in)::z
        character(len=*),intent(out)::str
        character(len=cifre*cifrx)::testo
        real(kind=q)::zz
        integer::j,k,n,p,np
        p=0
        do j=0,cifre-1
            zz=z%z(j)
            do k=1,cifrx
                p=p+1
                n=modulo(zz,10.0_q)
                testo(p:p)=char(48+n)
                zz=(zz-n)/10.0_q
                if(n>0) np=p
            end do
        end do
        k=min(len(str),np)
        str=" "
        do j=1,k
            str(j:j)=testo(k+1-j:k+1-j)
        end do
        if(1>len_trim(str)) str="0"
        return
    end subroutine stringazahlen
    !
    function fisomcomod(z,c)result(s)
        type(zahlen),intent(in)::z
        integer,intent(in)::c
        type(zahlen)::s
        real(kind=q)::zz
        zz=c
        call somcomod(s%z,z%z,zz)
        return
    end function fisomcomod
    !
    function fi2somcomod(c,z)result(s)
        type(zahlen),intent(in)::z
        integer,intent(in)::c
        type(zahlen)::s
        real(kind=q)::zz
        zz=c
        call somcomod(s%z,z%z,zz)
        return
    end function fi2somcomod
    !
    function frsomcomod(z,zz)result(s)
        type(zahlen),intent(in)::z
        real(kind=q),intent(in)::zz
        type(zahlen)::s
        call somcomod(s%z,z%z,zz)
        return
    end function frsomcomod
    !
    function fr2somcomod(zz,z)result(s)
        type(zahlen),intent(in)::z
        real(kind=q),intent(in)::zz
        type(zahlen)::s
        call somcomod(s%z,z%z,zz)
        return
    end function fr2somcomod
    !
    subroutine somcomod(sz,vz,a)
        real(kind=q),dimension(0:),intent(in)::vz
        real(kind=q),intent(in)::a
        real(kind=q),dimension(0:),intent(out)::sz
        real(kind=q)::rcs
        integer::j
        rcs=min(abs(a),basecifre-1.0_q)
        do j=0,cifre-1
            sz(j)=rcs+vz(j)-zahlenmod%z(j)
            if(sz(j)>=basecifre) then
                sz(j)=sz(j)-basecifre
                rcs=1.0_q
            else if(0>sz(j)) then
                sz(j)=sz(j)+basecifre
                rcs=-1.0_q
            else
                rcs=0.0_q
            end if
        end do
        if(0>rcs) then
            rcs=0.0_q
            do j=0,cifre-1
                sz(j)=sz(j)+rcs+zahlenmod%z(j)
                if(sz(j)>=basecifre) then
                    sz(j)=sz(j)-basecifre
                    rcs=1.0_q
                else
                    rcs=0.0_q
                end if
            end do
        end if    
        return
    end subroutine somcomod
    !
    function fsommamod(z,zz)result(s)
        type(zahlen),intent(in)::z,zz
        type(zahlen)::s
        call sommamod(s%z,z%z,zz%z)
        return
    end function fsommamod
    !
    subroutine sommamod(sz,vz,wz)
        real(kind=q),dimension(0:),intent(in)::vz,wz
        real(kind=q),dimension(0:),intent(out)::sz
        real(kind=q)::rcs
        integer::j
        rcs=0.0_q
        do j=0,cifre-1
            sz(j)=rcs+vz(j)+wz(j)-zahlenmod%z(j)
            if(sz(j)>=basecifre) then
                sz(j)=sz(j)-basecifre
                rcs=1.0_q
            else if(0>sz(j)) then
                sz(j)=sz(j)+basecifre
                rcs=-1.0_q
            else
                rcs=0.0_q
            end if
        end do
        if(0>rcs) then
            rcs=0.0_q
            do j=0,cifre-1
                sz(j)=sz(j)+rcs+zahlenmod%z(j)
                if(sz(j)>=basecifre) then
                    sz(j)=sz(j)-basecifre
                    rcs=1.0_q
                else
                    rcs=0.0_q
                end if
            end do
        end if    
        return
    end subroutine sommamod
    !
    function fidifcomod(z,c)result(s)
        type(zahlen),intent(in)::z
        integer,intent(in)::c
        type(zahlen)::s
        real(kind=q)::zz
        zz=c
        call difcomod(s%z,z%z,zz)
        return
    end function fidifcomod
    !
    function fi2difcomod(c,z)result(s)
        type(zahlen),intent(in)::z
        integer,intent(in)::c
        type(zahlen)::ss,s
        real(kind=q)::zz
        call diffemod(ss%z,zahlenmod%z,z%z)
        zz=c
        call somcomod(s%z,ss%z,zz)
        return
    end function fi2difcomod
    !
    function frdifcomod(z,zz)result(s)
        type(zahlen),intent(in)::z
        real(kind=q),intent(in)::zz
        type(zahlen)::s
        call difcomod(s%z,z%z,zz)
        return
    end function frdifcomod
    !
    function fr2difcomod(zz,z)result(s)
        type(zahlen),intent(in)::z
        real(kind=q),intent(in)::zz
        type(zahlen)::s,ss
        call diffemod(ss%z,zahlenmod%z,z%z)
        call somcomod(s%z,ss%z,zz)
        return
    end function fr2difcomod
    !
    subroutine difcomod(sz,vz,a)
        real(kind=q),dimension(0:),intent(in)::vz
        real(kind=q),intent(in)::a
        real(kind=q),dimension(0:),intent(out)::sz
        real(kind=q)::rcs
        integer::j
        rcs=min(-abs(a),basecifre-1.0_q)
        do j=0,cifre-1
            sz(j)=rcs+vz(j)
            if(0>sz(j)) then
                sz(j)=sz(j)+basecifre
                rcs=-1.0_q
            else
                rcs=0.0_q
            end if
        end do
        if(0>rcs) then
            rcs=0.0_q
            do j=0,cifre-1
                sz(j)=sz(j)+rcs+zahlenmod%z(j)
                if(sz(j)>=basecifre) then
                    sz(j)=sz(j)-basecifre
                    rcs=1.0_q
                else
                    rcs=0.0_q
                end if
            end do
        end if    
        return
    end subroutine difcomod
    !
    function fdiffemod(z,zz)result(s)
        type(zahlen),intent(in)::z,zz
        type(zahlen)::s
        call diffemod(s%z,z%z,zz%z)
        return
    end function fdiffemod
    !
    subroutine diffemod(sz,vz,wz)
        real(kind=q),dimension(0:),intent(in)::vz,wz
        real(kind=q),dimension(0:),intent(out)::sz
        real(kind=q)::rcs
        integer::j
        rcs=0.0_q
        do j=0,cifre-1
            sz(j)=rcs+vz(j)-wz(j)
            if(0>sz(j)) then
                sz(j)=sz(j)+basecifre
                rcs=-1.0_q
            else
                rcs=0.0_q
            end if
        end do
        if(0>rcs) then
            rcs=0.0_q
            do j=0,cifre-1
                sz(j)=sz(j)+rcs+zahlenmod%z(j)
                if(sz(j)>=basecifre) then
                    sz(j)=sz(j)-basecifre
                    rcs=1.0_q
                else
                    rcs=0.0_q
                end if
            end do
        end if    
        return
    end subroutine diffemod
    !
    function nonzero(z)result(f)
        type(zahlen),intent(in)::z
        logical::f
        integer::j
        do j=cifre-1,0,-1
            if(abs(z%z(j))>0.0_q) then
                f=.true.
                return
            end if
        end do
        f=.false.
        return
    end function nonzero
    !
    function nonuno(z)result(f)
        type(zahlen),intent(in)::z
        logical::f
        integer::j
        do j=cifre-1,1,-1
            if(z%z(j)>0.0_q) then
                f=.true.
            end if
        end do
        f=(z%z(0)-1.0_q)>0.0_q
        return
    end function nonuno
    !
    function menuno(z)result(f)
        type(zahlen),intent(in)::z
        logical :: f
        integer::j
        f=.true.
        do j=cifre-1,1,-1
            if(abs(z%z(j)-zahlenmod%z(j))>0.0_q) then
                f=.false.
                return
            end if
        end do
        if(abs(z%z(0)-zahlenmod%z(0)+1.0_q)>0.0_q ) then
            f=.false.
        end if
        return
    end function menuno 
    !
    subroutine dimezzo(pari,z)
        type(zahlen),intent(in out)::z
        logical,intent(out)::pari
        real(kind=q)::res
        integer::j
        res=0.0_q
        do j=cifre-1,0,-1
            z%z(j)=z%z(j)+res
            if(modulo(z%z(j),2.0_q)>0.0_q) then
                z%z(j)=(z%z(j)-1.0_q)/2.0_q
                res=basecifre
            else
                z%z(j)=z%z(j)/2.0_q
                res=0.0_q
            end if
        end do
        pari=0.0_q>=res
        return
    end subroutine dimezzo
    !
    function numeropari(z)result(f)
        type(zahlen),intent(in)::z
        logical::f
        f=0.0_q>=modulo(z%z(0),2.0_q)
        return
    end function numeropari
    !
    subroutine trascrivo(z,a)
        type(zahlen),intent(in)::a
        type(zahlen),intent(out)::z
        integer::j
        do j=cifre-1,0,-1
            z%z(j)=modulo(a%z(j),basecifre)
        end do
        return
    end subroutine trascrivo
    !
    function prodotto(aa,bb)result(vs)
        type(zahlen),intent(in):: aa,bb
        type(zahlen)::vs
        type(zahlen)::as,bs
        logical::pari
        call trascrivo(as,aa)
        call trascrivo(bs,bb)
        vs=0
        do
            call dimezzo(pari,as)
            if(.not.pari) then
                vs=vs+bs
            end if
            bs=bs+bs
            if(.not.nonzero(as)) exit
        end do 
    end function prodotto
    !
    function potenza(aa,n)result(vp)
        type(zahlen),intent(in):: aa,n
        type(zahlen)::vp
        type(zahlen)::bp,mp
        logical::pari
        call trascrivo(bp,aa)
        call trascrivo(mp,n)
        vp=1
        do
            call dimezzo(pari,mp)
            if(.not.pari) then
                vp=bp*vp
            end if
            bp=bp*bp
            if(.not.nonzero(mp)) exit
        end do 
    end function potenza
    !
    function pseudoprimoforte(a,n)result(f)
        type(zahlen),intent(in)::a,n
        logical::f,pari
        type(zahlen)::sb,vp,nn
        integer::j
        call trascrivo(nn,zahlenmod)
        call trascrivo(zahlenmod,n)
        call trascrivo(sb,n)
        sb=n-1
        j=0
        do 
            j=j+1
            vp=sb
            call dimezzo(pari,sb)
            if(.not.pari) then
                sb=vp
                exit
            end if
        end do
        vp=a**sb
        f=.not.nonuno(vp)
        if(f) then
            call trascrivo(zahlenmod,nn)
            return
        end if
        do
            f=menuno(vp)
            if(f) exit
            sb=sb+sb
            vp=vp*vp
            j=j-1
            if(0>j) exit
        end do
        call trascrivo(zahlenmod,nn)
        return
    end function pseudoprimoforte
    !
    subroutine controllo_pseudoprimoforte()
        type(zahlen)::a,mm
        character(79):: ilnumero
        integer::k
        write(*,*)"Assegna il possibile numero primo"
        read(*,"(1a)") ilnumero
        if(1>len_trim(ilnumero)) return
        mm=ilnumero
        ilnumero=mm
        write(*,*)"Analizza il numero:"
        write(*,*) ilnumero
        ilnumero=" "
        k=2
        do
            a=k
            if(pseudoprimoforte(a,mm) ) then
                write(*,*)"Con la base",k," il numero sembra primo"
            else
                write(*,*)"Con la base",k," numero NON PRIMO"
            end if
            k=2*((k+1)/2)+1
            write(*,*)"Digita 0 per finire"
            read(*,"(1a)") ilnumero
            if(ilnumero(1:1)=="0") exit
        end do
        return
    end subroutine controllo_pseudoprimoforte
    !
    subroutine cercagermain()
        type(zahlen)::a,uno,due,tre,cinque,mm,poi
        character(79):: ilnumero
        integer::k,nl,tot
        logical::siono
        character(len=*),parameter::fs="almod-germain.txt"
        zahlenmod%z(:)=0.0_q
        zahlenmod%z(cifre-1)=basecifre/10.0_q
        !
        tot=0
        uno=1
        due=2
        tre=3
        cinque=5
        !
        write(*,*)"Catene di primi di Sophie Germain"
        write(*,*)" "
        write(*,*)"Numeri notevoli trovati con questo programma"
        write(*,*)"Livello 6: 89,63419,127139,405269,810809,...,181774409"
        write(*,*)"Livello 7: 1122659,...,183561929"
        write(*,*)"Livello 8: 19099919"
        write(*,*)"Livello 9: 85864769"
        write(*,*)" "
        write(*,*)"Assegna il numero dispari di partenza:"
        read(*,"(1a)") ilnumero
        mm=ilnumero
        ilnumero=mm
        write(*,*)"Inizia dal numero:"
        write(*,*) ilnumero
        write(*,*)"Quanti livelli di Sophie Germain:"
        read(*,*) nl
        if(1>nl) return
        nl=max(1,nl)
        open(file=fs,unit=12,status="replace",action="write")
        write(12,*)"Ricerca fino al livello",nl
        close(unit=12)
        write(*,*)"Ora indaga e si arresta quando lo trova: invia per iniziare"
        read(*,*)
        do
            poi=mm
            controllo:do k=1,nl
                ! ilnumero=poi
                ! write(*,*)"Controllo passo:",k
                ! write(*,*) ilnumero
                siono=pseudoprimoforte(due,poi)
                if(.not.siono) exit controllo
                siono=pseudoprimoforte(tre,poi)
                if(.not.siono) exit controllo
                siono=pseudoprimoforte(cinque,poi)
                if(.not.siono) exit controllo
                poi=poi*due
                poi=poi+uno
                if(k>max(2,nl-6)) then
                    ilnumero=mm
                    open(file=fs,unit=12,status="replace",action="write",&
                         position="append")
                    write(12,*)"Livello ",k
                    write(12,*) ilnumero
                    close(12)
                end if
            end do controllo
            if(siono) then
                ilnumero=mm
                write(*,*)"Pseudoprimo di SF di livello ",nl
                write(*,*) ilnumero
                open(file=fs,unit=12,status="replace",action="write",&
                     position="append")
                write(12,*)"Pseudoprimo di SF di livello ",nl
                write(12,*) ilnumero
                close(12)
                write(*,*)"Digita 1 per proseguire, altrimenti smetto..."
                read(*,*) k
                if(k/=1) exit
            end if
            mm=mm+2
            tot=tot+1
            if(modulo(tot,100000)==0)  then
                 ilnumero=mm
                 write(*,*) ilnumero
                 tot=1
            end if
        end do
        return
    end subroutine cercagermain
    !
end module algebramodulare
!
program almod
    use algebramodulare
    implicit none
    character(len=78)::stringona
    type(zahlen)::a,b,c
    call inizahlen()
    !
    zahlenmod="100000"
    stringona=zahlenmod 
    do 
        call controllo_pseudoprimoforte()
        write(*,*)"....... digita 0 per finire ....."
        read(*,"(1a)") stringona
        if(stringona(1:1)=="0") exit     
    end do     
    call cercagermain()   
    write(*,*)"Amen"
    read(*,*)
    stop
end program almod
!