bilgiz.org

C# İle biLGİsayar programlama temelleri (C# Programlama Kitabı) Svetlin Nakov & Co

  • 9.4.1 Daha Yapılandırılmış Program ve Daha Fazla Okunabilir Kod
  • 9.4.2 Yinelenen Koddan Kaçının



  • Sayfa16/31
    Tarih02.07.2017
    Büyüklüğü3.36 Mb.

    Indir 3.36 Mb.
    1   ...   12   13   14   15   16   17   18   19   ...   31

    NOT 10111011 = 01000100
    C# dilinde bitsel negation ~ ile temsil edilir:


    int result = ~integer1;



    8.2.10 Onaltılık Sayılar
    Onaltılık sayılar için sistem tabanı olarak 16 kullanılır, 0 'dan 15 dahil tüm olası 16 değeri temsil eden basamakların kullanıldığını ifade eder. Zaten önceki bölümlerdeki tablolardan birinde gösterdiğimiz gibi onaltılık sistemde sayıların gösterilmesi için 0-9 basamakları ve A-F Latin karakterleri kullanılır. Bunların her birinin karşılık gelen bir değeri vardır:
    A=10, B=11, C=12, D=13, E=14, F=15
    Onaltılık sayılar için şu örnekler verilebilir: D2, 1F2F1, ve D1E.
    Ondalık sisteme dönüştürmek için ilk önce en sağdaki basamağı 160 ile çarparız, sonra sola doğru sonraki basamağı 161ile çarparız ve daha sonra sola doğru bir sonraki basamağı 162 ile çarparız, ve bunun gibi devam eder. Sonunda hepsini toplayarak sonucu buluruz.
    D1E(16) = E*160 + 1*161 + D*162 = 14*1 + 1*16 + 13*256 = 3358(10).
    Onaltılık rakam sistemine dönüştürmek için ondalık sayıyı ard arda 16 ile böleriz ve kalanları tersten alırız. Örnek:

    3358 / 16 = 209 + kalan 14 (E)

    209 / 16 = 13 + kalan 1 (1)

    13 / 16 = 0 + kalan 13 (D)


    Kalanlar tersten alınınca sayı D1E(16) olur.

    8.2.11 İkili Sistemden Onaltılık Sayılara Hızlı Dönüştürme
    İkili sistemden onaltılık sayılara hızlı dönüştürme hızlı ve kolay şekilde yapılabilir. Bunun için ikili sayı dört bitlik gruplar (yarımşar baytlar) halinde bölünür. Herhangi bir gruptaki basamaklar dörtten azsa, sayının değerini değiştirmeden en soldaki konumlara 0’lar eklenerek dörtlü grup tamamlanır. Bölünme ve sıfırların da, gerekiyorsa eklenmesinden sonra, tüm gruplara karşılık gelen onaltılık basamaklar yan yana dizilir ve sonuç elde edilir. Bir örnek aşağıda verilmiştir:
    1110011110(2) sayısına bir bakalım:


        1. Yarım baytlara böleriz ve baştaki sıfırları ekleriz.

    Örnek: 0011 1001 1110.

        1. Her yarım baytı karşılık gelen onaltılık basamak ile yer değiştiririz ve böylece

    sonuç olarak 39E(16) elde edilir.
    Bu nedenle, 1110011110 (2) = 39E(16).

    8.2.12 Sayı Sistemleri – Özet
    Özetle, kısa ve net bir şekilde tekrarlayarak formüle edecek olursak, bir konumsal sayı sisteminden diğerine dönüştürmek için kullanılan algoritmalar:


    • Ondalık sayıdan k-tabanlı sayı sistemine dönüştürmek için ondalık sayı ard arda yinelenen bir şekilde k sayısına bölünür ve her bölme işleminden sonra elde edilen kalan not edilir. Yinelenen bölme işlemleri son bulduğunda baştan sona dek elde edilen kalanlar sondan başa olacak şekilde ters sırada yazılarak sonuç olan sayıyı belirler.

    • k-tabanlı sayı sisteminden ondalık sayıya dönüştürmek için en sağdaki basamak k0 ile çarpılır, sağdan sola bir önceki basamak k1 ile çarpılır, bir önceki basamak k2 ile çarpılır, ve bunun gibi devam eder ve çarpımlar toplanır.

    • k-tabanlı sayı sisteminden p-tabanlı sayı sistemine (onaltılık ve ikili sayı sistemleri hariç) dönüştürmek için sayı önce ondalık sisteme dönüştürülür, sonra ondalıktan istenen sayı tabanına çevrilir.

    • İkili ve onaltılık sayı sistemleri arasındaki dönüştürmeler dörtlü–bit gruplarının karşılık gelen onaltılık basamağa çevrilmesi ile ve ikili sisteme dönüştürmek için de benzer şekilde her onaltılık basamağın dörtlü-bit grubuna çevrilmesi ile yapılır.



    8.3 Sayıların Gösterimi
    İkili kod bilgisayar makinelerinin işletme belleğinde veri depolamak için kullanılır. Veri türüne bağlı olarak (dizeler, tamsayılar ve ondalık kısmı olan gerçek sayılar) saklamak istediğimiz bilgi özel bir şekilde temsil edilmektedir. Bu veri türüne göre belirlenir.
    Bir üst düzey dili kullanırken bile bir programcının, makinenin çalışma belleğinde verinin nasıl tahsis edildiğini bilmesi gerekir. Eldeki harici taşıyıcılar üzerinde depolansa da bu durum yine geçerlidir, çünkü veri işlendiğinde, çalışma belleğinde yer alacaktır.
    Bu bölümde farklı veri türlerini sunmak ve işlemek için başvurulan farklı yollara göz atacağız. Genel olarak bunlar bit, bayt (byte) ve makine sözcüğü (word) kavramlarına dayanmaktadır.
    Bit 0 veya 1 ikili değerlerinden birine sahip olan bilgi birimidir.
    Bellekteki bilgiler tek bir bayttan oluşan 8 bitlik diziler halinde toplanır.
    Bir aritmetik cihaz verilerini işlemek için, belirli bir sayıda bayt (2, 4 veya 8) bellekte yer almalıdır, bu bir makine sözcüğünü oluşturur. Bunlar her programcının bilmesi ve anlaması gerekli kavramlardır.

    8.3.1 Tamsayıların Bellekte Gösterimi
    Şimdiye kadar ele almadığımız konulardan biri de sayıların işaretleridir. Tamsayılar bellekte iki şekilde temsil edilir: işaretli yada işaretsiz. Sayılar işaretli olarak temsil edildiğinde, bir işaret biti tanıtılmalıdır. Bu bit en yüksek seviyedeki bittir, ve negatif sayılar için 1 değerine ve pozitif sayılar için 0 değerine sahiptir. Bitlerin geri kalanı bilgilendiricidir ve sadece sayı değerini temsil ederler (içerirler). İşaretsiz bir sayı olması durumunda, tüm bitler sayı değerini temsil eder.

    8.3.2 İşaretsiz Tamsayılar
    İşaretsiz tamsayılar için 1, 2, 4 veya 8 bayt belleğe tahsis edilir. Verilen bir sayının gösterimi için kullanılan bayt sayısına bağlı olarak, değişken boyutlu ve farklı kapsamda gösterimler oluşur. n bayt sayesinde [0, 2n-1] aralığındaki tüm tamsayılar temsil edilebilir:

    Sayının bellekte temsili için gerekli bayt sayısı

    Aralık

    Üslü gösterim

    Sayısal gösterim

    1

    0 ÷ 28-1

    0 ÷ 255

    2

    0 ÷ 216-1

    0 ÷ 65,535

    4

    0 ÷ 232-1

    0 ÷ 4,294,967,295

    8

    0 ÷ 264-1

    0 ÷ 18,446,744,073,709,551,615


    Örnek olarak ikili gösterimi 10011110(2) olan 158 sayısının bir tek bayt ve bir çift bayt ile temsil edilişini vereceğiz:


    1. 1 bayt ile temsili:

    0

    0

    1

    1

    1

    1

    0





    2. 2 bayt ile temsili:



    0

    0

    0

    0

    0

    0

    0

    0

    1

    0

    0

    1

    1

    1

    1

    0





    8.3.3 Negatif Sayıların Temsili
    Negatif sayılar için 1, 2, 4 veya 8 bayt bilgisayarın belleğinde tahsis edilir. En yüksek seviyeli (en soldaki bit) bir işaret anlamına sahiptir ve sayı işareti hakkında bilgi taşır. Daha önce belirtildiği gibi, işaret biti 1 değerine sahip olduğunda sayı negatiftir, aksi takdirde sayı pozitiftir.
    Bir sonraki tablo, bilgisayarda gösterimi için kullanılan bayt sayısına göre işaretli tamsayı değerlerinin aralığını göstermektedir:

    Sayının bellekte temsili için gerekli bayt sayısı

    Seviye

    Üslü gösterim

    Sayısal gösterim

    1

    -27 ÷ 27-1

    -128 ÷ 127

    2

    -215 ÷ 215-1

    -32,768 ÷ 32,767

    4

    -231 ÷ 231-1

    -2,147,483,648 ÷ 2,147,483,647

    8

    -263 ÷ 263-1

    -9,223,372,036,854,775,808 ÷
    9,223,372,036,854,775,807



    Negatif sayıları kodlamak için, düz, ters ve ek kod kullanılır. Bu üç gösterimin tümünde işaretli tamsayılar şu aralıktadır: [-2n-1, 2n-1-1]. Pozitif sayılar hep aynı şekilde temsil edilmektedir ve düz, ters ve ek kodların hepsi aynı gösterimdir.
    Düz kod (işaretli büyüklük) sayının en basit temsilidir. En yüksek seviyedeki bit işaret bilgisini taşır ve bitlerin kalanı sayının mutlak değerini tutar. Bazı örnekler aşağıda verilmiştir:
    İşaretli büyüklüğü 3 olan sekiz bit uzunluğundaki sayı 00000011 olarak temsil edilir.
    İşaretli büyüklüğü –3 olan sekiz bit uzunluğundaki sayı 10000011 olarak temsil edilir.
    Ters kod (1’in tümleyeni) sayının işaretli büyüklüğünü oluşturan bitlerin tümünü tersine çevirerek (inversion: Tüm 1’leri 0 ile ve tersi tüm 0’ları 1 ile yer değiştirerek). Bu kod aritmetik işlemlerden toplama ve çıkarma için uygun değildir, çünkü çıkarma gerekli olduğu takdirde farklı bir şekilde yürütülür. Ayrıca işaret bitinin bilgi taşıyan bitlerden ayrı olarak işlenmesi gerekir. Bu dezavantaj ek kod kullanılarak önlenir. Çıkarma işleminin yerine negatif bir sayı ile toplama yapılır. İkinci yöntemde gerekli negatif sayıyı elde etmek için 2n ile başlayan ve sayının mutlak değerini içeren bir gösterimde toplama işlemi gerçekleştirilir. Örnek:
    -127 sayısının işaretli büyüklüğü 1 1111111 olarak ve 1 ’in tümleyeninde 1 0000000 olarak temsil edilir.
    3 sayısının işaretli büyüklüğü 0 0000011 olarak ve 1 ’in tümleyeninde 0 1111100 olarak temsil edilir.
    Ek kod (2 ’nin tümleyeni) ters kod temsilindeki sayıya toplama aracılığıyla 1 ’in eklenmesiyle elde edilen sayıdır. Örnek:
    -127 sayısının ek kod temsili 1 0000001 ’dir.
    Binary Coded Decimal sisteminde, aynı zamanda BCD kodu olarak da bilinir, bir byte içinde iki ondalık basamak kaydedilir. Her bir yarım bayt içinde tek bir ondalık basamak kodlanır. Bu şekilde temsil edilen sayılar bitiştirilebilir, yani bitişik yazım şeklinde ifade edilebilir. Tek bir ondalık basamağı bir bayt içinde temsil edersek, bitiştirilmemiş biçim elde ederiz.
    Modern işlemciler negatif sayıların temsilinde yukarıda anlattığımız kodlardan birini veya birkaçını kullanırlar, en yaygın kullanılan yöntem 2 ’nin tümleyenidir.

    8.3.4 C# Dilinde Tamsayı Türleri
    C# dilinde sekiz tamsayı veri türü vardır, işaretli veya işaretsiz. Her bir tür için ayrılan byte miktarına bağlı olarak, farklı değer aralıkları belirlenmiştir. Türlerin açıklamalarını aşağıdaki tabloda bulacaksınız:

    Tür

    Boyut

    Aralık

    .NET Framework Türü

    sbyte

    8 bit

    -128 ÷ 127

    System.SByte

    byte

    8 bit

    0 ÷ 255

    System.Byte

    short

    16 bit

    -32,768 ÷ 32,767

    System.Int16

    ushort

    16 bit

    0 ÷ 65,535

    System.UInt16

    int

    32 bit

    -2,147,483,648 ÷ 2,147,483,647

    System.Int32

    uint

    32 bit

    0 ÷ 4,294,967,295

    System.UInt32

    long

    64 bit

    –9,223,372,036,854,775,808 ÷ 9,223,372,036,854,775,807

    System.Int64

    ulong

    64 bit

    0 ÷ 18,446,744,073,709,551,615

    System.UInt64



    En çok kullanılanlara kısaca bakacağız. En sık kullanılan tamsayı int türüdür. Bu 2 ’nin tümleyeni olan bir 32-bit sayı olarak temsil edilir ve [-231, 231-1] aralığında bir değer alır. Bu tür değişkenler en sık döngüleri çalıştırmak için, endeks dizilerinde ve diğer tamsayı hesaplamalarında kullanılır. int türünde bir değişken örneğinin bildirildiği bir örnek aşağıdaki verilmiştir:

    int integerValue = 25;

    int integerHexValue = 0x002A;

    int y = Convert.ToInt32("1001", 2); // Converts binary to int




    long türü C# dilinde tanımlı en büyük işaretli tamsayı türüdür. 64-bit (8-bayt) boyutu vardır. long türü değişkenlerin değerini verirken Latin harfleri "l" veya "L" tamsayı değişmezinin sonuna yerleştirilir. Bu pozisyonda yerleştirilen bu değiştiricinin anlamı, değişmezin long türünde bir değer olduğunu belirtmesidir. Bunun yapılmasına neden, varsayılan olarak tüm tamsayı değişmezlerinin int türünde olmasıdır. Bir sonraki örnekte, long türü değişkenleri bildireceğiz ve onlara 64-bit değer vereceğiz:


    long longValue = 9223372036854775807L;

    long newLongValue = 932145699054323689l;




    Önemli bir durum kullanılan türün temsil edebileceği en büyük sayı aralığını geçmemektir. Bununla birlikte, C# dili bir taşma meydana geldiğinde olacakları kontrol etme olanağını sunmaktadır. Bu checked ve unchecked bloklar aracılığıyla yapılır. Birincisi değişken aralığı aşıldığında bir istisna (System.OverflowException türünde) atmak gerektiğinde kullanılır. Aşağıdaki programlama kodu tam olarak bunu yapmaktadır:

    checked

    {

    int a = int.MaxValue;



    a = a + 1;

    Console.WriteLine(a);

    }



    Kod fragmanı denetlenmeyen (unchecked) bir blok olsaydı, herhangi bir özel durum olmayacak ve çıkış sonucu yanlış olacaktı:

    -2147483648


    Bu bloklar kullanılmadığı zaman C# derleyicisi varsayılan olarak kontrolsüz modda çalışır.
    C# dili daha büyük bir aralıktaki pozitif sayı kapsamındaki değişkenler için gerektiğinde yararlı olabilen işaretsiz türleri içerir. Aşağıda işareti olmayan değişkenleri bildiren bazı örnekler verilmiştir. ulong türünün son eklerine (tüm U, L, u, l kombinasyonları) dikkat etmelisiniz.

    byte count = 50;

    ushort pixels = 62872;

    uint points = 4139276850; // or 4139276850u, 4139276850U

    ulong y = 18446744073709551615; // or UL, ul, Ul, uL, Lu, lU





    8.3.5 Büyük-Endian ve Küçük-Endian Gösterimi
    Bir bayt uzunluğundan büyük tamsayıların gösteriminde bellekten baytlar iki yolla getirilebilir:


    • Küçük-Endian (Little-Endian: LE): Baytlar en düşük seviyeden en yüksek seviyeye olmak üzere soldan sağa doğru sıralanır. Bu temsil, Intel x86 ve x64 Intel mikroişlemci mimarisinde kullanılmıştır.

    • Büyük-Endian (Big-Endian: BE): Baytlar en yüksek seviyeden başlayarak en düşük seviyeye olmak üzere soldan sağa doğru sıralanır. Bu temsil PowerPC, SPARC ve ARM mikroişlemci mimarisinde kullanılmıştır.


    A8B6EA72(16) sayısının her iki bayt sıralamasında gösterimi ile ilgili bir örnek aşağıda verilmiştir:


    C# dilinde hangi standartta sıralama yapılacağını belirlememize yardımcı bazı sınıflar vardır. Bu İnternet üzerinden bilgi akışı gönderme/alma gibi işlemler için veya farklı standartlara göre yapılan cihazlar arasındaki diğer iletişim türleri için önemlidir. Örneğin BitConverter sınıfının IsLittleEndian alanı hangi modda sınıfın çalışıyor olduğunu ve mevcut bilgisayar mimarisinde verilerin nasıl saklandığını gösterir.

    8.3.6 Gerçek Kayan Nokta Sayılarının Gösterimi
    Gerçek sayılar bir tamsayı ve ondalık kısımdan oluşmaktadır. Bilgisayarlarda kayan noktalı sayılar olarak temsil edilmektedir. Aslında bu temsil önde gelen mikroişlemci üreticileri tarafından kabul edilen Kayan Nokta Aritmetik (IEEE 754) Standartı’ndan (Standard for Floating-Point Arithmetic) geliyor. Çoğu donanım platformları ve programlama dilleri bu standardın şartlarına göre hesaplama yapılmasına izin verir ve gerektirir. Standart şunu tanımlamaktadır:


    • Aritmetik formatlar: İkili ve ondalık veri formatında sonlu sayıda basamaktan oluşan bir kayan nokta.

    • Değişim formatları: Etkili ve kompakt bir formda veri alışverişi için kullanılabilen kodlama (bit dizileri).

    • Yuvarlama algoritmaları: Hesaplamalar sırasında sayıları yuvarlama için kullanılan yöntemler.

    • İşlemler: Aritmetik ve diğer aritmetik biçimlerdeki işlemler.

    • İstisnalar: Sıfıra gibi bölünme gibi olağanüstü olaylar, taşma ve diğerleri için sinyallerdir.


    Rasgele bir gerçek sayı R IEEE-754 standardına göre şu şekilde temsil edilir:
    R = M * qp
    burada M sayının mantisidir, p üstür, ve q sayının içinde bulunduğu sayı sistemine göre tabanı belirtir. Mantis pozitif veya negatif ortak kesir olmalıdır, |M|<1 ve üs - pozitif veya negatif tamsayıdır.

    Sayıların temsilinde söz edilen yöntemde, her kayan nokta sayısı özetle şu biçime sahip olacaktır: ±0,M*q±p.
    Kayan noktalı formatta sayıların gösteriminde, özellikle ikili sayı sistemi kullanıldığında R = M * 2p yazılabilir. Bilgisayar belleğindeki gerçek sayıların bu gösteriminde üssü değiştirdiğinizde, mantisteki ondalık nokta hareket eder ("yüzer"). Kayan-noktalı gösterim biçiminin yarı-logaritmik formu vardır. Açıklaması aşağıdaki şekilde verilmiştir:


    8.3.6.1 Kayan Nokta Sayılarının Gösterimi – Örnek
    Kayan nokta sayısının bellekte nasıl gösterildiğine bir örnek aşağıda verilmiştir. IEEE-754 standardına göre 32-bit (bir duyarlıkta) kayan nokta formatında bir sayı olan -21,15625 sayısını yazmak istiyoruz. Bu formatta, 23 bit mantis için kullanılır, üs için 8 bit, ve işaret için 1 bit kullanılır. Buna göre sayıyı aşağıdaki gibi gösterebiliriz:

    Sayı işareti negatiftir, mantisin eksi işareti olduğu anlamına gelir:
    S = -1
    Üssün değeri 4’tür (kayan sırada temsil edildiğinde):
    p = (20 + 21 + 27) - 127 = (1+2+128) – 127 = 4
    Gerçek değere dönüştürmek için 127 çıkarmalıyız, çünkü ek kod temsilinde sıfır konumundan başlayarak 8 bit ile çalışıyoruz, (127 = 27-1).
    Mantisin değeri (işareti dikkate alınmaksızın) aşağıdaki gibi hesaplanır:

    M = 1 + 2-2 + 2-4 + 2-7 + 2-9 =

    = 1 + 0.25 + 0.0625 + 0.0078125 + 0.001953125 =



    = 1.322265625
    Dikkat etmelisiniz ki, mantisin ikili gösteriminde eksik olan 1’i de eklemeliyiz. Bunu yaptık çünkü mantis her zaman normalizedir ve varsayılan bir 1 ile başlar.
    Sayının değeri, aşağıdaki formül kullanılarak hesaplanır, R = M * 2p, bizim örneğimizde aşağıdaki gibidir:
    R = -1,3222656 * 24 = -1,322265625 * 16 = -21,1562496 ≈ -21,15625

    8.3.6.2 Mantis Normalleştirme
    Üslü kullanımı daha etkin hale getirmek için mantisin en yüksek seviyedeki biti 1 olmalıdır. Bu şartı yerine getiren her mantis normalizedir. IEEE-754 standardı olarak, mantisin tamsayı kısmının değeri varsayılan olarak 1’dir, bunun anlamı mantis her zaman 1 ile 2 arasında kalan bir sayı olmalıdır.
    Hesaplamalar sırasında bu şartı yerine getirmez bir sonuç elde edilirse, bu normalleşmenin ihlali anlamına gelir. Sayı daha fazla işleme girmeden öncesinde normalleştirilmelidir, ve bu amaçla mantisdeki ondalık nokta taşınır ve ilgili üs değişikliği yapılır.

    8.3.7 C# Dilinde Gerçek Sayı Türleri – Float ve Double
    C# dilinde kayan nokta sayılarını temsil edebilen iki tür vardır: float türü kayan noktalı 32-bit bir gerçek sayıdır ve adı tek duyarlıklı kayan nokta sayısı olarak kabul edilmektedir. double, kayan noktalı 64-bit bir gerçek sayıdır ve adı çift duyarlıklı kayan nokta sayısı olarak kabul edilmektedir. Gerçek veri tipleri ve onlarla ilgili aritmetik işlemler IEEE 754-1985 standardına göre belirtilen şartnameye uygundur. Aşağıdaki tablo, iki türün en önemli özellikleri sunulmuştur:

    Tür

    Boyut

    Aralık

    Anlamlı Basamak Sayısı

    .NET Framework Türü

    float

    32 bit

    ±1.5 × 10−45 ÷ ±3.4 × 1038

    7

    System.Single

    double

    64 bit

    ±5.0 × 10−324 ÷ ±1.7 × 10308

    15-16

    System.Double


    float türünde 7 önemli basamak içeren bir mantis vardır, double türü 15-16 anlamlı basamak saklar. Kalan bitler mantis işaretini ve üs değerini belirtmek için kullanılır. double türü daha fazla sayıda anlamlı basamağa sahip olmasının yanı sıra ayrıca daha büyük bir üsse de sahiptir, ki bu da kabul edilebilir değerlerin daha geniş bir kapsama sahip olduğu anlamına gelir. float ve double türlerinde değişken bildiren bir örnek aşağıda verilmiştir:

    float total = 5.0f;

    float result = 5.0f;

    double sum = 10.0;

    double div = 35.4 / 3.0;

    double x = 5d;



    Denklemin sağ tarafında görünen sayıların ardına eklenen sonekler, sayının hangi türde ele alınacağını belirterek (f float için, d double için) bu amaca hizmet eder. Bu durumda sonekler yerinde ve uygun kullanılmıştır, çünkü varsayılan olarak 5,0 double sayıdır ve 5 int olarak yorumlanır.



    C# dilinde, varsayılan olarak kayan noktalı sayıların değişmezleri double türündendir.


    Tamsayılar ve kayan noktalı sayıların her ikisi de belirli bir ifadede mevcut olabilir. Bu durumda, tamsayı değişkenleri kayan nokta değişkenine dönüştürülür ve sonuç aşağıdaki kurallara göre tanımlanır:


    1. Kayan nokta türlerinin herhangi biri double türünde ise, sonuç double (veya bool) olacaktır.

    2. İfadede hiçbir double türü yoksa, sonuç float veya bool olur.
    Matematiksel işlemlerin çoğu özel bir değere sahip olmayan sonuçlar verebilir, "+/- sonsuzluk" değeri, veya NaN ("Bir Sayı Değildir" anlamına gelen) gibi bu değerler, sayı değildir. Bir örnek aşağıda verilmiştir:

    double d = 0;

    Console.WriteLine(d);

    Console.WriteLine(1/d);

    Console.WriteLine(-1/d);

    Console.WriteLine(d/d);



    Bunu çalıştırmak isterseniz aşağıdaki sonucu alırsınız:

    0.0

    Infinity


    -Infinity

    NaN



    Yukarıdaki kodu int yerine double kullanarak çalıştırdığınızda, System.DivideByZeroException istisnası fırlatılır, çünkü bir tamsayının 0 ile bölünmesi izin verilen bir işlem değildir.

    8.3.8 Kayan Noktalı Sayıları Kullanırken Karşılaşılan Hatalar
    IEEE 754 standardına göre sunulan kayan noktalı sayılar (birkaç yüz basamaklı) çok büyük sayıların ve aynı zamanda sıfıra çok yakın (ilk anlamlı basamak öncesinde noktadan sonraki yüzlerce basamağın var olduğu) sayıların kullanıldığı fizik hesaplamaları için çok uygundur. Bu sayılarla çalışırken, IEEE 754 formatı son derece uygundur, çünkü üs içinde sayının kuvvetini tutar, ve mantis sadece anlamlı basamakları saklamak için kullanılır. 15-16 basamaklı kesinlikteki 64-bit kayan noktalı sayılar için ondalık noktanın sola ve sağa 300 konum hareket etmesi (taşınması) mümkündür.
    Ne yazık ki her gerçek sayının IEEE 754 formatında tam bir temsili yoktur, çünkü her sayı 2’nin negatif üslerini içeren ve sınırlı sayıdaki terimlerinden oluşan birer polinom olarak yazılamaz. Bu günlük basit finansal hesaplamalar için kullanılan sayılar için de aynen geçerlidir. Örneğin 0,1 sayısının temsilinde 32-bit kayan nokta değeri 0,099999994 olarak sunulmuştur. Uygun yuvarlama kullanılırsa, sayı 0,1 olarak kabul edilebilir, ancak hata birikmiş ve ciddi sapmalara neden olabilir, özellikle finansal hesaplamalar için. Örneğin her birinin birim fiyatı 0,1 EUR olan 1000 elemanı toplarken 100 EUR bir miktar almalısınız, ancak hesaplamalar için 32-bit kayan noktalı sayıları kullanırsanız sonuç 99,99905 olacaktır. İkili rakam sisteminde ondalık gerçek sayıların yanlış sunumundan kaynaklanan hataları kanıtlayan bir örnek C# dili için aşağıda verilmiştir:

    float sum = 0f;

    for (int i = 0; i < 1000; i++)

    {

    sum += 0.1f;



    }

    Console.WriteLine("Sum = {0}", sum);

    // Sum = 99.99905



    Bu örneği çalıştırdığınızda veya daha çarpıcı hataları almak için değiştirirseniz kolayca hesaplama hatalarını görebilirsiniz.
    8.3.9 Kayan Noktalı Sayıların Duyarlıkları
    Kayan noktalı sayılar ile ilgili hesaplamaların sonuçları ve doğruluğu aşağıdaki parametrelere bağlıdır:


    1. Sayı gösteriminin kesinliği

    2. Kullanılan sayı yöntemlerinin kesinliği

    3. Yuvarlamalardan vb kaynaklanan hataların değeri

    Kayan noktalı sayılar ile yapılan hesaplamalar yanlış olabilir, çünkü bunlar ancak belirli bir duyarlığa kadar bellekte temsil edilirler.


    Bir örnek olarak aşağıdaki kod parçasına bakalım:

    double sum = 0.0;

    for (int i = 1; i <= 10; i++)

    {

    sum += 0.1;



    }

    Console.WriteLine("{0:r}", sum);

    Console.WriteLine(sum);



    Döngü içinde yürütülmesi sırasında sum değişkenine 1/10 değeri eklenir. WriteLine() yöntemi çağrıldığında, değişkenin (yuvarlatılmamış) değerini yazdırmak için gidiş-dönüş biçimi belirteci kullanılır : "{0:r}" ve bundan sonra bir format belirtmeden aynı değeri yazdırıyoruz. Programı çalıştırdığınızda sonuç olarak 1,0 döndürmesi beklenir, ancak gerçekte yuvarlama kapatıldığında, Program doğruya yakın ancak yine de farklı bir değer döndürür:

    0.99999999999999989

    1



    Örnekten de görülebileceği gibi, .NET Framework’te kayan noktalı sayılar yazdırılırken IEEE 754 formatında rastlanılan yanlış gösterim hataları azaltması amacıyla varsayılan olarak yuvarlatılmaktadır. Yukarıdaki hesaplama sonucu açıkçası yanlıştır, ancak yuvarlama sonrasında doğru görünmektedir. Ancak, 0,1 birkaç bin kere eklerseniz, hata birikir ve yuvarlama ile bunu telafi etmek mümkün olmayacaktır.
    Örnekteki yanlış cevabın nedeni 0,1 sayısının double türünde kesin bir temsilinin olmaması ve yuvarlatılmasıdır. float türünü double ile yer değiştirelim:

    float sum = 0.0f;

    for (int i = 1; i <= 10; i++)

    {

    sum += 0.1f;



    }

    Console.WriteLine("{0:r}", sum);




    Yukarıda kod çalıştırıldığında, tamamen farklı bir sonuç toplamı döndürülür:

    1.00000012


    Yine hata yuvarlamadan kaynaklanmaktadır.
    Programın bu sonuçları neden verdiğini araştırmak için, float türündeki 0,1 sayısının gösterimine aşağıdaki şekildeki gibi bakmalıyız:

    Tüm bunlar, mantis dışında, doğru görünüyor, mantis 1,6’dan biraz daha büyük bir değere sahiptir, tam kesinlikte 1,6’ya değil; çünkü bu sayı 2’nin negatif kuvvetlerinin bir toplamı olarak sunulamaz. Çok kesinlikte olmak zorundaysak, mantis değeri 1 + 1 / 2 + 1 / 16 + 1 / 32 + 1 / 256 + 1 / 512 + 1 / 4096 + 1 / 8192 + 1 / 65536 + 1 / 131072 + 1 / 1048576 + 1 / 2097152 + 1 / 8388608 ≈ 1,60000002384185791015625 ≈ 1,6. Yani 0,1 sayısı için IEE 754 tarafından getirilen öneri 1,6 × 2-4 sayısından biraz daha fazladır ve 0,1 float türü olarak kaydedildiğinde hata toplama sırasında değil ancak toplamadan önce oluşur.
    Double ve Float türlerinin, Epsilon adında bir alanı vardır. Sıfırdan büyük olan en küçük değeri içeren bir sabittir, System.Single veya System.Double örneği ile temsil edilebilir. Epsilon’dan daha küçük her değerin 0 'a eşit olduğu kabul edilir. Örneğin, birbirinden farklı olan iki sayıyı karşılaştırırsak, ancak farkları Epsilon’dan küçükse, bunlar eşit kabul edilecektir.

    8.3.10 Decimal Tür
    .NET Framework’ün System.Decimal türü büyük sayılar ve hassas finansal hesaplamalar için çok uygundur ve 128-bit kesinliğinde ondalık kayan nokta aritmetiğini kullanır. decimal türün bazı karakteristik özellikleri aşağıda verilmiştir:

    Tür

    Boyut

    Aralık

    Anlamlı basamak sayısı

    .NET Framework Türü

    decimal

    128 bit

    ±1.0 × 10−28 ÷ ±7.9 × 1028

    28-29

    System.Decimal


    Kayan noktalı sayıların aksine, decimal türü için geçerli aralıktaki tüm ondalık sayıların duyarlığı korunur. Ondalık sayılarla çalışırken elde edilen bu mükemmel duyarlık, mantisin iç gösteriminin ikili sistemde değil, ondalık sistemde olmasından dolayıdır. Üs ayrıca 10’un kuvveti değil, 2’nin kuvvetidir. Böylece sayılar ikili sayı sisteme dönüştürülmeksizin tam kesinlikte temsil edilir.
    float ve double türleri ve üzerlerinde gerçekleştirilen işlemler tüm modern bilgisayar mikroişlemcilerinin parçası olan aritmetik işlemci tarafından gerçekleştirildiği için, ve decimal türü .NET CLR yazılımı tarafından uygulandığı için double ile karşılaştırıldığında decimal onlarca kat daha yavaş çalışır, ancak finansal hesaplamaların yürütülmesi için yeri doldurulamaz.
    Hedefiniz decimal türünde değişkene belirli bir değişmezi atamak ise, sonek olarak m veya M kullanmanız gerekir. Örneğin:

    decimal calc = 20.4m;

    decimal result = 5.0M;




    Önceki örnekte float / double yerine decimal kullanalım:

    decimal sum = 0.0m;

    for (int i = 1; i <= 10000000; i++)

    {

    sum += 0.0000001m;



    }

    Console.WriteLine(sum);




    Bu kez sonuç tam olarak beklediğimiz gibidir:

    1.0000000


    decimal türü kayan nokta türlerine göre daha yüksek bir duyarlığa sahip olsa da, daha küçük bir değer aralığına sahiptir ve, örneğin, 1e-50 değerini göstermek için kullanılamaz. Sonuç olarak, kayan noktalı sayılar decimal ’a dönüştürülürken bir taşma oluşabilir.

    8.3.11 Karakter Verileri (Dizeler)
    Hesaplamada karakter (metin) verisi bir bayt dizisi kullanılarak kodlanan metindir. Metin verilerini kodlamak için kullanılan farklı kodlama şemaları vardır. Çoğu bir bayt veya birkaç bayt sırası içinde tek karakteri kodlar. Böyle kodlanan şemalar arasında ASCII, Windows 1251, UTF-8 ve UTF-16 bulunmaktadır.
    8.3.11.1 Kodlama Şemaları (Kodlamalar)
    ASCII kodlama şeması Latin alfabesinin benzersiz harflerini diğer sembolleri ve özel karakterler ile karşılaştırır ve tek bir bayt halinde yazar. ASCII standardı 127 toplam karakteri içerir, bunların her biri bir bayt halinde yazılmıştır. ASCII standardına göre bir bayt dizisi olarak yazılmış bir metin, Arap, Korece ve Çince olanlar gibi diğer alfabeleri veya Kiril karakterlerini içeremez.
    ASCII standardında olduğu gibi, Windows 1251 kodlama şeması da Latin alfabesindeki harfleri, Kril ve diğer sembolleri ve özel karakterleri karşılaştırır ve bir byte halinde yazar.

    Windows 1251 kodlaması 256 adet karakter tanımlar – bir bayt içine yazılabilecek en fazla sayıda değer. Windows 1251 standardına göre yazılmış bir metin, sadece Kiril ve Latin harflerini içerebilir, Arapça, Hintçe yada Çince desteklenmez.
    UTF-8 kodlaması tamamen farklıdır. Unicode standartındaki tüm karakterler dünyadaki tüm yaygın dillerde kullanılan harfler ve semboller (Kiril, Latin, Arap, Çin, Japon, Kore ve diğer birçok dil ve yazı sistemleri) bu standart içinde kodlanabilir. UTF-8 kodlama yarım milyondan fazla sembol içermektedir. UTF-8 kodlamasında daha sık kullanılan semboller (örneğin Latin harfleri ve basamaklar) 1 bayt ile kodlanmıştır, ikinci en sık kullanılan semboller 2 bayt ile kodlanmıştır (örneğin Kiril harfleri), ve daha nadiren kullanılanlar 3 veya 4 bayt ile kodlanmıştır (Çin, Japon ve Kore alfabesinde olduğu gibi).
    UTF-16 kodlaması, UTF-8’de yaygın olarak kullanılan tüm diller ve yazı sistemlerindeki metinleri Unicode standartında tasvir edebilir. UTF-16 ’da her sembol 16-bit ile yazılır (2 bayt) ve daha nadiren kullanılan semboller iki 16-bit değer dizisi olarak sunulmaktadır.

    8.3.11.2 Bir Dizi Karakterin Sunulması
    Karakter dizileri çeşitli şekillerde temsil edilebilir. Bellekte metin yazmak için en yaygın yöntem 2 yada 4 bayt içinde önce dizenin uzunluğunu, bunun ardından metnin kendisinin bir çeşit kodlama ile kodlanmış bayt dizisini yazdırmaktır (Örneğin Windows-1251 veya UTF-8 için).
    Bellekte metin yazdırmak için C dili için tipik ve daha az başvurulan bir başka yaygın yöntem de, metinleri genellikle 1 byte içinde karakter dizisi olarak kodlar, özel bir bitiş karakteri tarafından, çoğunlukla bu 0 ’dır, takip edilir. Bu yöntemi kullanırken, bellek içinde belirli bir konumda bulunan kaydedilmiş metin uzunluğu önceden belirli değildir. Bu, birçok durumda bir dezavantaj olarak kabul edilmektedir.

    8.3.11.3 Char Türü
    C# dilinde char türü tek bir Unicode karakterin tamamının veya bir kısmının kodlandığı 16-bitlik değere sahiptir. Tüm Avrupa dilleri tarafından kullanılan çoğu alfabede bir harf, tek bir 16-bitlik değer ile yazılır ve bu nedenle char türünde bir değişkenin tek bir karakteri temsil ettiği kabul edilir. Bir örnek aşağıda verilmiştir:

    char ch = 'A';

    Console.WriteLine(ch);





    8.3.11.4 String Türü
    C# dilinde string türü UTF-16 kodlu metinleri saklamada kullanılır. Tek bir C# dizesi 4 baytlık uzunluk, ve char türünün 16-bit değerleri olarak yazılan bir char dizisini belirtir. string türü ile tüm yaygın alfabelerde ve insanların yazdığı her türlü yazı sistemi ile yazılmış metinleri saklayabilirsiniz - Latin, Kiril, Çince, Japonca, Arap ve birçok diğerleri. string kullanımına bir örnek aşağıda verilmiştir:

    string str = "Example";

    Console.WriteLine(str);





    8.4 Alıştırmalar


    1. 151, 35, 43, 251, 1023 ve 1024 sayılarını ikili sayı sistemine dönüştürün.

    1. 1111010110011110(2) sayısını onaltılık ve ondalık sayı sistemlerine dönüştürün.

    2. Onaltılık sistemdeki FA, 2A3E, FFFF, 5A0E9 sayılarını ikili ve ondalık sayı stemlerine dönüştürün.

    3. Ondalık sayı sistemindeki bir sayıyı ikili sayıya dönüştüren bir program yazın.

    4. İkili sayı sistemindeki bir sayıyı ondalık sayıya dönüştüren bir program yazın.

    5. Ondalık sayı sistemindeki bir sayıyı onaltılık sayıya dönüştüren bir program yazın.

    6. Onaltılık sayı sistemindeki bir sayıyı ondalık sayıya dönüştüren bir program yazın.

    7. Onaltılık sayı sistemindeki bir sayıyı ikili sayıya dönüştüren bir program yazın.

    8. İkili sayı sistemindeki bir sayıyı onaltılık sayıya dönüştüren bir program yazın.

    9. İkili sayı sistemindeki bir sayıyı onaltılık sayıya Horner şemasını kullanarak dönüştüren bir program yazın.

    10. Romen basamaklarına karşılık gelen Arap basamaklarını yazdıran bir program yazın.

    11. Arap basamaklarına karşılık gelen Romen basamaklarını yazdıran bir program yazın.

    12. Verilen bir N, S, D için (2 S, D 16) N sayısını S tabanlı sayı sisteminden D tabanlı sayı sistemine dönüştüren bir program yazın.

    13. 50.000.000 kere 0,000001 sayısını ard arda toplamayı deneyin. Bir döngü içinde toplama kullanın (doğrudan çarpma kullanmayın). float ve double türleri için ve bundan sonra decimal ile deneyin. Hesaplama hızı ve sonuçlardaki farkı açıklayınız.

    14. * float türündeki sayılar (IEEE 754 standardına göre kayan noktalı 32-bitlik sayılar) için mantis değeri, mantis işareti ve üssünü yazdıran bir program yazın. Örnek: -27,25 sayısı için işaret biti = 1, üs = 10000011, mantis = 10110100000000000000000 olarak yazılmalıdır.

    Bölüm 9.Metotlar


    9.1 Bölümün İçindekileri
    Bu bölümde metotlar ve neden kullanılması gerektikleri üzerinde duracağız. Metotların nasıl bildirileceği, parametreler ve metot imzasının ne anlama geldiği, bir metotun nasıl çağrılacağı, metota argümanların nasıl geçirileceği, ve metotların değer döndürmeleri okuyucuya gösterilecektir. Bu bölümün sonunda kendi metotlarımızı nasıl oluşturacağımızı ve gerektiğinde bunları nasıl kullanacağımızı (çağıracağımızı) öğrenmiş olacağız. Sonunda, metotlarla çalışırken önerilen bazı iyi uygulamaları göreceğiz. Bu bölümün içeriğine okuyucunun öğrenilen materyalin uygulanmasına yardımcı olacak detaylı örnekler ve alıştırmalar eşlik edecektir.

    9.2 Programlamada Altyordamlar
    Özellikle karmaşık belirli bir görevi çözmek için, eski Romalılar’ın önerdiği metotu uyguluyoruz: "böl ve yönet". Bu ilkeye göre, çözmek istediğimiz sorun küçük alt problemlere ayrılmalıdır. Ayrı ayrı ele alındığında alt problemlerin iyi tanımlanması ve özgün probleme göre çözülmesi daha kolay olması gerekmektedir. Tüm küçük sorunlara çözüm bulunması sonucunda karmaşık problem de çözülmüş olacaktır.
    Aynı analojiyi kullandığımızda, belirli bir görevi çözmek amacıyla yazılım programı yazmak isteriz. Bunu verimli ve "kolay" bir şekilde yapmak için, yukarıda belirtilen aynı "böl ve yönet" metotunu kullanırız. Verilen görevi ayrı ayrı küçük görevler içinde düşünerek bunlara yönelik çözüm geliştiririz ve tek bir program halinde onları bir araya koyarız. Bu küçük görevlere altyordamlar diyoruz.
    Bazı diğer programlama dillerinde altyordamlar işlevler veya prosedürler olarak adlandırılabilir. C# dilinde metotlar denir.

    9.3 “Metot” Nedir?
    Metot, programın bir ana parçasıdır. Belirli bir sorunu çözebilir, sonunda parametreler alır ve bir sonuç döndürür.
    Bir metot, programın belirli bir görevi çözmek için yaptığı tüm veri dönüşümünü temsil eder. Metotlar programın mantığından oluşur. Üstelik "gerçek iş"in yapıldığı yerdir. Bu nedenle, metotlar tüm program için ana ünite olarak ele alınabilir. Öte yandan bu, daha karmaşık ve sofistike sorunları çözen büyük programlar oluşturmak için, basit blokları kullanma fırsatını bize veriyor. Aşağıda dikdörtgenin alanını hesaplayan basit bir metot örneği verilmiştir:

    static double GetRectangleArea(double width, double height)

    {

    double area = width * height;



    return area;

    }




    9.4 Neden Metot Kullanmalıyız?
    Metotları kullanmanızı gerektiren birçok neden vardır. Bunlardan bazıları aşağıda listelenmiştir, ve deneyim kazanarak, metotların ciddi bir görevi gerçekleştirmek için kaçınılması zor bir şey olduğuna kendinizi de inandırabilirsiniz.

    9.4.1 Daha Yapılandırılmış Program ve Daha Fazla Okunabilir Kod



    Bir program oluşturulacağı zaman, iyi yapılandırılmış ve okunması kolay ve dolayısıyla diğer insanlar tarafından değiştirilebilir kod yazabilmek için her zaman metotların kullanılması iyi bir uygulamadır.
    Bunun için iyi bir neden, harcanan çabanın sadece %20’sini, oluşturma ve test etme için, kalan zamanı bakım, değiştirme ve ilk sürüme yeni özellikler eklemek için saklı tutmamızdır. Birçok durumda, kod yayına sürüldükten sonra, yalnızca ilk oluşturan kişi değil, birçok diğer geliştiriciler de bakım ve değiştirme sağlar. Kodun mümkün olduğunca iyi yapılandırılmış ve okunabilirliğinin önemli olmasının nedeni budur.

    9.4.2 Yinelenen Koddan Kaçının



    Metotları kullanmak için bir başka çok önemli neden de yinelenen kodun önlemesinde fayda sağlamasıdır. Kodun yeniden kullanımı fikri ile güçlü ilişkisi vardır.

    9.4.3 Kodun Yeniden Kullanımı



    Bir kod parçasını, programda bir kereden fazla kullanıyorsanız, onu bir kereden çok çağırabileceğiniz metotlar haline ayırmak daha iyidir. Böylece aynı kodu yeniden yazmadan tekrar tekrar kullanılabilirsiniz. Bu şekilde kodun yinelenmesi önlenir, ancak tek yararı bu değildir. Programın kendisi daha okunabilir ve iyi yapılandırılmış olur.
    Kod tekrarı çok zararlı ve tehlikelidir, çünkü programın bakımı için engelleyicidir ve hatalara yol açar. Genellikle, her değişiklik için geliştirici tekrarlanan kodun sadece bazı bloklarını değiştirirken, diğerlerini unutabilir, ancak sorunlar değiştirilmeyen diğer bloklar için hala devam etmektedir. Yani, örneğin bir kusur, program üzerinde 10 farklı yere kopyalanan 50 satır kod parçası içinde bulunursa, tekrarlanan 10 farklı yer için kusurun düzeltilmesi gerekir. Ancak tecrübe edinilen odur ki, genellikle dikkat eksikliği veya başka nedenlerle, geliştirici düzeltmeleri bütün bloklar için değil sadece bazı kod parçaları üzerinde gerçekleştirir. Örnek bir durumda, geliştiricinin kodu 10 üzerinden 8 blokta düzelttiğini varsayalım. Sonuç itibariyle bu, sadece nadir durumlar için beklenmedik program davranışına sebebiyet verecektir, ve dahası, programın nerelerde yanlışa düştüğünü öğrenmek de çok zor bir iş haline gelecektir.


    1   ...   12   13   14   15   16   17   18   19   ...   31






        Ana sayfa


    C# İle biLGİsayar programlama temelleri (C# Programlama Kitabı) Svetlin Nakov & Co

    Indir 3.36 Mb.