[Python] come ottenere numeri dispari casuali in un intervallo dato

Stefano Dal Pra s.dalpra a gmail.com
Mar 5 Gen 2010 14:50:05 CET


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:

me a 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:

me a 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.franchi a 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 a lists.python.it
> http://lists.python.it/mailman/listinfo/python
>
-------------- parte successiva --------------
Un allegato non testuale è stato rimosso....
Nome:        randspeed2.py
Tipo:        text/x-python
Dimensione:  724 bytes
Descrizione: non disponibile
Url:         http://lists.python.it/pipermail/python/attachments/20100105/434a06c3/attachment.py 


Maggiori informazioni sulla lista Python