PDA

Tam Sürümünü Görmek İçin : Tür dönüştürme işleci hakkında ACİL yardıma ihtiyacım var


kcetinkaya
06/02/2008, 19:57
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double usalma(int a,int b)
{
int k;
double us=1;
if (b<0) {
a=1/a;
b=-1*b;
}
for (k=1;k<=b;k++)
us*=a;
return us;
}

int main()
{
printf("exp(5*log(2)) : %f \n",exp(5*log(2)));
printf("usalma(2,5) : %f \n",usalma(2,5));
printf("(int)exp(5*log(2)) : %d \n",(int)exp(5*log(2)));
printf("(int)usalma(2,5) : %d \n",(int)usalma(2,5));
return 0;
}

Arkadaşlar yukardıki kodun çıktısı niye aşağıdaki şekilde ?

exp(5*log(2)) : 32.000000
usalma(2,5) : 32.000000
(int)exp(5*log(2)) : 31
(int)usalma(2,5) : 32

Demek istediğim us almak icin iki farkli yol kullandim. Tekinde math.h kütüphanesindeki exp() ve log fonksiyonlarını kullanarak hesapladım diğerinde usalma() diye kendim ayrı bir fonksiyon yazdım. Gördüğünüz gibi math.h kütüphanesindeki exp() fonksiyonunu da benim kendi yazdığım usalma() fonksiyonu da double bir değere dönüyor. Bu değerleri ilk iki printf te olduğu gibi %f ile double olarak ekrana yazdırdığımda doğru sonuçlar görüyorum. Ancak (int)... ifadesi ile bu değerleri tür dönüştürme işlemine soktuğumda ekrana verdikleri çıktılar 31 ve 32 :S Normalde benim bildiğim double dan int e dönüştürme işleminde noktadan sonra olan kısım kesilip atılır kalan tamsayı kısım integer türü için değer olur. kendi yazdığım usalma() fonksiyonunda ve bugune kadar yazdığım tüm programlarda bu kurala uyarken neden exp() kullandığımda bu kurala uyulmuyor ? İşlemin çıktısı 31.99999999999999.... gibi bir değer olsa anlayacağım direk 31 olur dönüşüm işlemi sonu. Ancak oyle olduğu zamanda double olarak yazdırdığımda 32 yazmaması gerekir diye düşünüyorum. kafayı yemek üzereyim neden böyle neden böyle diye :S Bugune kadar yanlış mı biliyordum yoksa bir hata mı var ? Derleyiciden kaynaklanıyordur diye iki farklı derleyicide denedim TurboC ve Code::Blocks hiç farketmedi. Lütfen şunun nedenini söyleyin de içim rahatlasın yav :)

Şunu da belirteyim virgülden sonraki kısmı yazdırmamak için int e dönüştürmene gerek yok %.0f ile aynı işlemi yapabilirsin gibisinden öneriler sunmayın, benim amacım bunları ekrana yazdırmak tabii ki değil sadece size sorunu daha iyi anlatabilmek için yukarıdaki basit örneği yazdım.

Şİmdiden teşekkürler...


myavuzselim
06/02/2008, 22:02
İşlemin çıktısı 31.99999999999999.... gibi bir değer olsa anlayacağım direk 31 olur dönüşüm işlemi sonu.

Buyuk bir ihtimalle oyle ve printf yazdirmadan once yuvarliyor. Su anda deneyemiyorum, ama printf("exp(5*log(2)) : %.20f \n",exp(5*log(2))); gibi birsey yaparak test edebilirsin.

kcetinkaya
06/02/2008, 22:14
Buyuk bir ihtimalle oyle ve printf yazdirmadan once yuvarliyor. Su anda deneyemiyorum, ama printf("exp(5*log(2)) : %.20f \n",exp(5*log(2))); gibi birsey yaparak test edebilirsin.

Hayır değilmiş :S Calculus kitabımı açtım ve baktım logaritma ya da exponential fonksiyonun özelliklerine ifadenin tam olarak 2^5 yani 32 vermesi gerekiyor. e sayısı hernekadar irrasyonel olsada log ve exp işlevleri e sayısını götürecek ve sona 2^5 kalacak kesin ifadeyle. Yine de denedim dediğin gibi fraction kısmını daha da büyülttüm ancak yine değişmedi. İlgin için tşkrler.

myavuzselim
06/02/2008, 22:28
Ne yazik ki bilgisayarlarin isleyisi calculus kitaplarindaki formuller kadar saf degil. log(2) cok buyuk bir ihtimalle "floating point" olarak tam gosterilemiyor. Onun ustune bir de 5 ile carpip exp fonksiyonuna sokuyorsun. Kucuk de olsa hata olmasi normal.

http://en.wikipedia.org/wiki/Floating_point

Hemen linux'a reboot edip bir deneyim :)

kcetinkaya
06/02/2008, 22:49
Haklısın sonuçta insan değil ki bir makine :P logaritma ile e sayısını direk götürmek aklına gelmez ki önce log(2) nin değerini hesaplayacak ve bu değer dediğin gibi biryerde takılacak sonra bu değeri exp() fonksiyonuna gönderecek ordan da yeni bir değer hesaplayacak bu da takılacak bu floating point denen şeye ;)

Ama şimdide şu aklıma takıldı. Atıyorum log2 yi hesapladı kendi yazmacı içerisinde ieee754 standartlarına göre binary olarak yazdı dediğin gibi burda floating point e takıldı. Daha sonra bu değeri aldı k tam sayısı ile çarptı ve elde ettiği son sayıyı tuttu exp() fonksiyonuna parametre olarak gönderdi. Bütün bu işlemlerin sonucunda elde ettiği sayıyı işlemcimiz önce kendi yazmaçları içerisinden birine yada ram in bir bölgesine vs. geçici olarak depolaması daha sonra tür dönüştürme işlecine ya da printf() fonksiyonuna parametre olarak göndermesi gerekmezmi ? Yani demek istediğim sonuçta hernasıl bir hataya takılıyorsa da iki işleme de aynı değerin gitmesi gerektiği. printf içerisinde de &f operatörünü bu şekilde sade halde kullandığımda herhangibir yuvarlama yapmadan yazabildiği yere kadar (floating point :) tamamını yazması gerekiyor diye biliyorum herhangibir yuvarlama yapmadan. Yuvarlamanın yapıldığı tek yer kanımca floating point dediğimiz noktada olacaktır.

Kafam karıştı :S

myavuzselim
06/02/2008, 23:21
Benim derleyicimle (gcc 4.1.3, linux) exp(5*log(2)) nasil oluyorsa tam sonuc veriyor. Hangi derleyiciyi kullaniyorsun? Su programin ciktisini soyler misin?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

void printDoubleBits(double d) {
int i;
unsigned long long decimal;

assert(sizeof(unsigned long long) == sizeof(double));
assert(sizeof(unsigned long long) == 8);

decimal = *(unsigned long long*)(&d);

for(i=8*8-1; i>=0; i--) {
printf("%d", (int) ((decimal>>i) & 1));
if (i==63 || i==52)
printf(" ");
}
printf("\n");
}

int main()
{
printDoubleBits(32.0);
printDoubleBits(exp(5*log(2)));
printf("\n");
printDoubleBits(27.0);
printDoubleBits(exp(3*log(3)));
return 0;
}

kcetinkaya
06/02/2008, 23:32
TurboC ve gcc üzerine kurulu mingw32 derleyicisini kullanan Code::Blocks ve DevC++ IDE leri. Üçünde de windows altında denedim ve hatalı sonuç verdi :S Aynı programı şimdi pardus altına geçip gcc ile derleyeceğim bakalım ne sorun verecek.

myavuzselim
06/02/2008, 23:57
Benim platformumda exp(5*log(2)) tam sonuc donduruyor, fakat tam sonuc dondurmeyen baska bir ornek verilebilir:


int main()
{
printDoubleBits(49.0);
printDoubleBits(exp(2*log(7)));
return 0;
}

Cikti:
0 10000000100 10001000000000000000000000000000000000000000000000 00
0 10000000100 10000111111111111111111111111111111111111111111111 11

Ikinci sonuctaki 1'ler sonsuza kadar gidebilseydi birinci sonuca esit olacakti.

kcetinkaya
07/02/2008, 00:09
Lİnux a yabancı olduğumdan ve gcc yi kullanmayı bilmediğimden derleyemedim :S
log ve exp fonksiyonları için undefined reference hatası veriyor. Oysaki math.h yazdım başa. gcc versiyonu 3.4.6, paket dağıtım pardus 2007.3 lynx. math.h başlık dosyasını bizzat elimle kontrol edeyim dedim /usr/include/math.h olacak şekilde standat klasörde mevcut.

gcc hata.c -o hata

gcc hata.c -o hata -lmath

ikisini de denedim konsolda ancak yine de derleyemedim math.h ı görmüyor log ile exp için undefined diyor :S

Küçücük bir ayrıntı neler çıkardı başımıza :S

myavuzselim
07/02/2008, 00:10
gcc hata.c -o hata -lm

kcetinkaya
07/02/2008, 00:15
Tamamdır çok saolasın derlemeyi başardım. Sonuç ise tüm değerleri 32 olarak yazdı. Sanırım ortamların farklılığından kaynaklanıor