Tam Sürümünü Görmek İçin : if kullanmadan sayiyi yuvarlamak
öncelikle tesekkürler myavuzselim ve acehreli.hocalardan ögrendigimden daha fazlasini ögreniyorum burda.uzun süredir netim olmadigi icin bakamiyorum foruma. gecen semester ilk alisimdi programlama dersini ve malesef kaldim.
simdi bu dönem ders daha da agir ama en azindan unutmamak icin bir daha deneyecegim.
simdi de bir program yazmaliyim
bir sayiyi yuvarlayacak yani 0.5 ten büyükse bir üsst sayiya kücükse bir düsük sayiya. yalniz if yada benzer bir operator kullanmamak sarti var. konumuz veri tipleri, variable ler ve ifadeler.sanirim veri tipleri ile ilgili bir sey olacak ama ben if siz yapamiyorum.if siz yapilablinir mi bu??
myavuzselim
19/03/2007, 16:57
Bu bana birinci sinifta yaptigim bir alistirmayi hatirlatti. Alistirmada subat ayinin verilen yilda 29 gun cekip cekmeyecegini hesaplayan bir program isteniyordu. Ben de daha if veya donguleri ogrenmedigimiz icin inat ederek onlarsiz cozmeye calismistim. Program round/floor gibi islemler ve cast doluydu, ve o zaman test edebildigim kadariyla dogru sonucu veriyordu. Ne yazik ki o programi kaybettim.
Neyse, sizden istenilen acikcasi cok garip: if kullanmadan program yazmak. Eger dongu de kullanmamanin gerekiyorsa isin zor. Yok eger dongu kullanabiliyorsan, bu sefer elinde zaten if var demektir. Cunku:
if(a) {
X;
} else if(b) {
Y;
} else {
Z;
}
su sekilde tercume edilebilir:
if(a) {
X;
} else {
if(b) {
Y;
} else {
Z;
}
}
Ve:
if(a) {
X;
} else {
Y;
}
Su sekilde tercume edilebilir:
while(a) {
X;
break;
}
while(! a) {
Y;
break;
}
Sonucta cok cirkin olur, ama olur.
myavuzselim
19/03/2007, 17:10
Bak bakalim bu olmus mu :)
#include <stdio.h>
long isaret(double sayi) {
long i = (long) (sayi-1);
return 1 + 2 * (i >> (sizeof(long)-1));
}
long yuvarla(double d) {
return (long) (d + 0.5 * isaret(d));
}
void test(double d) {
printf("yuvarla(%f) = %d\n", d, yuvarla(d));
}
int main() {
double d;
for (d = 3; d > -3.1; d -= 0.25)
test(d);
return 0;
}
not 1: hocanin boyle bir kod bekmemesi muhtemel. O yuzden bunu kullanma, hocanin nasil birsey istedigini tam olarak anlayip ona gore kod yaz.
not 2: yuvarla'nin sonucu long olarak veriliyor. long double'in tuttugu her tamsayiyi tutamayabilir.
not 3: yuvarla(-1.5) -2 veriyor, sanirim normalde -1 vermesi lazim (baktim, c'nin kendi round'u da boyle calisiyormus).
denemedim ama şu işlev olabilir sanırım:
int yuvarla(float x) {
return (x-(int)x)<0.5 ? (int)x : (int)x+1 ;
}
acehreli
19/03/2007, 18:30
Bence burada tamsayilarin virgulden sonrasini saklayamiyor olma ozelliklerinden yararlanilmasi istenmis:
double d = 1.6;
int i = (int)d;
Iste simdi i, d'nin virgulden sonrasini kaybetti. mawera'nin dusunmesi gereken, bu kaybetme olayinda 1.6'yi bir sekilde 2 yapabilmek...
Ali
acehreli
19/03/2007, 18:32
myavuzselim de bunu soylemis zaten... :)
Ali
quasimodo
19/03/2007, 18:34
double sayilar ici %f mi daha dogru %lf mi?
acehreli
19/03/2007, 18:57
double icin %f ile %lf ayni... long double icin %Lf oluyor. (Tabii bunlar f icin oldugu gibi, g, G, e ve E icin de gecerli.)
Bu forumda hep "C (ve C++) icin dogal olan tur double'dir, float degildir" derim ya; dikkat ederseniz printf'te float turu icin bir belirtec yoktur. Bunun nedeni, float parametrelerin "..." parametre alan islevlere (ornegin printf) double olarak gonderilmeleridir. float degerler once double'a cevrilirler, ondan sonra gonderilirler. Gereksiz ek bir is... :)
Hatirlatmak icin, ayni sey tamsayilarda da vardir: "..." alan islevlere ornegin short gonderilmez, once int'e cevrilir, int gonderilir.
Ali
long yuvarla(double x) {
return (x-(int)x)<0.5 ? (int)x : (int)x+1 ;
}
double icin %f ile %lf ayni... long double icin %Lf oluyor. (Tabii bunlar f icin oldugu gibi, g, G, e ve E icin de gecerli.)
Bu forumda hep "C (ve C++) icin dogal olan tur double'dir, float degildir" derim ya; dikkat ederseniz printf'te float turu icin bir belirtec yoktur. Bunun nedeni, float parametrelerin "..." parametre alan islevlere (ornegin printf) double olarak gonderilmeleridir. float degerler once double'a cevrilirler, ondan sonra gonderilirler. Gereksiz ek bir is... :)
Hatirlatmak icin, ayni sey tamsayilarda da vardir: "..." alan islevlere ornegin short gonderilmez, once int'e cevrilir, int gonderilir.
Ali
o zaman short kullanmak da gereksiz mi acaba ? teşekkürler
acehreli
20/03/2007, 00:25
Evet, short kullanmak da gecerli bir neden olmadikca gereksiz. Cunku islemci zaten butun islemleri int turunde yaptigi icin, bu tUr de en hizli kullanilan tur oldugu icin int kullanmak gerek.
Ozel bir uygulamada, cok sayida short degerin saklandigi bir diziyi kucultmek icin kullanilabilir.
Ozel bir neden yoksa, tamsayi icin int; virgullu sayilar icin double...
Ali
myavuzselim kodunuz kafami karistirdi valla:)
#include <iostream>
int main()
{
double a=0;
double b=0;
int c=0;
std::cout<<"sayi: ";
std::cin>>a;
b = a - (int)a;
c = a + b;
std::cout<<c;
return 1;
}
long yuvarla(double x) {
return (x-(int)x)<0.5 ? (int)x : (int)x+1 ;
}
ternary operator kullaninca if kullanmis yerine gecmez mi?
ternary operator kullaninca if kullanmis yerine gecmez mi?
ben sadece if koşulunun kullanılmadığı bir çözüm istiyor sandım. başka türlü çözümler de vardır elbet.
myavuzselim
20/03/2007, 14:51
myavuzselim kodunuz kafami karistirdi valla:)
:)
Pozitif sayilar icin round(f) = (int)(f + 0.5) ile sonuc bulunabiliyor. Negatif sayilar icinse (int)(f - 0.5) demek gerekiyor. Sayinin pozitif olup olmadigini if ile test edemedigim icin isaret fonksiyonunu yazdim (nami diger signum).
isaret(f), f pozitifse +1, negatifse -1 donduruyor. 0 icin de hatali olarak -1 donduruyor, ama o sonucu etkilemiyor zaten.
isareti hesaplamak icin once sayiyi integer'a cast ettim. Bir integer'in en soldaki biti isaret biti oluyor. Bu bit 1 ise sayi negatiftir, 0 ise pozitif. O bite ulasmak icin sayinin bitlerini sizeof(sayi)-1 defa saga kaydirdim. Fakat burada bir hata yapmisim, signed sayilarda isaret biti oldugu yerde kaliyormus (*). Fakat bu da isime geliyor, cunku kaydirmadan sonra pozitif sayi icin 000...0 kaliyor, ki bu 0'a esit. Negatif sayi icinse 111...1 kaliyor, bu da -1 demek. Yani bana 1 + 2*kaydir(sayi) sayinin isaretini veriyor.
Bir problem daha vardi. double sayi ]-1,0[ araliginda bir negatif sayi ise, cast edince 0 oldugu icin bana sayi pozitif diyecekti.
sayi € ]-oo,-1] | (int)(sayi) € ]-oo,-1] | isaret(sayi) = -1
sayi € ]-1, 0[ | (int)(sayi) € {0} | isaret(sayi) = +1 (yanlis!)
sayi € {0} | (int)(sayi) € {0} | isaret(sayi) = +1
sayi € ]0, 1[ | (int)(sayi) € {0} | isaret(sayi) = +1
sayi € [1,+oo[ | (int)(sayi) € [1,+oo[ | isaret(sayi) = +1
Eger isareti belirlemek icin sayi-1'i kullanirsam:
sayi € ]-oo,-1] | (int)(sayi-1) € ]-oo,-2] | isaret(sayi) = -1
sayi € ]-1, 0[ | (int)(sayi-1) € {-1} | isaret(sayi) = -1
sayi € {0} | (int)(sayi-1) € {-1} | isaret(sayi) = -1 (yanlis, ama onemsiz)
sayi € ]0, 1[ | (int)(sayi-1) € {0} | isaret(sayi) = +1
sayi € [1,+oo[ | (int)(sayi-1) € [0,+oo[ | isaret(sayi) = +1
(*) C standardinda her derleyici signed sayinin isaret bitini saga kaydirirken sabit tutmak zorunda degilmis.
Euclides
20/03/2007, 18:27
mesela sadece akisyon olsun diye değişik yöntemlerde kullanabilirsin aslında
snippletlerimin arasında bunu buldum :)
int Round(double dValue)
{
unsigned long magic[] = {0x00000000, 0x42380000};
dValue = dValue + *(double*)magic;
return ((*(long*)&dValue) >> 16);
}
böyle bisi dogru oldu sanirim,
#include <iostream.h>
#include <stdlib.h>
int main()
{
double sayi , kalan;
int sonuc;
cout<<"Bir sayi giriniz : ";
cin>> sayi ;
kalan= sayi-(int)sayi;
sonuc=sayi+kalan;
cout<< "Sonuc : "<< sonuc ;
return 0;
}
simdi de myavuzselim in programini ve double meselesini anlamaya celisacagim :)
myavuzselim
20/03/2007, 23:41
@euclides, bilmem anlamis miyim.
magic'in exponent tarafinda 2^36 var, mantissa'da ise 2^0+2^-1 var. magic ile dValue toplanirken dValue'nun exponentini de 2^36 yapmak icin dValue'nun 1'den buyuk degerlerini belirten bitleri mantissa'nin 17. biti ve soluna diziliyorlar, cunku mantissa'da 52 bit var, 52-36=16. Kucuk bitleri de 16. bit ve saginda kaliyorlar. double long'a cast edilince magic'in exponentini belirten gereksiz degerler cope gidiyor. Elimizde kalani 16 defa saga kaydirinca da istedigimiz degeri elde ediyoruz.
Peki 2^-1'in amaci ne (magic'deki 8 sayisi)? Onu 0 yaparsam dogru calismiyor, mutlaka bir islevi olmali.
Bir de sayiyi bir onceki tam sayiya degil de en yakin tam sayiya yuvarlamak icin magic'in mantissa'daki sagdan 16. biti 1 yaptim, ve calisti :) (unsigned long magic[] = {0x00008000, 0x42380000}; ).
Bu arada benim programda (i >> (sizeof(long)-1)) yerine (i >> (8*sizeof(long)-1)) olmasi lazim. Bu hatayla nasil negatif sayilar icin dogru calisabilmis anlayamadim.
Forum Yazılımı : vBulletin v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.