Ana Sayfa

Bilgisayar Eğitim CD

Bilgisayar Kitapları

 
 
Adım Adım Web Eğitim Seti Adobe Flash Eğitim Seti


C# Kayar Nokta Veri Türleri

Kayar Nokta Veri Türleri

Bilimsel ve mühendislik uygulamalarda, genellikle çok küçük ve çok büyük sayılarla çalışmak ve daha fazla esnek olmak istersiniz. C#taki decimal veri türü sadece ondalık kısmın sağında ve solunda 28 basamağa kadar izin verir. Bu sınırlamalardan dolayı esnek değildir. Mesela güneşin ağırlığı yaklaşık 2*1030 kilogramdır. Elektronun ağırlığı ise yaklaşık 9*10-31 kilogramdır.

Uzun yıllar, bilim adamları 3 ya da 4 hassasiyetli sayılarla işlemlerini kaydırma kuralları ile yaptılar. Günümüzde, kayar nokta veri türlerini kullanarak bilimsel gösterime yakın bir biçimde sayıları gösterip bilimsel hesaplamalarını yapıyorlar. C#ta 2 tane kayar nokta türü vardır, float ve double.

1985 yılında IEEE kayar nokta türleri ile ilgili standartları belirledi. İki tane tür belirlendi. 4 byte gerektirene tek hassasiyet 8 byte gerektirene de çift hassasiyet denildi.

.net Framework içerisinde, bu iki kavramı karşılayan System.Single ve System.Double adında iki tane yapı vardır. Fakat C# double ve float isimlerini C dinliden miras aldı. Aşağıdaki tablo double ve float hakkında bilinmesi gerekenleri özetlemektedir.

C# Türü
.NET Türü
Anlamlı Kısım
Üssel Kısım

float
System.Single
23 bits (7 basamak)
8 bits (-45 to 38)

double
System.Double
52 bits (15–16 basamak)
11 bits (-324 to 308)


Sağ taraftaki iki sütun float türünün 32 bitinin ve double türünün 64 bitinin, anlamlı kısımla üssel kısım arasında nasıl paylaşıldığını göstermektedir. Ek bir bit ise anlamlı kısmın işaretini tutar. Aşağıdaki sayıyı inceleyelim.

8.364 10-24

Anlamlı kısmı 8.364 olan kısmıdır. Float veri türünde 23 bit anlamlı kısım için ayrıldığına göre bu kısım yaklaşık 7 basamağa kadar olabilir. Üssel kısım için ise 8 bit ayrılmıştır.

float ve double veri türlerini gösterirken Macar gösterimi kullanalım. float için f önekini, double için de d önekini kullanalım.

float f;

Tabi ki virgülden sonraki kısmı olmayan bir sayıyı yani bir tamsayıyı da float bir değişkende tutmak mümkündür.

f = 123456789;

Tamsayının kayar nokta türüne dönüşümü sırasında tamsayı hassasiyet kaybına uğrar. Eğer bu sayıyı ekranda görmek istersek aşağıdaki kodu yazıp çıktısını görelim.

float f;

f = 123456789;

Console.WriteLine(f);

Console.ReadLine();
C# Console
Aslında aynı sayıdır. Sayının genliği değişmez ama 7 basamaktan yukarısını float ile gösteremediğimiz için hassasiyet kaybı olur.

float bir değişkene ondalık kısmı olan bir sayı ataması yapılabilir.

f = 45.384f;
Bilimsel gösterimde bir sayıyı da float bir değişkene atayabiliriz.

f = -34.78e-14f;
Yukarıdaki örneklerde de görüldüğü gibi eğer tamsayı değil de ondalık kısmı olan ya da bilimsel gösterimdeki bir sayıyı float bir değişkende tutmak istersek sayının sonuna küçük harfle ya da büyük harfle F yazmak gerekiyor. Ayrıca bilimsel gösterimdeki e harfini de büyük ya da küçük yazmak fark etmez.

Şimdi de bir double değişken tanımlayalım.

double d = 456.374584;

Double bir sayı tanımlarken herhangi bir sonek koymaya gerek yok ama gene de küçük ya da büyük harfle d harfi koyulabilir. Diğer bir ifadeyle ondalık kısmı olan ya da bilimsel gösterime sahip olan sayılar varsayılan olarak double kabul edilir.

Bir çok programcı sadece double kullanır ve float ile ilgilenmez. Çünkü kayar nokta işlemleri işlemcinin matematik işlemler bölümünde özel bir kısımda ele alınır, bu yüzden double yerine float kullanmanın performans üzerinde bir etkisi yoktur. Günümüz uygulamalarında çoğu zaman belleğin verimli kullanımı ihmal edilebilir.

Gerekli durumlarda C# tamsayı türünden bir sayıyı kapalı olarak float ya da double türüne dönüştürebilir. Biraz hassasiyet kaybı olur ama genliğinde bir kayıp söz konusu olmaz. Hatta C# float türünü de aynı şekilde double türüne kapalı olarak dönüştürebilir.

C# kapalı olarak herhangi bir tamsayı türünü float ya da double türüne dönüştürmez. Eğer dönüştürme yapacaksak casting yapmak gerekiyor. Hangi türün hangi türe kapalı olarak dönüştürülebileceği aşağıdaki şekilde görülmektedir.
C# Console 2
IEEE kayar nokta türleri (float, double) için standart tanımlarken diğer sayısal veri türlerine göre çok farklı tanımlamıştır. Mesela kayar nokta hesapları yapılırken asla istisna oluşmaz. Aşağıda tam sayılar için sıfıra bölme istisnası oluşturabilecek bir örnek var.

double dPay = 124;

double dPayda = 0;

double dBolum = dPay / dPayda;

Console.WriteLine(dBolum);

Console.ReadLine();

İşlemin sonucunda dBolum adlı değişkene çok özel bir değer dönüyor. Bu özel değerler IEEE tarafından belirlenmiştir. Infinity (sonsuz) değeri de bunlardan biridir.

Eğer dPay değişkenini -124 diye değiştirirsek o zaman da –Infinity (- Sonsuz) sonucunu göreceksiniz.
C# Console 3
Eğer dPay değerini de 0 olarak değiştirirseniz NaN göreceksiniz. NaN (Not a Number – Sayı Değil) anlamına gelmektedir. Eğer kayar nokta hesabında aşağı taşma ya da yukarı taşma durumu meydana gelirse o zaman da NaN değeri görüntülenecektir.

float ve double yapıları PositiveInfinity, NegativeInfinity, ve NaN olan üç adet alana sahiptir. Bu alanlar açık olarak değer ataması yapabilmek içindir. Mesela, eğer double tanımlanmış 1 sayısını Positive Infinity değerine bölerseniz 0 sonucunu alırsınız ama PositiveInfinity değerini PositiveInfinity değerine bölerseniz 1 yerine NaN sonucunu alırsınız.

Başka bir yazıda bu özel değerlerle nasıl çalışılacağını anlatacağız. Şimdilik kayar nokta veri türleri ile çalışırken bu tür sonuçların görülebileceğini bilsek yeter.

Kayar nokta türlerini, çok büyük ya da çok küçük sayıların bölme ve çarpma gibi işlemlerini yaparken doğal olarak tercih etmeniz gerekiyor. Çünkü bu tür bir işlemde hiçbir zaman taşma meydana gelmeyecektir.

Eğer C# kullanarak bilimsel ya da mühendislik hesaplamalar yapmak isterseniz üssel, logaritmik ve trigonometrik fonksiyonlarla hesaplamalar yapmak isteyeceksiniz. Bütün bunlar System isim uzayındaki Math sınıfının içerisinde statik yöntemler olarak mevcuttur.

Meselâ, üs alma işlemini Pow yöntemini kullanarak yapabilirsiniz.

dSonuc = Math.Pow(dTaban, dUs);

Bu yönteme virgülle ayrılmış 2 tane argüman geçeriz. double olmayan argümanlar kapalı olarak double türüne çevrilir.

double dSonuc = Math.Pow(3, 4);

Console.WriteLine(dSonuc);

Console.ReadLine();
C# Console 4
Ama decimal veri türü hiçbir türe kapalı olarak çevrilemeyeceğinden ötürü decimal sayıları bu yönteme geçmek için açık dönüşüm yapmak gerekiyor.

Karekök almak için Pow yöntemini ilgili sayının 0.5 kuvvetini almak suretiyle kullanabilirsiniz.

dSonuc = Math.Pow(dSayi, 0.5);

Ya da karekök almak için olan Sqrt yöntemini kullanabilirsiniz.

dSonuc = Math.Sqrt(dSayi);

Şimdi bir dik üçgenin hipotenüsünü hesaplayabileceğimiz küçük bir örnek yazalım. Pisagor teoremine göre dik üçgenin hipotenüs uzunluğu dik kenarlar uzunluklarının kareleri toplamının kareköküne eşittir. Math.Sqrt yöntemine argüman olarak iki tane Math.Pow işleminin sonuçlarının toplamlarını geçeceğiz.

using System;

class Program

{

static void Main()

{

Console.Write("İlk Kenar: ");

double dKenar1 = Double.Parse(Console.ReadLine());



Console.Write("İkinci Kenar: ");

double dKenar2 = Double.Parse(Console.ReadLine());



double dSonuc = Math.Sqrt(Math.Pow(dKenar1, 2) + Math.Pow(dKenar2, 2));

Console.WriteLine("Hipotenüs hesaplandı: {0}", dSonuc);

Console.ReadLine();

}

}

C# Console 5
Math sınıfının ayrıca iki tane sabit alanı vardır, matematik hesaplarda sık kullanılan iki tane sabit değerli sayı.

pi sayısını Math.PI, e sayısını da Math.E alanları bize verir.

Bazı uygulamalarda kayar nokta vazgeçilmezdir ama her yerde değil. Gereksiz kullanımlarda bir takım sıkıntılar da meydana getirir. Klasik BASIC programlama dili bütün sayısal verileri kayar nokta şekilde tutar. Daha sonraki programla dilleri her sayı türü için ayrı değişken türü tanımlamaya olanak tanısa da programcılar çoğunlukla kayar nokta türleri tercih ederler. Çünkü alt taşma yok, üst taşma yok, daha kolay gelir.

Kayar nokta türlerle uzun süre haşır neşir olmuş programcılar sıkıntılarını da iyi bilirler. Mesela 23.5 gibi bir sayı 23.50001 ya da 23.49999 olarak saklanmış olabiliyor. İkincisi büyük bir problemdir. Çünkü en yakın tamsayıya yuvarlamak istersek 23.49999 sayısı 23 sayısına 24 sayısından daha yakındır.

Yeni programlama dillerinde kayar nokta türler çok fazla problem olmuyor. Sürekli birileri daha sağlıklı hesaplamalar yapmaya izin verecek çalışmalar yapıyor. Ama hala sıkıntılar var. Aşağıdaki örneği inceleyelim.

Console.WriteLine(9.666e-7f);
C# Console 6
Gördüğünüz gibi WriteLine bize aynı sayıyı göstermedi.

Şimdi de aşağıdaki örneğe bakalım.

using System;

class Program

{

static void Main()

{

float f1 = 1234567;

float f2 = 0.1234567f;

float f3 = f1 + f2;

Console.WriteLine(f3);

Console.ReadLine();

}

}
C# Console 6
float veri türü sadece 7 basamak gösterebiliyor, işlemin sonucunu da görüyorsunuz. f2 değişkeninin değeri kayıp. Eğer 7 basamaktan daha büyük sayılar gösterecekseniz double ver türünü kullanabilirsiniz. Ama double veri türünün de 16 basamaktan fazlasını tutamayacağını bilmeniz gerekiyor.

Çok az denk gelse de IEEE standardı bizim istediğimiz sayıyı tutmaya yetmiyor. Bu genellikle anlamlı kısmın hassasiyetinden kaynaklanıyor. 16,777.216 ile 16,777.217 float sayıları arasındaki fark ihmal ediliyor. Çok küçük ve çok büyük sayılarda yakınsama söz konusudur. Meselâ, 12.34 sayısı float olarak saklandığı zaman 12,939,428 tamsayısının 220 ile bölümü olarak saklanır. Bu sayı yaklaşık olarak 12.34 ediyor. Eğer double olarak saklanırsa 6,946,802,425,218,990 tamsayısının 249 ile bölümü olarak saklanır. Bu sayı 12.34 sayısına çok çok yakındır, ama aynısı değildir.

Aynı sayıyı decimal olarak saklarsak 1234 sayısının 102 ile bölümü olarak saklanır. Bu sayı tam olarak 12.34 eder. Bu durum decimal veri türünün ne kadar güçlü olduğunu gösteriyor. Bunun yanında şu gerçeği de göz önünde bulundurmak gerekiyor, kayar nokta türler bilimsel ve mühendislik hesaplarda kullanılsın diye var. Bilimsel ve mühendislik hesaplarda da her zaman yakınsama ve yuvarlama söz konusudur. Kesinlik gerektiren ama ondalık kısmı olan işlemler için zaten C# decimal diye bir tür içeriyor ve oldukça güçlü.