Avevo fatto un test, prima di vedere la tua risposta, chiedendomi se potevo
dimostrare a suon di esempio quel che pensavo. Allego il codice.
Salta fuori che randint()|1 e' in effetti meno efficiente di randrange
ma, secondo me, non per l'uso del | , ma per come e'
implementata la randint() stessa.
ho fatto randspeed2.py <Massimo> <numero_iterazioni>
e mi risulta questo:

con 100 come massimo e 1e6 iterazioni:

m...@myhost:~$ python randspeed2.py 100 1000000
con randint(0,Rmax)|1 tempo = 7.436640
con randrange(1,Rmax=1,2) tempo = 6.940893
con choiche(...) tempo = 3.326678
con int(random.rand()*Rmax)|1  tempo = 2.339324

con 1e6 come massimo e 1e6 iterazioni:

m...@myhost:~$ python randspeed2.py 1000000 1000000
con randint(0,Rmax)|1 tempo = 8.687074
con randrange(1,Rmax=1,2) tempo = 8.094956
con choiche(...) tempo = 5.408784
con int(random.rand()*Rmax)|1  tempo = 2.754338


Salta fuori che  int(random.rand()*Rmax)|1 batte la concorrenza in
modo abbastanza vistoso,
oltre a richiedere meno risorse in assoluto (puo' capitare che python
giri in ambiente dove
risparmiare memoria e' importante).

Quanto al | in se, per me e' un operatore python, tanto come + e deve
essere, per me, tanto
leggibile quanto gli altri operatori. Naturalmente rispetto le tue preferenze.

Ciao e grazie per la discussione

Stefano


2010/1/5 Enrico Franchi <enrico.fran...@gmail.com>:
>
> On Jan 5, 2010, at 1:01 PM, Stefano Dal Pra wrote:
>
>> Perche' quella e' pura e semplice sintassi python, quindi legittima.
>
> Attenzione ad usare il termine "sintassi" a sproposito.
> Tutta e' "sintassi" python, se non sarebbe rifiutata dal compilatore
> e saremmo in presenza di programmi non ben formati.
>
>> Poi per motivi di efficienza:
>> l'interprete, se non e' scemo, dovrebbe tradurre il | 1 con una
>> singola istruzione macchina (or bit a bit). Se  devi generare un
>> dispari e via, ok. Se ne devi fare moltissimi e piu' rapidamente
>> possibile, il discorso cambia.
>
> Ho smesso nel credere alle misure spannometriche.
>
> 1. assumi che la macchina virtuale Python *sia* scema
> 2. in generale in Python e' l'astrazione a pagare, non il dettaglio a basso 
> livello.
>
> Quindi, se voglio dire che "una cosa e' piu' veloce di un'altra" la misuro.
> Finche' non mi sono reso conto che *ho* un problema di performance, la cosa 
> non la valuto neppure.
> Se la valuto, la valuto in modo oggettivo, controllato, misurato. Cerco il 
> collo di bottiglia
> e non intervengo "a caso". Trovato il collo di bottiglia, si valuta se lo 
> speedup atteso
> sia comparabile con il peggioramento del codice oppure se non sia possibile 
> un intervento
> architetturale piu' efficiente ancora.
>
> A questo punto si procede, misurando attentamente i vantaggi in termini di 
> performance.
>
> In particolare, nel nostro specifico caso, salta fuori che il metodo 
> suggerito da Marco
> sia *piu' veloce* di quello suggerito da te, che asserisci essere piu' veloce 
> non mi
> e' chiaro sulla base di cosa.
>
> % /usr/bin/python2.6 oddrandom.py
> baseline : 0.0180490016937
> bit manip: 2.38537406921
> randrange: 2.28163599968
>
>
> Certo, non *molto* piu' veloce. Su un milione di esecuzioni circa un decimo 
> di secondo.
> Fossero stati i risultati invertiti, non mi sarei preoccupato ugualmente.
>
> Quindi, di fatto e' il classico esempio di ottimizzazione prematura. Anzi, 
> un'ottimizzazione
> che *peggiora* le performance (e la leggibilita').
>
> Tra l'altro, quando si fanno simulazioni numeriche, spesso si accetta di 
> rifare piu' volte
> gli esperimenti (quindi "di fatto" peggiorando il tempo di esecuzione di un 
> fattore lineare)
> pur di provarli con diversi generatori di numeri per mettersi al riparo da 
> problemi di
> non troppo pseudo-casualita'. Quindi, figuriamoci. :)
>
>
>> Per non giocare con i bit uno puo' fare randint(0,4) * 2 + 1 e ottiene
>> i dispari tra 1 e 9, tanto equiprobabili quanto randint(0,4).
>> Nel caso di randint(0,9) | 1 , ogni risultato ha esattamente due
>> possibilita' di uscire: era il pari immediatamente superiore a cui si
>> e' aggiunto 1, oppure era direttamente dispari, e non e' cambiato.
>
> No, hai *perso* informazione. Eventualmente una quantita' completamente 
> trascurabile,
> possibilmente una quantita' rilevante. Con la semplice assunzione che ognuno 
> dei
> 32 bit sia responsabile per 1/32 della qi, il primo modo fa una 
> trasformazione lineare
> (e quindi di fatto anche la qi rimane invariata). Con il tuo trucco invece 
> perdi 1/32 della
> qi. Non tanto, ma nemmeno poco. Dopotutto, visto che si puo' evitare il tutto.
>
> Questo *a monte* del fatto che stai scegliendo su un range ristretto di 
> numeri, eh.
> _______________________________________________
> Python mailing list
> Python@lists.python.it
> http://lists.python.it/mailman/listinfo/python
>
#!/usr/bin/env python

import time,random,sys

n,iter,T=0,0,[]

Rmax=int(sys.argv[1])
itermax=int(sys.argv[2])

T0=time.time()
while iter<itermax:
  n=random.randint(0,Rmax)|1
  iter+=1
T1=time.time()
print "con randint(0,Rmax)|1 tempo = %f"%(T1-T0)

iter=0
T2=time.time()
while iter<itermax:
  n=random.randrange(1,Rmax+1,2)
  iter+=1
T3=time.time()
print "con randrange(1,Rmax=1,2) tempo = %f"%(T3-T2)


iter=0
T4=time.time()
R=range(1,Rmax+1,2)
while iter<itermax:
  n=random.choice(R)
  iter+=1
T5=time.time()
print "con choiche(...) tempo = %f"%(T5-T4)


iter=0
T6=time.time()
Rmax-=1
while iter<itermax:
  n=int(random.random()*Rmax)|1
  iter+=1
T7=time.time()
print "con int(random.rand()*Rmax)|1  tempo = %f"%(T7-T6)
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a