2013-04-22 15 views
14

Qual è il modo più efficiente e portabile per generare un casuale casuale in [0,1] in Cython? Un approccio è quello di utilizzare INT_MAX e rand() dalla libreria C:Modo corretto per generare numeri casuali in Cython?

from libc.stdlib cimport rand 
cdef extern from "limits.h": 
    int INT_MAX 
cdef float randnum = rand()/float(INT_MAX) 

E 'OK per utilizzare INT_MAX in questo modo? Ho notato che è molto diverso dal costante si ottiene da max int di Python:

import sys 
print INT_MAX 
print sys.maxint 

rendimenti:

2147483647 (C max int) 
9223372036854775807 (python max int) 

Qual è il giusto numero di "normalizzazione" per rand()? EDIT inoltre, come è possibile impostare il seme casuale (ad esempio, il seeding basato sull'ora corrente) se si utilizza l'approccio C per chiamare rand() da libc?

+0

Hai appena provato a prendere il massimo e il minimo di qualche migliaio di campioni e vedere quale fattore di scala si avvicina a 1.0? – phs

+0

Si prega di guardare "[rand() considerato dannoso] (https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful)" –

risposta

8

Lo standard C dice rand restituisce un int nel range da 0 a RAND_MAX compreso, quindi dividendolo per RAND_MAX (da stdlib.h) è il modo corretto per normalizzare esso. In pratica, RAND_MAX sarà quasi sempre uguale a MAX_INT, ma non fare affidamento su questo.

Poiché rand fa parte di ISO C dal C89, è garantito che sia disponibile ovunque, ma non vengono fornite garanzie relative alla qualità dei numeri casuali. Se la portabilità è la tua preoccupazione principale, tuttavia, è la scelta migliore, a meno che tu non sia disposto a utilizzare il modulo random di Python.

Python sys.maxint è un concetto completamente diverso; è solo il più grande numero positivo che Python può rappresentare in il proprio tipo int; quelli più grandi dovranno essere lunghi. Gli interi e gli oggetti lunghi di Python non sono particolarmente correlati a quelli di C.

+0

Grazie! Sai come si può impostare il seme usando l'approccio libc? – user248237dfsf

+1

Probabilmente userò 'random.randint (0, INT_MAX)' per quello, davvero. L'overhead non è un problema perché si verificherà solo una volta. L'overhead – Cairnarvon

+0

è un grosso problema in quanto viene chiamato più volte in un ciclo che deve generare numeri casuali (per campionare da multinomiale in parte). Posso impostare 'random.randint (0, INT_MAX)' e poi chiamare C 'rand()' e far sì che i semi C e Python siano "sincronizzati"? – user248237dfsf

2

'c' stdlib rand() restituisce un numero compreso tra 0 e RAND_MAX che è generalmente 32767.

C'è qualche motivo per non utilizzare il pitone casuale()?

Generate random integers between 0 and 9

+0

Sto usando questo un ciclo interno in una funzione Cython e chiamando Python per questo è troppo costoso – user248237dfsf

+0

RAND_MAX è 2147483647 (2 ** 31-1) sul mio sistema. È garantito che sia * almeno * 2 ** 15-1, ma non credo di averlo mai visto così basso nella pratica. – Cairnarvon

+0

Oh, apparentemente msvc è 2 ** 15-1. È terribile. – Cairnarvon

1

Non sono sicuro che drand sia una nuova aggiunta ma sembra fare esattamente quello che vuoi evitando la divisione costosa.

cdef extern from "stdlib.h": 
    double drand48() 
    void srand48(long int seedval) 

cdef extern from "time.h": 
    long int time(int) 

# srand48(time(0)) 
srand48(100) 
# TODO: this is a seed to reproduce bugs, put to line of code above for 
# production 
drand48() #This gives a float in range [0,1) 

mi sono imbattuto this idea mentre la ricerca se il vostro metodo di divisione ha generato casualità sufficiente. La fonte che ho trovato rende il buon punto che nel mio caso sto confrontando il numero casuale con un numero decimale con due cifre, quindi ho davvero bisogno solo di 3 punti decimali di precisione. Quindi INT_MAX è più che adeguato. Ma sembra che drand48 salvi il costo della divisione, quindi potrebbe valerne la pena.

+2

A proposito, questo non è portatile perché 'srand48' e' drand48' sono disponibili solo su sistemi POSIX –

Problemi correlati