Javascript rastgele sayı üreteci tohumlama


372

Javascript'te rastgele sayı üretecini (Math.random) tohumlamak mümkün mü?


farklı testler için aynı sonuçları tekrar tekrar elde edip etmemek veya kullanım arasında daha iyi rastgelelik için kullanıcı başına 'benzersiz bir şey' ile tohumlamak isteyip istemediğiniz açık değildir.
simbo1905

2
Hayır, maalesef mümkün değil. jsrand , görülebilen bir PRNG'ye ihtiyacım olduğunda yazdığım küçük bir kütüphanedir. Bunun için googling bulabileceğiniz daha karmaşık kütüphaneler de vardır.
Domenico De Felice

4
Soruya ek olarak: bir PRNG'yi tohumlamak için bir araç kullanmadan sunmak iyi bir fikir olabilir mi ?? Bunun için iyi bir sebep var mı?
Alan

Yanıtlar:



159

NOT: Özlüğe ve belirgin zarafete rağmen (ya da daha doğrusu), bu algoritma hiçbir şekilde rastgele olma açısından yüksek kaliteli bir algoritma değildir. Daha iyi sonuçlar için örneğin bu cevapta listelenenleri arayın .

(Başlangıçta bir yorumda başka bir cevaba sunulan zekice bir fikirden uyarlanmıştır.)

var seed = 1;
function random() {
    var x = Math.sin(seed++) * 10000;
    return x - Math.floor(x);
}

seedHerhangi bir sayı olarak ayarlayabilirsiniz , sadece sıfırdan (veya Math.PI'nin herhangi bir katından) kaçının.

Bu çözümün şıklığı, bence, herhangi bir "sihirli" sayının eksikliğinden geliyor (10000 dışında, tuhaf desenlerden kaçınmak için atmanız gereken minimum basamak miktarını temsil ediyor - 10 , 100 , 1000 değerlerine sahip sonuçlara bakın. ). Kısalık da güzel.

Math.random () (2 veya 3 faktörü ile) biraz daha yavaş, ancak JavaScript ile yazılmış herhangi bir çözüm kadar hızlı olduğuna inanıyorum.


20
Bu RNG'nin eşit olarak dağıtılmış sayılar ürettiğini kanıtlamanın bir yolu var mı? Deneysel olarak öyle görünüyor: jsfiddle.net/bhrLT
Nathan Breit

6
6.000.000 ops / saniye oldukça hızlı, tıklama başına ~ 3.000.000'dan fazla üretmeyi planlamıyorum. Şaka yapıyorum, bu harika.
AMK

59
-1, Bu tekdüze bir örnekleyici değil - 0 ve 1'e karşı oldukça önyargılı ( hesaplamak için biraz zaman alabilecek jsfiddle.net/bhrLT/17'ye bakın ). Ardışık değerler birbiriyle ilişkilidir - her 355 değer ve hatta her 710'da bir ilişki vardır. Lütfen daha dikkatli düşünülmüş bir şey kullanın!
Spencer Spencer

37
Soru, kriptografik olarak güvenli bir rasgele sayı üreteci oluşturmakla ilgili değil, javascript'te çalışan, hızlı demolar vb. İçin yararlı olan bir şeydir.
Jason Goemaat

15
Dikkatli ol. Math.sin () istemci ve sunucuda farklı sonuçlar verebilir. Meteor kullanıyorum (istemci ve sunucuda javascript kullanır).
Obiwahn

145

Düz JavaScript'te iyi, kısa ve hızlı bir dizi Pseudorandom sayı üreteci (PRNG) işlevi uyguladım . Hepsi tohumlanabilir ve kaliteli numaralar sağlayabilir.

Her şeyden önce, PRNG'lerinizi doğru şekilde başlatmaya özen gösterin. Aşağıdaki jeneratörlerin çoğunda (basitlik amacıyla) yerleşik tohum üretme prosedürü yoktur, ancak bir veya daha fazla 32 bit değeri PRNG'nin başlangıç durumu olarak kabul edilir . Benzer tohumlar (örneğin, 1 ve 2'nin basit bir tohumu), zayıf PRNG'lerde korelasyonlara neden olabilir, bu da çıktının benzer özelliklere sahip olmasıyla sonuçlanır (rastgele üretilen seviyeler benzerdir). Bundan kaçınmak için, PRNG'leri iyi dağıtılmış bir tohumla başlatmak en iyi uygulamadır.

Neyse ki, hash fonksiyonları kısa dizelerden PRNG'ler için tohum üretmede çok iyidir. İyi bir sağlama işlevi, iki dize benzer olsa bile çok farklı sonuçlar üretir. İşte MurmurHash3'ün karıştırma fonksiyonuna dayanan bir örnek:

function xmur3(str) {
    for(var i = 0, h = 1779033703 ^ str.length; i < str.length; i++)
        h = Math.imul(h ^ str.charCodeAt(i), 3432918353),
        h = h << 13 | h >>> 19;
    return function() {
        h = Math.imul(h ^ h >>> 16, 2246822507);
        h = Math.imul(h ^ h >>> 13, 3266489909);
        return (h ^= h >>> 16) >>> 0;
    }
}

Her bir sonraki çağrı dönüş fonksiyonu arasında xmur3bir PRNG bir tohum olarak kullanılmak üzere yeni bir "rastgele", 32-bit karma değer üretir. Bunu nasıl kullanabileceğiniz aşağıda açıklanmıştır:

// Create xmur3 state:
var seed = xmur3("apples");
// Output four 32-bit hashes to provide the seed for sfc32.
var rand = sfc32(seed(), seed(), seed(), seed());

// Output one 32-bit hash to provide the seed for mulberry32.
var rand = mulberry32(seed());

// Obtain sequential random numbers like so:
rand();
rand();

Alternatif olarak, sadece tohumu doldurmak için kukla veriler seçin ve ilk durumu iyice karıştırmak için jeneratörü birkaç kez ilerletin (12-20 iterasyon). Bu genellikle PRNG'lerin referans uygulamalarında görülür, ancak başlangıç ​​durumlarının sayısını sınırlandırır.

var seed = 1337 ^ 0xDEADBEEF; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
var rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (var i = 0; i < 15; i++) rand();

Bu PRNG işlevlerinin çıktısı, rasgele sayılar istiyorsanız, 0-1 (0 dahil, 1 özel) arasında eşdeğer bir kayan nokta sayısına dönüştürülen pozitif bir 32 bit sayı (0 ila 2 32 -1) üretir MDN ile ilgili bu makaleyiMath.random() okuyun . Yalnızca ham bitleri istiyorsanız, son bölme işlemini kaldırmanız yeterlidir.

Dikkat edilmesi gereken başka bir şey de JS'nin sınırlamalarıdır. Sayılar yalnızca 53 bit çözünürlüğe kadar tam sayıları temsil edebilir. Bitsel işlemler kullanıldığında, bu 32'ye düşürülür. Bu, 64 bit sayıları kullanan C veya C ++ ile yazılmış algoritmaların uygulanmasını zorlaştırır. 64 bit kodun taşınması, performansı önemli ölçüde azaltabilen şimler gerektirir . Basitlik ve verimlilik uğruna, sadece JS ile doğrudan uyumlu olduğu için sadece 32 bit matematik kullanan algoritmaları düşündüm.

Şimdi jeneratörlere doğru. (Tam referansları burada saklıyorum )


sfc32 (Basit Hızlı Sayaç)

sfc32 , PractRand rasgele sayı test paketinin (elbette geçtiği) bir parçasıdır . sfc32 128-bit bir duruma sahiptir ve JS'de çok hızlıdır.

function sfc32(a, b, c, d) {
    return function() {
      a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0; 
      var t = (a + b) | 0;
      a = b ^ b >>> 9;
      b = c + (c << 3) | 0;
      c = (c << 21 | c >>> 11);
      d = d + 1 | 0;
      t = t + d | 0;
      c = c + t | 0;
      return (t >>> 0) / 4294967296;
    }
}

Mulberry32

Mulberry32 32 bit devlet ile basit bir jeneratör, ama son derece hızlı ve (yazar bunun tüm testleri geçen devletler iyi kaliteye sahip gjrand test paketi ve tam 2 sahiptir 32 dönemini ama doğrulamadım).

function mulberry32(a) {
    return function() {
      var t = a += 0x6D2B79F5;
      t = Math.imul(t ^ t >>> 15, t | 1);
      t ^= t + Math.imul(t ^ t >>> 7, t | 61);
      return ((t ^ t >>> 14) >>> 0) / 4294967296;
    }
}

Sadece basit ama iyi bir PRNG gerekiyorsa ve milyarlarca rasgele sayıya ihtiyacınız yoksa bunu tavsiye ederim (bkz. Doğum Günü sorunu ).

xoshiro128 **

Mayıs 2018 itibariyle, xoshiro128 ** , Xighift ailesinin yeni üyesi, Vigna / Blackman (ayrıca Chrome'da kullanılan xoroshiro'u da yazdı). 128 bitlik bir durum sunan en hızlı jeneratördür.

function xoshiro128ss(a, b, c, d) {
    return function() {
        var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
        c ^= a; d ^= b;
        b ^= c; a ^= d; c ^= t;
        d = d << 11 | d >>> 21;
        return (r >>> 0) / 4294967296;
    }
}

Yazarlar rastgele testlerden iyi geçtiğini iddia ediyorlar ( uyarılar olsa da ). Diğer araştırmacılar, TestU01'de (özellikle LinearComp ve BinaryRank) bazı testlerin başarısız olduğunu belirtti. Pratikte, şamandıralar kullanıldığında sorunlara neden olmamalıdır (bu uygulamalar gibi), ancak ham düşük bitlere dayanarak sorunlara neden olabilir.

JSF (Jenkins'in Küçük Hızlı)

Bu JSF veya ISAAC ve SpookyHash yapan Bob Jenkins (2007) tarafından 'smallprng' . O geçer olmasa kadar hızlı SFC olarak, PractRand testleri ve oldukça hızlı olmalıdır.

function jsf32(a, b, c, d) {
    return function() {
        a |= 0; b |= 0; c |= 0; d |= 0;
        var t = a - (b << 27 | b >>> 5) | 0;
        a = b ^ (c << 17 | c >>> 15);
        b = c + d | 0;
        c = d + t | 0;
        d = a + t | 0;
        return (d >>> 0) / 4294967296;
    }
}

LCG (Lehmer / Park-Miller RNG veya MCG olarak da bilinir)

LCG son derece hızlı ve basittir, ancak rasgeleliğinin kalitesi o kadar düşüktür ki, yanlış kullanım aslında programınızda hatalara neden olabilir! Yine de, Math.sinveya öneren bazı cevaplardan önemli ölçüde daha iyidir veya Math.PI! Güzel olsa da tek astarlı :).

var LCG=s=>()=>(2**31-1&(s=Math.imul(48271,s)))/2**31;

Bu uygulamaya 1988 ve 1993 yıllarında Park-Miller tarafından önerilen ve C ++ 11 olarak uygulanan minimal standart RNG denir . Devletin 31 bit olduğunu unutmayın (31 bit 2 milyar olası durum verir, 32 bit bunun iki katı verir). Bu, başkalarının değiştirmeye çalıştığı PRNG'nin çok türüdür!minstd_rand

Çalışacak, ancak gerçekten hıza ihtiyacınız yoksa ve rasgelelik kalitesini umursamıyorsanız kullanmazdım (yine de rastgele nedir?). Bir oyun reçel veya bir demo ya da bir şey için harika. LCG'ler tohum korelasyonlarından muzdariptir, bu nedenle bir LCG'nin ilk sonucunu atmak en iyisidir . Ve bir LCG kullanmakta ısrar ederseniz, bir artış değeri eklemek sonuçları iyileştirebilir, ancak muhtemelen daha iyi seçenekler olduğunda boşuna bir egzersizdir.

32 bit durum (artan durum alanı) sunan başka çarpanlar var gibi görünüyor:

var LCG=s=>()=>(s=Math.imul(741103597,s)>>>0)/2**32;
var LCG=s=>()=>(s=Math.imul(1597334677,s)>>>0)/2**32;

Bu LCG değerleri şöyledir: P. L'Ecuyer: Farklı boyutlarda ve iyi kafes yapısına sahip Doğrusal Konjügasyon Jeneratörleri tablosu, 30 Nisan 1997.


5
Bu inanılmaz bir cevap. Eminim buna geri dönecekler.
DavidsKanal

1
Pierre L'ecuyer'in "Doğrusal Konjugatif Jeneratör Tabloları ..." dan alıntıladığınız değerlerin Javascript'teki maksimum tamsayı boyutunu aşabileceğine inanıyorum. (2 ^ 32-1) * 741103597 ≈ 3e18'in maksimum çekirdeği, JavaScript'in maksimum int of 9e15 boyutundan daha büyük. Ben Pierre'in kitabından aşağıdaki değerler yerli sınırlar içinde büyük dönemi var düşünüyorum: seed = (seed * 185852 + 1) % 34359738337.
Lachmanski

1
@Lachmanski doğrudur, ancak bunlar 32 bit (ve Park-Miller 31 bit) ile sınırlıdır. Kullanmak Math.imul32 bit tamsayılarda C çarpma kullanırken olduğu gibi taşmasına izin verir. Önerdiğiniz, JS'nin tam sayı alanını kullanan bir LCG'dir, bu da kesinlikle keşfedilecek ilginç bir alandır. :)
bryc

1
Bu harika! Sfc32'nizi bir LGPL programına kopyalayabilir miyim?
user334639

4
@ blobber2 ne demek istediğinizden emin değilim, ancak orijinal kod buradan (başkalarıyla birlikte): github.com/bryc/code/blob/master/jshash/PRNGs.md . az ya da çok bir depo içinde bir
öz

39

Hayır, ancak burada basit bir sözde jeneratör, Wikipedia'dan uyarlanmış taşıma ile çarpma uygulaması (o zamandan beri kaldırıldı):

var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;

// Takes any integer
function seed(i) {
    m_w = (123456789 + i) & mask;
    m_z = (987654321 - i) & mask;
}

// Returns number between 0 (inclusive) and 1.0 (exclusive),
// just like Math.random().
function random()
{
    m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
    m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
    var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
    result /= 4294967296;
    return result;
}

EDIT: sıfırlama yaparak sabit tohum işlevi m_z
EDIT2: Ciddi uygulama kusurları giderildi


3
Herkes bu işlevi rastgele için test etti mi?
Justin

3
Bu, oldukça uzun bir süreye sahip taşıma ile çarpma (MWC) rastgele üreticisidir. Vikipedi'den
Michael_Scharf

10
seedÇünkü fonksiyon, rasgele jeneratör sıfırlanmaz mz_zzaman değişken değiştirilir random()denir. Bu nedenlemz_z = 987654321seed
Michael_Scharf

Rastgele renk üretecimle (HSL) kullandığımda, sadece yeşil ve mavi renkler üretir. Orijinal rastgele jeneratör tüm renkleri üretir. Yani, aynı değil ya da çalışmıyor.
Tomas Kubes

@Michael_Scharf 1) Tohum değişikliği m_w, değil m_z. 2) Her ikisi de m_wve m_zönceki değerlerinde BASED değerini değiştirir, böylece sonucu değiştirir.
ESL

26

Antti Sykäri'nin algoritması hoş ve kısa. Başlangıçta Math.seed (s) çağırdığınızda Javascript Math.random yerine bir varyasyon yaptım, ama sonra Jason işlevi dönen daha iyi olacağını yorumladı:

Math.seed = function(s) {
    return function() {
        s = Math.sin(s) * 10000; return s - Math.floor(s);
    };
};

// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());

Bu, Javascript'te bulunmayan başka bir işlevsellik sağlar: birden fazla bağımsız rastgele jeneratör. Aynı anda birden fazla tekrarlanabilir simülasyon yapmak istiyorsanız bu özellikle önemlidir.


3
Birden Math.randomfazla bağımsız jeneratöre sahip olmanızı sağlayacak bir ayar yerine işlevi döndürürseniz , değil mi?
Jason Goemaat

1
Sizin için
önemliyse

Bunun sonucunda meydana gelen rasgele nasıl tekrarlanabilir? Her seferinde yeni sayılar vermeye devam ediyor
SMUsamaShah

Tek yapmanız her zaman Math.seed(42);bunu yaparsanız o fonksiyonu sıfırlar, böylece var random = Math.seed(42); random(); random();almak 0.70..., sonra 0.38.... var random = Math.seed(42);Tekrar arayarak sıfırlarsanız , bir daha aradığınızda tekrar random()alırsınız 0.70...ve bir dahaki sefere 0.38...tekrar alırsınız .
WOUNDEDStevenJones

1
Lütfen bunu kullanmayın. Lütfen bunun yerine yerel randombir javascript işlevinin üzerine yazmak yerine adlı bir yerel değişkeni kullanın. Üzerine yazma Math.randomişlemi JIST derleyicisinin tüm kodunuzu açmamasına neden olabilir.
Jack Giffin

11

Lütfen Pierre L'Ecuyer'in 1980'lerin sonlarına ve 1990'ların başına kadar olan çalışmalarına bakın. Başkaları da var. Bir uzman değilseniz, kendi başına (sözde) rasgele bir sayı üreteci oluşturmak oldukça tehlikelidir, çünkü sonuçların istatistiksel olarak rasgele olmaması veya küçük bir döneme sahip olma olasılığı yüksektir. Pierre (ve diğerleri) uygulaması kolay olan bazı iyi (sözde) rasgele sayı üreteçlerini bir araya getirmiştir. LFSR jeneratörlerinden birini kullanıyorum.

https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf

Phil Troy


1
Harika yanıt, ancak javascript ile ilgili değil :)
Nikolay Fominyh

3
Profesör L'Ecuyer'in çalışmalarını uygulama kodu java için halka açıktır ve çoğu programcı tarafından Javascript'e kolayca çevrilebilir.
user2383235

6

Önceki cevaplardan bazılarını birleştirdiğinizde, aradığınız görülebilir rastgele işlev budur:

Math.seed = function(s) {
    var mask = 0xffffffff;
    var m_w  = (123456789 + s) & mask;
    var m_z  = (987654321 - s) & mask;

    return function() {
      m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
      m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;

      var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
      result /= 4294967296;
      return result;
    }
}

var myRandomFunction = Math.seed(1234);
var randomNumber = myRandomFunction();

4
Bu, dizinin başlangıcında farklı tohumlarla çok benzer sonuçlar üretir. Örneğin, Math.seed(0)()döndürür 0.2322845458984375ve Math.seed(1)()döndürür 0.23228873685002327. Her ikisini de değiştirmek m_wve m_ztohuma göre yardımcı olur. var m_w = 987654321 + s; var m_z = 123456789 - s;farklı tohumlarla ilk değerlerin güzel dağılımını üretir.
undefined

1
@defined tanımladığınız sorun son düzenleme itibariyle düzeltildi, MWC uygulamasında bir hataydı.
bryc

Şimdi Ocak 2020 itibariyle güzel çalışıyor. 0 ile tohum, 0.7322976540308446 olsun. 1, 0.16818441334180534, 2: 0.6040864314418286, 3: 0.03998844954185188 ile tohum. İkinize de teşekkürler!
Eureka

3

Kendi sözde rastgele jeneratör yazmak oldukça basittir.

Dave Scotese'nin önerisi faydalıdır, ancak başkalarının da işaret ettiği gibi, oldukça eşit dağılmamıştır.

Ancak bunun nedeni günahın tamsayı argümanları değildir. Bunun nedeni, bir dairenin tek boyutlu bir projeksiyonu olan günah aralığıdır. Çemberin açısını alırsanız, üniform olur.

Sin (x) yerine arg (exp (i * x)) / (2 * PI) kullanın.

Doğrusal düzeni sevmiyorsanız, xor ile biraz karıştırın. Gerçek faktör de o kadar önemli değil.

N sözde rastgele sayılar üretmek için kod kullanılabilir:

function psora(k, n) {
  var r = Math.PI * (k ^ n)
  return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))

Ayrıca, gerçek entropi gerektiğinde sözde rastgele dizileri kullanamayacağınızı da unutmayın.


Ben uzman değilim, ama sıralı tohumlar sürekli bir kalıp izliyor . Renkli pikseller> = 0,5'dir. Yarıçapı tekrar tekrar yinelediğini tahmin ediyorum?
bryc


1

Math.randomhayır, ama koşan kütüphane bunu çözer. Hayal edebileceğiniz neredeyse tüm dağıtımlara sahiptir ve tohumlanmış rastgele sayı üretimini destekler. Misal:

ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)

-1

Tohumlanmış rasgele bir sayı döndüren bir işlev yazdım, Math.sin uzun bir rasgele sayıya sahip kullanır ve tohum sayıları almak için kullanır.

Kullanım:

seedRandom("k9]:2@", 15)

ilk parametre herhangi bir dize değeri ise tohumlanmış numaranızı döndürür; senin tohum. ikinci parametre kaç basamak döneceğidir.

     function seedRandom(inputSeed, lengthOfNumber){

           var output = "";
           var seed = inputSeed.toString();
           var newSeed = 0;
           var characterArray = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','U','R','S','T','U','V','W','X','Y','Z','!','@','#','$','%','^','&','*','(',')',' ','[','{',']','}','|',';',':',"'",',','<','.','>','/','?','`','~','-','_','=','+'];
           var longNum = "";
           var counter = 0;
           var accumulator = 0;

           for(var i = 0; i < seed.length; i++){
                var a = seed.length - (i+1);
                for(var x = 0; x < characterArray.length; x++){
                     var tempX = x.toString();
                     var lastDigit = tempX.charAt(tempX.length-1);
                     var xOutput = parseInt(lastDigit);
                     addToSeed(characterArray[x], xOutput, a, i); 
                }                  
           }

                function addToSeed(character, value, a, i){
                     if(seed.charAt(i) === character){newSeed = newSeed + value * Math.pow(10, a)}
                }
                newSeed = newSeed.toString();

                var copy = newSeed;
           for(var i=0; i<lengthOfNumber*9; i++){
                newSeed = newSeed + copy;
                var x = Math.sin(20982+(i)) * 10000;
                var y = Math.floor((x - Math.floor(x))*10);
                longNum = longNum + y.toString()
           }

           for(var i=0; i<lengthOfNumber; i++){
                output = output + longNum.charAt(accumulator);
                counter++;
                accumulator = accumulator + parseInt(newSeed.charAt(counter));
           }
           return(output)
      }

1
Bu şekilde üretilen sayı dizileri, rastgele sayı dizilerinin özelliklerine yaklaşmaz. Onunla 15 sayı oluşturun ve ortaya çıkan dize, neredeyse her anahtar için neredeyse her zaman 7 ile başlar.
Gabriel

-2

Sabit bir tohum için basit bir yaklaşım:

function fixedrandom(p){
    const seed = 43758.5453123;
    return (Math.abs(Math.sin(p)) * seed)%1;
}

-6

0 ile 100 arasında bir sayı için.

Number.parseInt(Math.floor(Math.random() * 100))

3
Soru tohumlama ilgili Math.randomher şekilde Math.randomaynı tohum ile tohumlanır, bu rasgele sayı aynı ardışık dizi üretecektir. Bu soru, her halükarda, fiili kullanımı / gösterimi ile ilgili değildir Math.random.
Jack Giffin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.