RASTGELE SAYI ÜRETİMİ Rasgele sayı üretimi matematiğin önemli konularından biridir. Rasgele sayılar ya da daha doğru ifadeyle, rasgele izlenimi veren sayılar (sözde rasgele sayılar - pseudo random numbers) istatistik, ekonomi, matematik gibi pekçok alanda olduğu gibi programcılıkta da kullanılmaktadır. Rasgele sayılar bir rasgele sayı üreticisi (random number generator) tarafından üretilirler. Rasgele sayı üreticisi aslında matematiksel bir fonksiyondur. Söz konusu fonksiyon bir başlangıç değeri alarak bir değer üretir. Daha sonra ürettiği her değeri girdi olarak alır ve tekrar başka bir sayı üretir . Üreticinin ürettiği sayılar rasgele izlenimi vermektedir. C standartları rasgele tamsayı üreten bir fonskiyonun standart bir C fonksiyonu olarak tanımlanmasını zorunlu kılmıştır. Bu fonksiyonun prototip bildirimi aşağıdaki gibidir: int rand(void); C standartları rand fonksiyonunun rasgele sayı üretimi konusunda kullanacağı algoritma ya da teknik üzerinde bir koşul koymamıştır. Bu konu derleyiciyi yazanların seçimine bağlı (implementation dependent) bırakılmıştır. rand fonksiyonunun prototipi standart bir başlık dosyası olan stdlib.h içinde bildirilmiştir. Bu yüzden rand fonksiyonunun çağırılması durumunda bu başlık dosyası "include" önişlemci komuduyla kaynak koda dahil edilmelidir. #include <stdlib.h> rand fonksiyonu her çağırıldığında [0, RAND_MAX] aralığında rasgele bir tamsayı değerini geri döndürür. RAND_MAX stdlib.h başlık dosyası içinde tanımlanan bir sembolik sabittir, derleyicilerin çoğunda RAND_MAX sembolik sabiti 32767 olarak, yani 2 byte'lık signed int türünün maximum değeri olarak tenımlanmıştır. Aşağıdaki program parçasında 0 ile 32767 arasında 10 adet rasgele sayı üretilerek ekrana yazdırılmaktadır : #include <stdio.h> #include <stdlib.h> int main() { int k; for (k = 0; k < 10; ++k) printf("%d ", rand()); return 0; } Yukarıdaki kaynak kodla oluşturulan programın her çalıştırılmasında ekrana aynı sayılar yazılacaktır. Örneğin yukarıdaki programı DOS altında Borland Turbo C 2.0 derleyicisi ile derleyip çalıştırdığımızda ekran çıktısı aşağıdaki gibi oldu: 346 130 10982 1090 11656 7117 17595 6415 22948 31126 Oluşturulan program her çalıştırıldığında neden hep aynı sayı zinciri elde ediliyor? rand fonksiyonu rasgele sayı üretmek için bir algoritma kullanıyor. Bu algoritma derleyiciden derleyiciye değişsede, rasgele sayı üretiminde kullanılan ana tema aynıdır. Bir başlangıç değeri ile işe başlanır. Buna tohum değer diyoruz. Bu değer üzerinde bazı işlemler yapılarak rasgele bir sayı elde edilir. Tohum değer üzerinde yapılan işlem bu kez elde edilen rasgele sayı üzerinde tekrarlanır... rand fonksiyonu rasgele sayı üretmek için bir başlangıç değeri kullanıyor. Rasgele sayı üreticilerinin (random number generator) kullandıkları başlangıç değerine tohum değeri (seed) denir. rand fonksiyonunu içeren programı her çalıştırdığımızda aynı tohum değerinden başlayacağı için aynı sayı zinciri elde edilecektir. İşte ikinci fonksiyon olan srand fonksiyonu, rasgele sayı üreticisinin tohum değerini değiştirmeye yarar: void srand (unsigned seed); srand fonksiyonuna gönderilen arguman rasgele sayı üreticisinin tohum değerini değiştir. srand() fonksiyonuna başka bir tohum değeri gönderdiğimizde fonksiyonun ürettiği rasgele sayı zinciri değişecektir. Yukarıdaki programa bir ilave yaparak yeniden çalıştırın. #include <stdio.h> #include <stdlib.h> int main() { int k; srand(100); for (k = 0; k < 10; ++k) printf("%d ", rand()); return 0; } 1862 11548 3973 4846 9095 16503 6335 13684 21357 21505 Ancak bu kez oluşturduğumuz programı her çelıştırdığımızda yine yukarıdaki sayı zinciri elde edilecek. Zira rand fonksiyonunun kullanmakta olduğu önceden seçilmiş (default) tohum değerini kullanmasak da, rasgele sayı üretme mekanizması bu kez her defasında bizim srand fonksiyonuyla göndermiş olduğumuz tohum değerini kullanacak. Programı birkaç kere çalıştırıp aynı sayı zincirini ürettiğini test edin. Bir çok durumda programın her çalıştırılmasında aynı rasgele sayı zincirinin üretilmesi istenmez. Programın her çalışmasında farklı bir sayı zincirinin elde edilmesi için programın her çalışmasında srand fonksiyonu başka bir değerle, rasgele sayı üreticisinin tohum değerini set etmelidir. Bu amaçla çoğu zaman time fonksiyonundan faydalanılır: time fonksiyonu standart bir C fonksiyonudur, prototip bildirimi standart bir başlık dosyası olan time.h içindedir. time fonksiyonu, parametre değişkeni gösterici olan bir fonksiyon olduğundan ileride detaylı olarak ele alınacaktır. Şimdilik time fonksiyonunu işimizi görecek kadar inceleyeceğiz. time fonksiyonu 0 argumanıyla çağırıldığında 01.01.1970 tarihinden fonksiyonun çağırıldığı ana kadar geçen saniye sayısını geri döndürür. Fonksiyonun geri dönüş değeri derleyicilerin çoğunda long türden bir değerdir. İçinde rasgele sayı üretilecek programda, srand fonksiyonuna arguman olarak time fonksiyonunun geri dönüş değeri arguman olarak gönderilirse, program her çalıştığında rasgele sayı üreticisi başka bir tohum değeriyle ilk değerini alacaktır, böyle progarmın her çalıştırılmasında farklı sayı zinciri üretilecektir. srand(time(0)); srand fonksiyonunun bu şekilde çağırımı derleyicilerin çoğunda randomize isimli bir makro olarak tanımlanmıştır. Yukarıdaki fonksiyon çağırımı yerinde bu makro da çağırılabilir. Makrolar konusunu ileride detaylı olarak inceşeyeceğiz : randomize(); Yukarıdaki örnek programı her çalıştığında farklı sayı zinciri üretecek hale getirelim: #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int k; srand(time(0)); for (k = 0; k < 10; ++k) printf("%d ", rand()); return 0; } Programlarda bazen belirli bir aralıkta rasgele sayı üretmek isteyebiliriz. Bu durumda mod operatörü kullanılabilir : rand() % 2 Yalnızca 0 ya da 1 değerini üretir. rand() % 6 0 - 5 aralığında rasgele bir değer üretir rand() % 6 + 1 1 - 6 aralığında rasgele bir değer üretir. rand() % 6 + 3 5 - 8 aralığında rasgele bir değer üretir. Karmaşık olasılık problemleri, olsılığa konu olayın bir bilgisayar programı ile simule edilemesi yoluyla çözülebilir. İyi bir rasgele sayı üreticisi kullanıldığı takdirde, olasılığa konu olay bir bilgisayar programı ile simule edilir ve olay bilgisayarın işlem yapma hızından faydanlanılarak yüksek sayılarda tekrar ettirilir. Şüphesiz hesap edilmek istenen olaya ilişkin olasılık değeri, yapılan tekrar sayısına ve rasgele sayı üreticisinin kalitesine bağlı olacaktır. Aşağıdaki kod yazı tura atılması olayında tura gelme olasılığını hesap etmektedir. #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #define TIMES 100 #define HEADS 1 int main() { long heads_counter = 0; long k; for (k = 0; k < TIMES; ++k) if (rand() % 2 == HEADS) heads_counter++; printf("tura gelme olasılığı = %lf", (double) heads_counter / TIMES); getch(); return 0; } Yukarıdaki programı TIMES sembolik sabitinin farklı değerleri için çalıştırdığımızda ekran çıktısı aşağıdaki şekilde oldu: #define TIMES 100 tura gelme olasılığı = 0.480000 #define TIMES 500 tura gelme olasılığı = 0.496000 #define TIMES 2500 tura gelme olasılığı = 0.506800 #define TIMES 10000 tura gelme olasılığı = 0.503500 #define TIMES 30000 tura gelme olasılığı = 0.502933 #define TIMES 100000 tura gelme olasılığı = 0.501450 #define TIMES 1000000 tura gelme olasılığı = 0.500198 #define TIMES 10000000 tura gelme olasılığı = 0.500015 #define TIMES 2000000 tura gelme olasılığı = 0.500198 Aşağıdaki main fonksiyonunda uzunlukları 3 - 8 harf arasında değişen ingiliz alfabesindeki harfler ile oluşturulmuş rasgele 10 kelime ekrana yazdırılmaktadır: #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #define TIMES 20 void write_word(void); int main() { int k; srand(time(0)); for (k = 0; k < TIMES; ++k) { write_word(); putchar('_); } getch(); return 0; } void write_word(void) { int len = rand() % 6 + 3; while (len--) putchar('A' + rand() % 26); } Programın ekran çıktısı: USPFY KDUP BUQJB LMU PKPBKFA WQM NQHPTXL QCANSTEH XZU MNRI OXUTGISR XBNG BYOQ TFO MQUCSU OIHFPJ BLVD WDDEM OHMHJBZY ALIAQ
8 Temmuz 2020 Çarşamba
C programlana rastgele sayı üretme
Kaydol:
Kayıt Yorumları (Atom)
Hiç yorum yok:
Yorum Gönder
Her yorum bilgidir. Araştırmaya devam...