1. Skip to Menu
  2. Skip to Content
  3. Skip to Footer>

Rasgele sayı üretmek

PDF Yazdır e-Posta

Written by Admin

Posted on 05 Eylül 2010

Son Güncelleme 05 Eylül 2010

RASTGELE SAYILAR ÜRETME

Şimdide, kısaca popüler programlama uygulamalarından olan eğlenceli bir yöne bakalım; oyunlar ve simülasyonlar yazacağız. Bu kısımda ve gelecek kısımda yapısal programlama ile birden çok fonksiyonu içeren bir oyun programı geliştireceğiz. Bu program, şu ana kadar kullandığımız kontrol yapılarının çoğunu kullanmaktadır.

Oyun oynanan mekanlarda, en zor oyunlardan en kolay oyunlara kadar oyuncuları heyecanlandıran bir faktör vardır. Bu, şans faktörüdür. Oyuncuların ceplerindeki bir miktar parayı bir servete dönüştürme ihtimalleri bulunmaktadır. Şans faktörü, bilgisayar uygulamalarına C standart kütüphanesinde bulunan rand fonksiyonu sayesinde uygulanabilir.
Şimdi

1
i = rand( );

ifadesine bakalım. rand fonksiyonu 0 ile RAND_MAX (<stdlib.h> öncü dosyasında tanımlı bir sembolik sabit) değeri arasında bir tamsayı yaratır. ANSI standartlarına göre RAND_MAX, iki byte (16 bit) tamsayıların alabileceği en büyük değer olan 32767'den küçük olamaz. Bu kısımdaki programlar, RAND_MAX değeri en çok 32767 olan bir sistem için yazılmıştır.

Eğer rand düzgün olarak çalışarak tamsayılar oluşturursa, 0 ile RAND_MAX arasındaki tüm sayıların üretilme şansı (ihtimali) rand her çağrıldığında aynı olacaktır.

rand tarafından üretilen sayıların dizisi, genellikle bir uygulamada ihtiyaç duyulanlardan farklıdır. Örneğin, yazı tura oyununu gerçekleştiren bir uygulamada yazıyı belirtmek için sıfır, turayı belirtmek için bir kullanmak yeterli olur. Zar atma programı, 6 yüzlü bir zar için birden altıya kadar sayılara ihtiyaç duyacaktır.

rand fonksiyonunu daha iyi anlamak için, 6 yüzlü bir zarın 20 kez atılışını gerçekleyen bir program geliştirelim ve her atışta gelen sayıyı yazdıralım. rand fonksiyonunun prototipi <stdlib.h> içinde bulunabilir. Mod operatörünü (%) rand ile aşağıdaki biçimde kullandığımızda

1
rand( )%6

0 ile 5 dizisindeki (0,1,2,3,4,5) tamsayılar üretilecektir.Buna derecelendirme (scaling) denir. 6 sayısı, derecelendirme faktörü olarak adlandırılır.Daha sonra, önceki sonucumuza 1 ekleyerek sayıların dizisini kaydırırız. Şekil 5.7 , sonuçların 1-6 dizisi içinde olduğunu onaylamaktadır.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Şekil 5.7:fig05_07.c
1+rand( )%6 ile üretilmiş kaydırılmış ve
derecelendirilmiş tamsayılar */

#include <stdio.h>
#include <stdlib.h>
 
int main( )
{
int i;
 
for ( i = 1; i <= 20; i++ ) {
printf( "%10d", 1 + ( rand( ) % 6 ) );
 
if ( i % 5 == 0 )
printf( "\n" );
}//for
 
return 0;
}//main
 
 
5       5       3       5       5

2 4 2 5 5
5 3 2 2 1
5 1 4 6 4

Şekil 5.7 1+rand( )%6 ile üretilmiş tamsayılar

Bu sayıların yaklaşık olarak eşit ihtimalle ortaya çıktıklarını göstermek için, Şekil 5.8'de zarın 6000 kez atılmasını gerçekleyelim.1'den 6'ya kadar tüm tamsayılar yaklaşık olarak 1000 kez zarın üstüne gelmelidir.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* Şekil 5.8:fig05_08.c
6 yüzlü bir zarı 6000 kez atmak */
#include <stdio.h>
#include <stdlib.h>
 
int main( )
{
int yuz, atis, frekans1 = 0, frekans2 = 0,
frekans3 = 0, frekans4= 0,
frekans5= 0, frekans6= 0;
 
for ( atis = 1; atis <= 6000; atis++ ) {
yuz = 1 + rand() % 6;
 
switch ( yuz ) {
case 1:
++frekans1;
break;
case 2:
++frekans2;
break;
case 3:
++frekans3;
break;
case 4:
++frekans4;
break;
case 5:
++frekans5;
break;
case 6:
++frekans6;
break;
}//switch
}//for
 
printf( "%s%13s\n", "Yüz", "Frekans" );
printf( "1%15d\n", frekans1 );
printf( "2%15d\n", frekans2 );
printf( "3%15d\n", frekans3 );
printf( "4%15d\n", frekans4 );
printf( "5%15d\n", frekans5 );
printf( "6%15d\n", frekans6 );
return 0;
}//main

Yüz Frekans
1    987
2    984
3  1029
4    974
5  1004
6  1022

Şekil 5.8 6 yüzlü bir zarı 6000 kaz atmak

Program çıktılarından da görüldüğü gibi, derecelendirme ve kaydırma ile rand fonksiyonunun 6 yüzlü bir zarın atışını gerçekçi bir biçimde gerçeklemesini sağlattık. switch yapısında default kısmının kullanılmadığına dikkat ediniz. Ayrıca, sütunların başlıkları olarak yazdırılan "Yüz"ve "Frekans" karakter stringleri için %s dönüşüm belirteci kullandığımıza dikkat ediniz. 6.Ünitede dizileri çalıştıktan sonra, tüm switch yapısını tek satırda nasıl yazabileceğimizi göstereceğiz.

Şekil 5.7'deki programı yeniden çalıştırdığımızda

5 5 3 5 5
2 4 2 5 5
5 3 2 2 1
5 1 4 6 4

sonucunu elde ederiz.

Bu sonucun, daha önce yazdırılan sonuç ile aynı olduğuna dikkat ediniz. Öyleyse bu sayılar nasıl rasgele sayılar olabilir? Bu tekrar, rand fonksiyonunun önemli bir özelliğidir. Bir programın hatası ayıklanırken, bu tekrar programda yapılan düzeltmelerin doğru bir biçimde çalıştığını kanıtlamak için önemlidir.

rand fonksiyonu gerçekte, sahte rasgele sayılar üretir. rand fonksiyonunu tekrar tekrar çağırmak, rasgele gibi görünen bir dizi sayı oluşmasına sebep olur. Ancak bu dizi, program her çalıştırıldığında kendini tekrar etmektedir. Programın hataları tamamen ayıklandığında, her çalıştırılmada rasgele sayıların farklı bir dizisinin üretilmesi sağlatılabilir. Buna, rassallaştırma denir ve standart kütüphane fonksiyonu olan srand sayesinde yapılır. srand fonksiyonu, unsigned tipte bir tamsayıyı argüman olarak kullanır ve rand fonksiyonunu besleyerek, programın her çalıştırılışında farklı bir dizide rasgele sayılar oluşturulmasını sağlar.

srand fonksiyonunun kullanımı, Şekil 5.9'da gösterilmiştir. Programda, unsigned int için kısaltma olarak unsigned veri tipini kullandığımıza dikkat ediniz. int , hafızada en az iki byte içinde saklanır ve negatif ya da pozitif değerler alabilir. unsigned tipinde bir değişken de en az iki byte içinde saklanır. İki byte bir unsigned int yalnızca, 0'dan 65535'e kadar olan pozitif değerleri alabilir. Dört byte bir unsigned int yalnızca, 0'dan 4294967295'e kadar olan pozitif tamsayıları alabilir. srand fonksiyonu, unsigned bir değeri argüman olarak alır. %u dönüşüm belirteci, scanf ile unsigned bir değeri okumakta kullanılır. srand fonksiyonunun prototipi <stdlib.h> içinde bulunur.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* Şekil 5.9: fig05_09.c
Rasgele zar atma programı */
#include <stdlib.h>
#include <stdio.h>
 
int main( )
{
int i;
unsigned besleme;
 
printf( "Beslemeyi girin: " );
scanf( "%u", &besleme );
srand( besleme );
 
for ( i = 1; i <= 10; i++ ) {
printf( "%10d", 1 + ( rand() % 6 ) );
 
if ( i % 5 == 0 )
printf( "\n" );
}//for
 
return 0;
}//main

Beslemeyi girin: 67
1 6 5 1 4
5 6 3 1 2

Beslemeyi girin: 432
4 2 5 4 3
2 5 1 4 4

Beslemeyi girin: 67
1 6 5 1 4
5 6 3 1 2

Şekil 5.9 Zar atma programını rastgele hale getirme.

Programı bir çok kez çalıştırıp, sonuçları inceleyelim. Program her çalıştırıldığında ve farklı bir besleme sağlandığında, farklı bir dizide rastgele sayılar oluşturulduğuna dikkat ediniz.
Eğer her seferinde besleme girmeden rasgele hale getirmek istiyorsak, aşağıdaki gibi bir ifade kullanabiliriz:

1
srand ( time ( NULL ) );

Bu, bilgisayarın besleme değeri olarak otomatik bir biçimde kendi saatini okumasına sebep olur. time fonksiyonu, o andaki saati saniye biçiminde oluşturur. Bu değer, unsigned bir tamsayıya dönüştürülür ve rasgele sayı üretiminde besleme olarak kullanılır. time fonksiyonu argüman olarak NULL kullanır. (time programcının o günkü zamanı temsil eden bir dizeyi (string) elde etmesini sağlar ; NULL bu özelliği, time fonksiyonuna yapılan belirli bir çağrıda ortadan kaldırır.) time fonksiyonunun prototipi <time.h> içindedir.

rand ile elde edilen değerler her zaman 0  rand( )  RAND_MAX aralığındadır.

Daha önce, 6 yüzlü bir zarın atılışını gerçeklemek için nasıl bir ifade yazılacağını göstermiştik;

1
yuz =1 + rand ( ) % 6;

Bu ifade her zaman, yuz değişkenine 1 - 6 aralığından rasgele olarak bir tamsayı atar. Bu aralığın genişliğinin (aralıkta ard arda gelen tamsayı sayısı) 6 olduğuna ve aralığın başlangıcının 1 olduğuna dikkat ediniz. Az önceki ifadeye dönersek, aralığın genişliğinin rand'ı derecelendirmek için mod operatörüyle birlikte kullanılan sayı olduğunu görüyoruz. (bu örnekte 6) Aralığın başlangıç sayısı ise rand % 6'ya eklenen sayıdır.(bu örnekte 1).Bu sonucu aşağıdaki biçimde genelleştirebiliriz:

1
n = a + rand ( ) % b;

Burada a, kaydırma değeri (istenen aralığın başlangıç değeridir) b ise derecelendirme faktörüdür ( istenen arlığın genişliğidir). Alıştırmalarda ard arda gelen sayılar yerine bir kümedeki sayılar içinden rasgele sayı seçmenin de mümkün olduğunu göreceğiz.

    Genel Programlama Hataları 5.12
    Rasgele sayılar üretirken rand yerine srand kullanmak.