Cosa succede con tre istruzioni in più?

di il
5 risposte

Cosa succede con tre istruzioni in più?

Ciao

Avrei bisogno di aiuto da parte di un programmatore esperto.

Il programma riportato qui sotto carica un file di numeri e lo pone dentro una matrice. Da questa matrice vengono estrapolati questi numeri che si aumentano di 6006 ogni qualvota la lettura arriva a fine matrice e riparte da capo

es. mat[0]=1, al secondo giro diventerà 6007, al terzo giro diventerà 12013 etc…

Ho messo un'asticella a 10 miliardi per sapere quanto ci mette a creare i primi 10 miliardi e poi i secondi e così via. Il tempo rilevato per ogni 10 miliardi è di 5,5 minuti. E fino a qui tutto bene.

Aggiungo queste quattro righe   a=nr%molt  (Divisione Modulare)                                                                                                                                                                                                       if a%2!=0 and molt-a<1000:                                                                                                                                                                                                                         b=molt

Aggiungento queste tre istruzioni il tempo per ogni 10 miliardi lievita a 11 minuti, praticamente il doppio.

Se qualche esperto mi sa dire del perchè queste tre righe in più complicano così tanto la vita a python lo ringrazio moltissimo.

Grazie                                                                                    

import time
import math
from datetime import datetime
now = datetime.now().time()
print("ora inizio =", now)
#************************
nr = 441000000000000000001
#**** numero di riferimento
limite=int(math.sqrt(nr))
print('Ricerca dal Numero','{:,}'.format(nr).replace(',', '.'),'Lunghezza',len(str(nr)))
print('Limite di Ricerca','{:,}'.format(limite).replace(',', '.'))
massimo=1000
limite2=int(massimo*1.3)
leggi=open('F:/programmi python/b6006/6006.txt','r')
np=[]
for i in range(10000):
    a=leggi.readline()
    if a=='' or a=='\n':
        leggi.close()
        break
    np.append (int(a))
np.append(0)
leggi.close()
tempo=100
agg=0
cont=1
start=time.process_time()
molt=0
while molt<=limite:
    if np[cont]==0:
        cont=0
        agg+=6006
    molt=np[cont]+agg
    if molt>tempo:
        end = time.perf_counter()
        print(molt,end-start)
        tempo+=10000000000
        start = time.perf_counter()
        
    #le 3 righe sopra descritte vanno aggiunte qui    
    
    cont=cont+1
now = datetime.now().time()
print("Fine Ricerca =", now)
                                                        

5 Risposte

  • Re: Cosa succede con tre istruzioni in più?

    Il modulo è un'operazione notoriamente lunga, il linguaggio non c'entra.

    Devi cercare di evitarlo, tipo scrivere a&1 invece di a%2!=0

  • Re: Cosa succede con tre istruzioni in più?

    No, non centra nulla la “lunghezza” (in tempo) dell'operazione modulo:

    1. per numeri macchina, l'operazione e' eseguita a livello di CPU
    2. l'infrastruttura fornita da Python compre abbondantemente le differenze di esecuzione tra una semplice somma e l'operazione modulo
    3. un IDIV, usato per calcolare il modulo, ha una latency di 10 rispetto ad un ADD che ha una latency di 1.


    https://uops.info/table.html

    Se fosse solo un problema di tempo di esecuzione dell'istruzione assembler, il tempo doveva essere 10 volte maggiore.

    Quindi, il tempo di esecuzione raddoppia per un motivo molto banale:
    il tempo di esecuzione di

    if a%2!=0 and molt-a<1000:  
        b=molt                                                                                                                                                                                                                  b=molt

    e' equivalente a 

    if np[cont]==0:
            cont=0
            agg+=6006
        molt=np[cont]+agg
        if molt>tempo:
            end = time.perf_counter()
            print(molt,end-start)
            tempo+=10000000000
            start = time.perf_counter()
            
        #le 3 righe sopra descritte vanno aggiunte qui    
        
        cont=cont+1

    se il primo blocco di codice richiede T secondi, il secondo T secondi, eseguire i due blocchi di codice richiedera' 2T secondi.

    .

    @claugoit capire perche' il codice impiega un certo tempo per eseguire un certo insieme di operazioni e' solo la PRIMA PARTE  del problema.
    La seconda parte e' capire come il tempo aumenta all'aumentare (o al diminuire) della dimensione del problema/dati.

    Per fare un esempio: SE per arrivare a 10 miliardi impiega 5.5 minuti, per arrivare a 5 miliardi impiega 2.25 minuti? Di piu'? Di meno?.

    Prova a fare qualche esperimento con questo codice:

    
    
    def timit(f, args):
        start = datetime.now()
        v = f(*args)
        return (v, datetime.now() - start)
    
    
    def fibonacci_r(n):
        if n == 0:
            return 0
        if n <= 2:
            return 1
        else:
            return fibonacci_r(n-1) + fibonacci_r(n-2)
    
    
    def fibonacci_i(n):
        p = 0
        c = 1
        for i in range(1, n+1):
            t = p
            p = c
            c = p + t
        return p
    
    
    for n in range(30, 35):
        v, time = timit(fibonacci_i, (n,))
        print(f"fibonacci_i({n})->{v} in {time}")
    
    for n in range(30, 35):
        v, time = timit(fibonacci_r, (n,))
        print(f"fibonacci_r({n})->{v} in {time}")
    

    .

    La domanda e': stanno lo stesso tempo per calcolare lo stesso valore? Si? No? Perche'?

  • Re: Cosa succede con tre istruzioni in più?

    Innanzi tutto grazie mille per aver risposto

    Di prove ne ho fatte tante e sul programma che ho postato ho eseguito anche la prova prova dei 5 miliardi anzichè 10 e mi ha restituito come tempo 3 minuti anzichè 2,25. Di fatto però aggiungendo una qualsiasi operazione, anche solo quella di a=nr%molt, mi aumenta il tempo del doppio. Inoltre devo dire che il tempo rimane costante anche a fronte di un numero sempre più grande e cioè ogni 10 miliardi o ogni 5 miliardi, il tempo rimane costante a 5,5 minuti e a 3 minuti 

    Ho provato perfino a riscrivere il programma nel linguaggio Julia(riportato sotto) per vedere la differenza di gestione del calcolo, ma è stato ancora peggio… 11 minuti senza nessun calcolo e 16 minuti con inserito le tre righe di calcolo.

    import Dates
    ora = Dates.Time(Dates.now())
    println("Inizio Ricerca ", ora)
    ni = 441000000000000000001
    #Numero di ricerca
    limite = isqrt(ni)
    lunghezza = length(string(ni))
    println("Numero di ricerca ", ni, " lunghezza ", lunghezza, " Limite ricerca ", limite)
    #*****************************
    leggi = open(string("F:/programmi python/b6006/6006.txt"), "r")
    mnassimo=1000
    np=[]
    cont=1
    while cont==1
        a=readline(leggi)
        if a==""
            close(leggi)
            break;
        end
        push!(np, parse(Int64,a))
    end  
    close(leggi)  
    agg=0
    tempo=100
    molt=0
    cont=2
    while molt<limite
        global cont
        global molt
        global tempo
        global agg
        global ora
        if np[cont]==0
            agg=agg+6006
            cont=1
        end
        
        molt=np[cont]+agg
        if molt>tempo
            ora = Dates.Time(Dates.now())
            println(molt," ", ora)
            tempo=tempo+10000000000
        end
        a=mod(ni, molt)
        if mod(a, 2)!=0
            if molt-a<mnassimo
                b=molt
            end
        end
        cont=cont+1
    end

    La cosa che mi lascia più perplesso è che il tempo impiegato con le tre righe di calcolo inserite, e cioè 11 minuti, è lo stesso tempo di un programma che calcola questa sequenza con un avanzamento più ridotto e cioè 30 anzichè 6006 e ne controlla ad uno ad uno i vari risultati.

    import math
    from datetime import datetime
    import time
    now = datetime.now().time()
    print("ora inizio =", now)
    #************************
    nr = 1000000000000000000001
    #**** numero da ricercare
    limite=int(math.sqrt(nr))
    print ('ricerca del numero ',nr,' ',len(str(nr)),' Limite ricerca ',limite)
    massimo=1000
    limite2=int(massimo*1.6)
    scrivi=open('divisori_ottimizzati.txt','w')
    scrivi.write(str(nr)+'\n')
    scrivi.write(str(massimo)+'\n')
    scrivi.write('3'+'\n')
    scrivi.write('5'+'\n')
    scrivi.write('7'+'\n')
    scrivi.write('11'+'\n')
    scrivi.write('13'+'\n')
    scrivi.write('17'+'\n')
    scrivi.write('19'+'\n')
    scrivi.write('23'+'\n')
    scrivi.write('29'+'\n')
    tempo=100
    molt=30
    start=time.perf_counter()
    while molt<limite2:
        a=nr%(molt+1)
        if a%2==0:
            b=(-a)+((molt+1)*2)
        else:
            b=(-a)+(molt+1)
        if b<=massimo:
            scrivi.write(str(molt+1)+'\n')
            
        a=nr%(molt+7)
        if a%2==0:
            b=(-a)+((molt+7)*2)
        else:
            b=(-a)+(molt+7)
        if b<=massimo:
            scrivi.write(str(molt+7)+'\n')
    
        a=nr%(molt+11)
        if a%2==0:
            b=(-a)+((molt+11)*2)
        else:
            b=(-a)+(molt+11)
        if b<=massimo:
            scrivi.write(str(molt+11)+'\n')
    
        a=nr%(molt+13)
        if a%2==0:
            b=(-a)+((molt+13)*2)
        else:
            b=(-a)+(molt+13)
        if b<=massimo:
            scrivi.write(str(molt+13)+'\n')
    
        a=nr%(molt+17)
        if a%2==0:
            b=(-a)+((molt+17)*2)
        else:
            b=(-a)+(molt+17)
        if b<=massimo:
            scrivi.write(str(molt+17)+'\n')
    
        a=nr%(molt+19)
        if a%2==0:
            b=(-a)+((molt+19)*2)
        else:
            b=(-a)+(molt+19)
        if b<=massimo:
            scrivi.write(str(molt+19)+'\n')
    
        a=nr%(molt+23)
        if a%2==0:
            b=(-a)+((molt+23)*2)
        else:
            b=(-a)+(molt+23)
        if b<=massimo:
            scrivi.write(str(molt+23)+'\n')
    
        a=nr%(molt+29)
        if a%2==0:
            b=(-a)+((molt+29)*2)
        else:
            b=(-a)+(molt+29)
        if b<=massimo:
            scrivi.write(str(molt+29)+'\n')
        molt=molt+30
    end=time.perf_counter()
    print('Tempo prima parte',end-start)
    print('seconda parte')
    
    start=time.process_time()
    while molt<limite:
        if molt>tempo:
            end = time.perf_counter()
            print(molt,end-start)
            tempo=molt+10000000000
            start = time.perf_counter()
    
        a=nr%(molt+1)
        if a%2!=0 and molt+1-a<massimo:
            scrivi.write(str(molt+1)+'\n')
    
        a=nr%(molt+7)
        if a%2!=0 and molt+7-a<massimo:
            scrivi.write(str(molt+7)+'\n')
    
        a=nr%(molt+11)
        if a%2!=0 and molt+11-a<massimo:
            scrivi.write(str(molt+11)+'\n')
    
        a=nr%(molt+13)
        if a%2!=0 and molt+13-a<massimo:
            scrivi.write(str(molt+13)+'\n')
    
        a=nr%(molt+17)
        if a%2!=0 and molt+17-a<massimo:
            scrivi.write(str(molt+17)+'\n')
    
        a=nr%(molt+19)
        if a%2!=0 and molt+19-a<massimo:
            scrivi.write(str(molt+19)+'\n')
    
        a=nr%(molt+23)
        if a%2!=0 and molt+23-a<massimo:
            scrivi.write(str(molt+23)+'\n')
    
        a=nr%(molt+29)
        if a%2!=0 and molt+29-a<massimo:
            scrivi.write(str(molt+29)+'\n')
    
                
                
        molt=molt+30
    end=time.process_time()
    print('Tempo seconda parte',end-start)
    scrivi.close()

    Inoltre questo programma scrive su disco il risultato ottenuto se la condizione è vera perciò penso sia più complesso per Python gestire questo programma rispetto al primo postato.

    Continuerò a fare prove perchè l'obbiettivo e portare il tempo a 5 minuti, o poco più, e se avete qualche idea sarà molto ben accetta.

    Di nuovo grazie mille

  • Re: Cosa succede con tre istruzioni in più?

    Come detto sono cose note. Sopra i quattro miliardi e rotti si passa a 64 bit e i calcoli si allungano e rimarranno costanti fino al prossimo cambio di tipo. Devi usare un linguaggio tipo C++ per vedere tutte queste cose e ottimizzarle

  • Re: Cosa succede con tre istruzioni in più?

    Sono impressionato

    Sono riuscito a creare il programma in c++  e utilizzando lo stesso sistema di calcolo del programma in Python che ci metteva 10 minuti ogni 10 miliardi, in c++ ci mette 50 secondi.

Devi accedere o registrarti per scrivere nel forum
5 risposte