Python SystemRandom ile Rastgele Sayı Üretmek

Python’da rastgele sayı üretebilmek için halihazırda random modülünden faydalanabiliyoruz. Bu modül rastgele sayı üretirken öncelerden Mersenne Twister adlı bir yöntem kullanıyormuş.[1] Dökümantasyonunda belirtildiğine göre 53 bit kesinlikte float türünde rastgele sayılar üretebiliyormuş.

Buraya kadar bakınca güzel gözüküyor. Şimdi bir adım öteye gidelim. Bu yöntem çok kullanılmakta ve Python altında hızlı çalışması için C ile yazılmış.

Bu algoritmanın periyodunun uzun olması ile, verdiği sayının güvenilirliği arasında bir orantı olduğu [2]’de belirtiliyor. Yalnız rastgelelik testlerinden bazılarında başarısız olduğu da yine [2]’de belirtilmiş. Ayrıca [1]’de de şifreleme uygulamalarında kullanılmaması gerektiği konusunda kullanıcılar uyarılıyor. Bu durumda başka bir çözüme ihtiyacımız olacak.

Python 2.3’te yine bu tür işlemler için Wichmann-Hill algoritmasına geçilmiş. Bu algoritma 0-1 kapalı aralığında rastgele sayılar üretiyor. Tabii biz kullanırken Python kütüphanesinde randint gibi birçok fonksiyonla istediğimiz aralığa uyarlanmış olarak elde edebiliyoruz. Ama uyarı bunun için de geçerli. Şifreleme gibi güvenlik gerektiren işlemlerde rastgele sayı üretmek için daha güvenilir kaynaklara ihtiyaç var.

Yani senaryo şu şekilde, Python kullanıyoruz ve şifreleme için rastgele bir sayıya ihtiyacımız var. Ne yapmamız gerekiyor?

Python içerisine bu amaçla, işletim sisteminin rastgele sayı üretimi için sağladığı kaynaklara erişimi sağlayan bir sınıf konulmuş. Bu sınıf random modülü içerisinde yer alan random.SystemRandom() olarak geçiyor. İçerisinde varsayılan olarak random sınıfında bulunan methodların tamamına yakını bulunuyor, bu da aynı fonksiyonları kullanma imkanı sunuyor.

Ancak yine dökümantasyonda, işletim sisteminin bu kaynakları sağlamadığı durumda sınıfın örnekleme sırasında hata döndüreceği belirtilmiş. Hatayı yakalamak isterseniz anahtarı da vereyim: NotImplementedError.

Bu yöntem yazılımsal bir kaynağa dayanmadığı için, elde edilen sayılar yeniden üretilebilir olmuyor.

Tabii tüm bu durumlarda üretilen sayılar pseudorandom olarak geçiyor, yani sözde rastgele sayılar. Gerçek rastgele sayılardan farklı olsalar da, SystemRandom ile üretilen sayılar gerçek rastgeleye daha yakın sonuçlar verdiği için şifreleme uygulamalarına random sınıfında üretilen değerlere göre daha uygunlar.

İçerisinde yer alan fonksiyonların açıklamaları şu şekilde, kullanımı alt kısımda:

>>> for i in dir(a):
...    exec("print(a."+i+".__doc__)")
... 

int(x=0) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4
Alternate random number generator using sources provided
    by the operating system (such as /dev/urandom on Unix or
    CryptGenRandom on Windows).

     Not available on all systems (see os.urandom() for details).

x.__delattr__('name') <==> del x.name
dict() -> new empty dictionary
dict(mapping) -> new dictionary initialized from a mapping object's
    (key, value) pairs
dict(iterable) -> new dictionary initialized as if via:
    d = {}
    for k, v in iterable:
        d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
    in the keyword argument list.  For example:  dict(one=1, two=2)
__dir__() -> list
default dir() implementation
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
x.__eq__(y) <==> x==y
default object formatter
x.__ge__(y) <==> x>=y
x.__getattribute__('name') <==> x.name
None
x.__gt__(y) <==> x>y
x.__hash__() <==> hash(x)
Initialize an instance.

        Optional argument x controls seeding, as for Random.seed().

x.__le__(y) <==> x<=y
x.__lt__(y) <==> x<y
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
x.__ne__(y) <==> x!=y
T.__new__(S, ...) -> a new object with type S, a subtype of T
None
helper for pickle
x.__repr__() <==> repr(x)
x.__setattr__('name', value) <==> x.name = value
None
__sizeof__() -> int
size of object in memory, in bytes
x.__str__() <==> str(x)
Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented.  If it returns
NotImplemented, the normal algorithm is used.  Otherwise, it
overrides the normal algorithm (and the outcome is cached).

None
Method should not be called for a system random number generator.
Return a random int in the range [0,n).  Raises ValueError if n==0.
Beta distribution.

        Conditions on the parameters are alpha > 0 and beta > 0.
        Returned values range between 0 and 1.

Choose a random element from a non-empty sequence.
Exponential distribution.

        lambd is 1.0 divided by the desired mean.  It should be
        nonzero.  (The parameter would be called "lambda", but that is
        a reserved word in Python.)  Returned values range from 0 to
        positive infinity if lambd is positive, and from negative
        infinity to 0 if lambd is negative.

Gamma distribution.  Not the gamma function!

        Conditions on the parameters are alpha > 0 and beta > 0.

        The probability distribution function is:

                    x ** (alpha - 1) * math.exp(-x / beta)
          pdf(x) =  --------------------------------------
                      math.gamma(alpha) * beta ** alpha

Gaussian distribution.

        mu is the mean, and sigma is the standard deviation.  This is
        slightly faster than the normalvariate() function.

        Not thread-safe without a lock around calls.

None
getrandbits(k) -> x.  Generates a long int with k random bits.
Method should not be called for a system random number generator.
Log normal distribution.

        If you take the natural logarithm of this distribution, you'll get a
        normal distribution with mean mu and standard deviation sigma.
        mu can have any value, and sigma must be greater than zero.

Normal distribution.

        mu is the mean, and sigma is the standard deviation.

Pareto distribution.  alpha is the shape parameter.
Return random integer in range [a, b], including both end points.

Get the next random number in the range [0.0, 1.0).
Choose a random item from range(start, stop[, step]).

        This fixes the problem with randint() which includes the
        endpoint; in Python this is usually not what you want.

        Do not supply the 'int' argument.

Chooses k unique random elements from a population sequence or set.

        Returns a new list containing elements from the population while
        leaving the original population unchanged.  The resulting list is
        in selection order so that all sub-slices will also be valid random
        samples.  This allows raffle winners (the sample) to be partitioned
        into grand prize and second place winners (the subslices).

        Members of the population need not be hashable or unique.  If the
        population contains repeats, then each occurrence is a possible
        selection in the sample.

        To choose a sample in a range of integers, use range as an argument.
        This is especially fast and space efficient for sampling from a
        large population:   sample(range(10000000), 60)

Stub method.  Not used for a system random number generator.
Method should not be called for a system random number generator.
x, random=random.random -> shuffle list x in place; return None.

        Optional arg random is a 0-argument function returning a random
        float in [0.0, 1.0); by default, the standard random.random.

Triangular distribution.

        Continuous distribution bounded by given lower and upper limits,
        and having a given mode value in-between.

        http://en.wikipedia.org/wiki/Triangular_distribution

Get a random number in the range [a, b) or [a, b] depending on rounding.
Circular data distribution.

        mu is the mean angle, expressed in radians between 0 and 2*pi, and
        kappa is the concentration parameter, which must be greater than or
        equal to zero.  If kappa is equal to zero, this distribution reduces
        to a uniform random angle over the range 0 to 2*pi.

Weibull distribution.

        alpha is the scale parameter and beta is the shape parameter.

Şimdi birkaç sayı üretelim:

>>> sifre.random()
0.2537550083929141
>>> sifre.random()
0.21777032994714807
>>> sifre.random()
0.35725300620115075
>>> sifre.random()
0.9742735026972249
>>> sifre.randint(1,100)
83
>>> sifre.randint(1,100)
43
>>> sifre.randint(1,100)
87
>>> sifre.randint(1,100)
16
>>> liste = ["elma","armut","ayva",1,2,3]
>>> sifre.choice(liste)
3
>>> sifre.choice(liste)
'armut'

choice fonksiyonu verilen liste içerisinden rastgele bir eleman seçiyor. randint(x,y) fonksiyonu x ile y kapalı aralığında rastgele bir tamsayı seçiyor. random fonksiyonu ise 0 ile 1 arasında bir rastgele sayı döndürüyor.

Son olarak da Python’da istenilen bit uzunluğunda rastgele sayı üretmek için şöyle bir seçeneğimiz mevcut:

>>> sifre.getrandbits(8192)
461652007078691607202743284552450886519383474458570989489395311810352036364325940458105101991002817971047895968112398243184011832601683855610456288700473774648351585297620996113451859959655210074539860778603552395396071780111126630525049505700970516765553192929072913094548574063034071951001199069827618719317882166044188164887488249424759905538217835061010806243134873372679410208658418368220680513317009100510236306996808984496787428313846683616443004706862265265296878468617697624229969144684676512491335266973052544768791187896847207828638425451500751560486649499688880600017726179304594925628774904701644792716642468347553611354230701992924275779698766872799745458494873088495918275358815544471930986156771803989853111534460801374189927796402578651207527051670191340221624265424569707709076135277758895234499668173585839212717791419809145239220175016422106972751242498508377008745945900524431171637042596118227576360256033900364657235477615786867316305777891349611303759934311679718084380346956918456667327966148398471264815819538462712044863297010018061042500941911239890329141115454190245506528398482923551122333546274527396189269090871935996142781886369020148576004616828528931825189822004746680501611744407532787359826806474667319615770722913362272034146798476142275073598841989993940998960737466418010891705293896587220656989436555012509539977072097375251166140609806015702938252215439957915947695967606002471701113879246405954982798953835300099716582519613945743207990838632321464940069788794715219891897239476706410766277804650847092674514959455080574571998284532215291135002966361215190688993780726557169370081876387708840476321241436388695455194579315017513423721523540691358738680601341167096572862432688699136580606130952369752037621911004155861310174009963244579189318787170849878818498939007098827947460190200934248748613357581527120012625378023388337152195616221811040857383360258293973773327255472384911262090129261480770612364427557354460710628614548177611403930046947845619334107562944819798719147055533551890698031212543575892141077113194885415240505664172840384789003234852571156940018216318427091933169404263272991778521888694069378160847354531834427038354997467233602860204173822410549798309431056867908301264468905545353515623976539039002707303945159554934904168803753218495011871454441422783294949149575472883235093120920400442572632917217235510338405935993029458889892900980983062898090815498729607881379643044779675046942164866963731994L

[1] http://docs.python.org/2/library/random.html#random.seed

[2] http://en.wikipedia.org/wiki/Mersenne_twister

 
comments powered by Disqus