Tamsayılar ve Aritmetik İşlemler
D'nin karar verme ile ilgili yapılarından if
'i ve while
'ı gördük. Bu bölümde temel türlerin sayısal olanlarıyla yapılan aritmetik işlemlere bakacağız. Böylece bundan sonraki bölümlerde çok daha becerikli ve ilginç programlar yazabileceksiniz.
Aritmetik işlemler aslında son derece basittirler çünkü zaten günlük hayatımızda her zaman karşımıza çıkarlar. Buna rağmen, temel türlerle ilgilenirken mutlaka bilinmesi gereken çok önemli kavramlar da vardır. Tür uzunluğu, taşma, ve kırpılma kavramlarını anlıyorsanız bütün konuyu bu tabloya bakarak geçebilirsiniz:
İşleç | Etkisi | Örnek kullanım |
---|---|---|
++ | değerini bir arttırır | ++değişken |
-- | değerini bir azaltır | --değişken |
+ | iki değerin toplamı | birinci + ikinci |
- | birinciden ikincinin çıkarılmışı | birinci - ikinci |
* | iki değerin çarpımı | birinci * ikinci |
/ | birincinin ikinciye bölümü | birinci / ikinci |
% | birincinin ikinciye bölümününden kalan | birinci % ikinci |
^^ | birincinin ikinci'nin değeri kadar üssü (birincinin ikinci kere kendisiyle çarpımı) |
birinci ^^ ikinci |
Tablodaki ikili işleçlerin yanına =
karakteri gelenleri de vardır: +=
, -=
, *=
, /=
, %=
, ve ^^=
. Bunlar işlemin sonucunu soldaki değişkene atarlar:
sayı += 10;
O ifade sayı
'ya 10 ekler ve sonucu yine sayı
'ya atar; sonuçta değerini 10 arttırmış olur. Şu ifadenin eşdeğeridir:
sayı = sayı + 10;
Taşma: Her değer her türe sığmaz ve taşabilir. Örneğin, 0 ile 255 arasında değerler tutabilen ubyte
'a 260 değeri verilmeye kalkışılırsa değeri 4 olur. (Not: C ve C++ gibi bazı dillerin tersine, taşma D'de işaretli türler için de yasaldır ve işaretsiz türlerle aynı davranışa sahiptir.)
Kırpılma: Tamsayılar virgülden sonrasını tutamazlar. Örneğin 3/2 ifadesinin değeri 1 olur.
Eğer bu kavramları örneğin başka dillerden biliyorsanız, bu kadarı yetebilir. İsterseniz geri kalanını okumayabilirsiniz, ama yine de sondaki problemleri atlamayın.
Bu bölüm ilgisiz bilgiler veriyor gibi gelebilir; çünkü aritmetik işlemler hepimizin günlük hayatta sürekli olarak karşılaştığımız kavramlardır: Tanesi 10 lira olan bir şeyden iki tane alırsak 20 lira veririz, veya üçü 45 lira olan şeylerin tanesi 15 liradır.
Ne yazık ki işler bilgisayarda bu kadar basit olmayabilir. Sayıların bilgisayarda nasıl saklandıklarını bilmezsek, örneğin 3 milyar borcu olan bir firmanın 3 milyar daha borç alması sonucunda borcunun 1.7 milyara düştüğünü görebiliriz. Başka bir örnek olarak, 1 kutusu 4 çocuğa yeten dondurmadan 11 çocuk için 2 tane yetecek diye hesaplayabiliriz.
Bu bölüm size öncekilerden daha teknik gelebilir ama tamsayıların bilgisayarda nasıl ifade edildiklerinin bir programcı tarafından mutlaka bilinmesi gerekir.
Tamsayılar
Tamsayılar ancak tam değerler alabilen türlerdir: -2, 0, 10, vs. Bu türler 2.5 gibi kesirli değerler tutamazlar. Daha önce temel türler tablosunda da gördüğünüz tamsayı türleri şunlardır:
Tür | Bit Uzunluğu | İlk Değeri |
---|---|---|
byte | 8 | 0 |
ubyte | 8 | 0 |
short | 16 | 0 |
ushort | 16 | 0 |
int | 32 | 0 |
uint | 32 | 0 |
long | 64 | 0L |
ulong | 64 | 0LU |
Hatırlarsanız, tür isimlerinin başındaki u
karakteri "unsigned"dan geliyordu ve "işaretsiz" demekti. O türler eksi işareti olmayan türlerdir ve yalnızca sıfır ve daha büyük değerler alabilirler.
Her ne kadar diğer türler gibi 0
değerine eşit olsalar da, 0L
ve 0LU
sırasıyla long
ve ulong
türünde hazır değerlerdir.
Bitler ve tür uzunlukları
Günümüzdeki bilgisayar sistemlerinde en küçük bilgi parçası bittir. Bit, elektronik düzeyde ve devrelerin belirli noktalarında elektrik geriliminin var olup olmaması kavramıyla belirlendiği için, ancak iki durumdan birisinde bulunabilir. Bu durumlar 0 ve 1 değerleri olarak kabul edilmişlerdir. Yani sonuçta bir bit, iki değişik değer saklayabilir.
Yalnızca iki durumla ifade edilebilen kavramlarla fazla karşılaşmadığımız için bitin kullanışlılığı da azdır: yazı veya tura, odada ışıkların açık olup olmadığı, vs. gibi iki durumu olan kavramlar...
Biraz ileri giderek iki biti bir araya getirirsek, ikisinin birlikte saklayabilecekleri toplam değer adedi artar. İkisinin ayrı ayrı 0 veya 1 durumunda olmalarına göre toplam 4 olasılık vardır. Soldaki rakam birinci biti, sağdaki rakam da ikinci biti gösteriyor olsun: 00, 01, 10, ve 11. Yani bir bit eklemeyle toplam durum sayısı ikiye katlanmış olur. Bit eklemenin etkisini daha iyi görebilmek için bir adım daha atabiliriz: Üç bit, toplam 8 değişik durumda bulunabilir: 000, 001, 010, 011, 100, 101, 110, 111.
Bu sekiz durumun hangi tamsayı değerlerine karşılık gelecekleri tamamen anlaşmalara ve geleneklere kalmıştır. Yoksa örneğin 000 durumu 42 değerini, 001 durumu 123 değerini, vs. gösteriyor da olabilirdi. Tabii bu kadar ilgisiz değerler kullanışlı olmayacaklarından, 3 bitlik bir türü örnek alırsak, bu 8 durumun işaretli ve işaretsiz olarak kullanılmasında aldığı değerler şu tablodakine benzer:
Bitlerin Durumu | İşaretsiz Değer | İşaretli Değer |
---|---|---|
000 | 0 | 0 |
001 | 1 | 1 |
010 | 2 | 2 |
011 | 3 | 3 |
100 | 4 | -4 |
101 | 5 | -3 |
110 | 6 | -2 |
111 | 7 | -1 |
Burada görmenizi istediğim, 3 bitten nasıl 8 farklı değer elde edilebildiğidir.
Görüldüğü gibi, eklenen her bit, saklanabilecek bilgi miktarını iki katına çıkartmaktadır. Bunu devam ettirirsek; bitlerin bir araya getirilmelerinden oluşturulan değişik uzunluktaki türlerin saklayabildikleri farklı değer miktarlarını, bir önceki bit uzunluğunun saklayabileceği değer miktarını 2 ile çarparak şöyle görebiliriz:
Bit Adedi | Saklanabilecek Farklı Değer Adedi | D Türü | En Küçük Değeri | En Büyük Değeri |
---|---|---|---|---|
1 | 2 | |||
2 | 4 | |||
3 | 8 | |||
4 | 16 | |||
5 | 32 | |||
6 | 64 | |||
7 | 128 | |||
8 | 256 | byte ubyte | -128 0 | 127 255 |
... | ... | |||
16 | 65,536 | short ushort | -32768 0 | 32767 65535 |
... | ... | |||
32 | 4,294,967,296 | int uint | -2147483648 0 | 2147483647 4294967295 |
... | ... | |||
64 | 18,446,744,073,709,551,616 | long ulong | -9223372036854775808 0 | 9223372036854775807 18446744073709551615 |
... | ... |
Bazı tablo satırlarını atladım ve aynı sayıda bitten oluşan D türlerinin işaretli ve işaretsiz olanlarını aynı satırda gösterdim (örneğin int
ve uint
32 bitlik satırdalar).
Hangi durumda hangi tür
D'de üç bitlik tür yoktur. Olsaydı, tutabildiği 8 farklı değer ile ancak atılan zarın sonucu veya haftanın gün sayısı gibi kavramları ifade etmek için kullanılabilirdi.
Öte yandan, uint
çok büyük bir tür olsa da, dünyadaki bütün insanları kapsayacak bir kimlik kartı numarası gibi bir kavram için kullanılamaz, çünkü uint
dünyadaki insan nüfusu olan 7 milyardan daha az sayıda değer saklayabilir. long
ve ulong
'un Türkçe'de nasıl okunduğunu bile bilemeyeceğim toplam değer adedi ise çoğu kavram için fazlasıyla yeterlidir.
Temel bir kural olarak, özel bir neden yoksa, tamsayılar için öncelikle int
'i düşünebilirsiniz.
Taşma
Türlerin bit sayılarıyla belirlenen bu kısıtlamaları, onlarla yapılan işlemlerde beklenmedik sonuçlar verebilir. Örneğin değerleri 3 milyar olan iki uint
'in toplamı gerçekte 6 milyar olsa da, en fazla 4 milyar kadar değer saklayabilen uint
'e sığmaz. Bu durumda sonuç uint
'ten taşmış olur; programda hiçbir uyarı verilmeden 6 milyarın ancak 4 milyardan geri kalanı, yani 2 milyar kadarı sonuç değişkeninde kalır. (Aslında 6 milyar eksi 4.3 milyar, yani yaklaşık olarak 1.7 milyar...)
Kırpılma
Tamsayılar kesirli değerler tutamadıkları için ne kadar önemli olsa da, virgülden sonraki bilgiyi kaybederler. Örneğin 1 kutusu 4 çocuğa yeten dondurmadan 11 çocuk için 2.75 kutu gerekiyor olsa bile, bu değer bir tamsayı tür içinde ancak 2 olarak saklanabilir.
Taşmaya ve kırpılmaya karşı alabileceğiniz bazı önlemleri işlemlerin tanıtımından sonra vereceğim. Önce aritmetik işlemleri tanıyalım.
Tür nitelikleri hatırlatması
Temel türlerin tanıtıldığı bölümde tür niteliklerini görmüştük: .min
, türün alabileceği en küçük değeri; .max
da en büyük değeri veriyordu.
Arttırma: ++
Tek bir değişkenle kullanılır. Değişkenin isminden önce yazılır ve o değişkenin değerini 1 arttırır:
import std.stdio; void main() { int sayı = 10; ++sayı; writeln("Yeni değeri: ", sayı); }
Yeni değeri: 11
Arttırma işleci, biraz aşağıda göreceğiniz atamalı toplama işlecinin 1 değeri ile kullanılmasının eşdeğeridir:
sayı += 1; // ++sayı ifadesinin aynısı
Arttırma işleminin sonucu; eğer türün taşıyabileceği en yüksek değeri aşıyorsa, o zaman taşar ve türün alabildiği en düşük değere dönüşür. Bunu denemek için önceki değeri int.max
olan bir değişkeni arttırırsak, yeni değerinin int.min
olduğunu görürüz:
import std.stdio; void main() { writeln("en düşük int değeri : ", int.min); writeln("en yüksek int değeri : ", int.max); int sayı = int.max; writeln("sayının önceki değeri : ", sayı); ++sayı; writeln("sayının sonraki değeri: ", sayı); }
en düşük int değeri : -2147483648 en yüksek int değeri : 2147483647 sayının önceki değeri : 2147483647 sayının sonraki değeri: -2147483648
Bu çok önemli bir konudur; çünkü sayı hiçbir uyarı verilmeden, en yüksek değerinden en düşük değerine geçmektedir; hem de arttırma işlemi sonucunda!
Buna taşma denir. Benzer taşma davranışlarını azaltma, toplama, ve çıkarma işlemlerinde de göreceğiz.
Azaltma: --
Tek bir değişkenle kullanılır. Değişkenin isminden önce yazılır ve o değişkenin değerini 1 azaltır:
--sayı; // değeri bir azalır
Azaltma işleci, biraz aşağıda göreceğiniz atamalı çıkarma işlecinin 1 değeri ile kullanılmasının eşdeğeridir:
sayı -= 1; // --sayı ifadesinin aynısı
++
işlecine benzer şekilde, eğer değişkenin değeri baştan o türün en düşük değerindeyse, yeni değeri o türün en yüksek değeri olur. Buna da taşma denir.
Toplama: +
İki ifadeyle kullanılır ve aralarına yazıldığı iki ifadenin toplamını verir:
import std.stdio; void main() { int sayı_1 = 12; int sayı_2 = 100; writeln("Sonuç: ", sayı_1 + sayı_2); writeln("Sabit ifadeyle: ", 1000 + sayı_2); }
Sonuç: 112 Sabit ifadeyle: 1100
Eğer iki ifadenin toplamı o türde saklanabilecek en yüksek değerden fazlaysa, yine taşma oluşur ve değerlerin ikisinden de daha küçük bir sonuç elde edilir:
import std.stdio; void main() { // İki tane 3 milyar uint sayı_1 = 3000000000; uint sayı_2 = 3000000000; writeln("uint'in en yüksek değeri: ", uint.max); writeln(" sayı_1: ", sayı_1); writeln(" sayı_2: ", sayı_2); writeln(" toplam: ", sayı_1 + sayı_2); writeln("TAŞMA! Sonuç 6 milyar olmadı!"); }
uint'in en yüksek değeri: 4294967295 sayı_1: 3000000000 sayı_2: 3000000000 toplam: 1705032704 TAŞMA! Sonuç 6 milyar olmadı!
Çıkarma: -
İki ifadeyle kullanılır ve birinci ile ikincinin farkını verir:
import std.stdio; void main() { int sayı_1 = 10; int sayı_2 = 20; writeln(sayı_1 - sayı_2); writeln(sayı_2 - sayı_1); }
-10 10
Eğer sonucu tutan değişken işaretsizse ve sonuç eksi bir değer alırsa, yine garip sonuçlar doğar. Yukarıdaki programı uint
için tekrar yazarsak:
import std.stdio; void main() { uint sayı_1 = 10; uint sayı_2 = 20; writeln("SORUN! uint eksi değer tutamaz:"); writeln(sayı_1 - sayı_2); writeln(sayı_2 - sayı_1); }
SORUN! uint eksi değer tutamaz: 4294967286 10
Eninde sonunda farkları alınacak kavramlar için hep işaretli türlerden seçmek iyi bir karardır. Yine, özel bir neden yoksa normalde int
'i seçebilirsiniz.
Çarpma: *
İki ifadenin değerlerini çarpar. Yine taşmaya maruzdur:
import std.stdio; void main() { uint sayı_1 = 6; uint sayı_2 = 7; writeln(sayı_1 * sayı_2); }
42
Bölme: /
Birinci ifadeyi ikinci ifadeye böler. Tamsayılar kesirli sayı tutamayacakları için, eğer varsa sonucun kesirli kısmı atılır. Buna kırpılma denir. Örneğin bu yüzden aşağıdaki program 3.5 değil, 3 yazmaktadır:
import std.stdio; void main() { writeln(7 / 2); }
3
Virgülden sonrasının önemli olduğu hesaplarda tamsayı türleri değil, kesirli sayı türleri kullanılır. Kesirli sayı türlerini bir sonraki bölümde göreceğiz.
Kalan: %
Birinci ifadeyi ikinci ifadeye böler ve kalanını verir. Örneğin 10'un 6'ya bölümünden kalan 4'tür:
import std.stdio; void main() { writeln(10 % 6); }
4
Bu işleç bir sayının tek veya çift olduğunu anlamada kullanılır. Tek sayıların ikiye bölümünden kalan her zaman için 1 olduğundan, kalanın 0 olup olmadığına bakarak sayının tek veya çift olduğu kolayca anlaşılır:
if ((sayı % 2) == 0) { writeln("çift sayı"); } else { writeln("tek sayı"); }
Üs alma: ^^
Birinci ifadenin ikinci ifade ile belirtilen üssünü alır. Örneğin 3 üssü 4, 3'ün 4 kere kendisiyle çarpımıdır:
import std.stdio; void main() { writeln(3 ^^ 4); }
81
Atamalı aritmetik işleçleri
Yukarıda gösterilen ve iki ifade alan aritmetik işleçlerin atamalı olanları da vardır. Bunlar işlemi gerçekleştirdikten sonra ek olarak sonucu sol taraftaki değişkene atarlar:
import std.stdio; void main() { int sayı = 10; sayı += 20; // sayı = sayı + 20 ile aynı şey; şimdi 30 sayı -= 5; // sayı = sayı - 5 ile aynı şey; şimdi 25 sayı *= 2; // sayı = sayı * 2 ile aynı şey; şimdi 50 sayı /= 3; // sayı = sayı / 3 ile aynı şey; şimdi 16 sayı %= 7; // sayı = sayı % 7 ile aynı şey; şimdi 2 sayı ^^= 6; // sayı = sayı ^^ 6 ile aynı şey; şimdi 64 writeln(sayı); }
64
Eksi işareti: -
Önüne yazıldığı ifadenin değerini artıysa eksi, eksiyse artı yapar:
import std.stdio; void main() { int sayı_1 = 1; int sayı_2 = -2; writeln(-sayı_1); writeln(-sayı_2); }
-1 2
Bu işlecin sonucunun türü, değişkenin türü ile aynıdır. uint
gibi işaretsiz türler eksi değerler tutamadıkları için, bu işlecin onlarla kullanılması şaşırtıcı sonuçlar doğurabilir:
uint sayı = 1; writeln("eksi işaretlisi: ", -sayı);
-sayı
ifadesinin türü de uint
'tir ve o yüzden eksi değer alamaz:
eksi işaretlisi: 4294967295
Artı işareti: +
Matematikte sayıların önüne yazılan + işareti gibi bunun da hiçbir etkisi yoktur. İfadenin değeri eksiyse yine eksi, artıysa yine artı kalır:
import std.stdio; void main() { int sayı_1 = 1; int sayı_2 = -2; writeln(+sayı_1); writeln(+sayı_2); }
1 -2
Önceki değerli (sonek) arttırma: ++
Not: Özel bir nedeni yoksa normal arttırma işlecini kullanmanızı öneririm.
Normal arttırma işlecinden farklı olarak ifadeden sonra yazılır. Yukarıda anlatılan ++
işlecinde olduğu gibi ifadenin değerini bir arttırır, ama içinde geçtiği ifadede önceki değeri olarak kullanılır. Bunun etkisini görmek için normal ++
işleciyle karşılaştıralım:
import std.stdio; void main() { int normal_arttırılan = 1; writeln(++normal_arttırılan); // 2 yazılır writeln(normal_arttırılan); // 2 yazılır int önceki_değerli_arttırılan = 1; // Değeri arttırılır ama ifadede önceki değeri kullanılır: writeln(önceki_değerli_arttırılan++); // 1 yazılır writeln(önceki_değerli_arttırılan); // 2 yazılır }
2 2 1 2
Yukarıdaki arttırma işleminin olduğu satır şunun eşdeğeridir:
int önceki_değeri = önceki_değerli_arttırılan; ++önceki_değerli_arttırılan; writeln(önceki_değeri); // 1 yazılır
Yani bir anlamda, sayı arttırılmıştır, ama içinde bulunduğu ifadede önceki değeri kullanılmıştır.
Önceki değerli (sonek) azaltma: --
Not: Özel bir nedeni yoksa normal azaltma işlecini kullanmanızı öneririm.
Önceki değerli arttırma ++
ile aynı şekilde davranır ama arttırmak yerine azaltır.
İşleç öncelikleri
Yukarıdaki işleçleri hep tek başlarına ve bir veya iki ifade ile gördük. Oysa mantıksal ifadelerde olduğu gibi, birden fazla aritmetik işleci bir arada kullanarak daha karmaşık işlemler oluşturabiliriz:
int sayı = 77; int sonuç = (((sayı + 8) * 3) / (sayı - 1)) % 5;
Mantıksal ifadelerde olduğu gibi, bu işleçlerin de D tarafından belirlenmiş olan öncelikleri vardır. Örneğin, *
işlecinin önceliği +
işlecininkinden yüksek olduğundan, parantezler kullanılmadığında sayı + 8 * 3
ifadesi önce *
işlemi uygulanacağı için sayı + 24
olarak hesaplanır. Bu da yukarıdakinden farklı bir işlemdir.
O yüzden, parantezler kullanarak hem işlemleri doğru sırada uygulatmış olursunuz, hem de kodu okuyan kişilere kodu anlamalarında yardımcı olmuş olursunuz.
İşleç öncelikleri tablosunu ilerideki bir bölümde göreceğiz.
Taşma olduğunu belirlemek
Her ne kadar henüz görmediğimiz işlev ve ref
parametre olanaklarını kullansa da, taşma durumunu bildirebilen core.checkedint
modülünü burada tanıtmak istiyorum. Bu modül +
ve -
gibi işleçleri değil, şu işlevleri kullanır: işaretli ve işaretsiz toplama için adds
ve addu
, işaretli ve işaretsiz çıkarma için subs
ve subu
, işaretli ve işaretsiz çarpma için muls
ve mulu
, ve ters işaretlisini almak için negs
.
Örneğin, a
ve b
'nin int
türünde iki değişken olduklarını varsayarsak, toplamlarının taşıp taşmadığını aşağıdaki kod ile denetleyebiliriz:
import core.checkedint; void main() { // Deneme amacıyla taşmaya neden oluyoruz int a = int.max - 1; int b = 2; // Aşağıdaki 'adds' işlevi sırasında sonuç taşmışsa bu // değişkenin değeri 'true' olur: bool taştı_mı = false; int sonuç = adds(a, b, taştı_mı); if (taştı_mı) { // 'sonuç'u kullanamayız çünkü taşmış // ... } else { // 'sonuç'u kullanabiliriz // ... } }
Taşma gibi sorunlara karşı etkili bir başka modül, Checked
türünü tanımlayan std.experimental.checkedint modülüdür. Ancak, hem kullanımı hem de gerçekleştirmesi kitabın bu noktasında fazla ileri düzey kabul edilmelidir.
Taşmaya karşı önlemler
Eğer bir işlemin sonucu seçilen türe sığmıyorsa, zaten yapılacak bir şey yoktur. Ama bazen sonuç sığacak olsa da ara işlemler sırasında oluşabilecek taşmalar nedeniyle yanlış sonuçlar elde edilebilir.
Bir örneğe bakalım: kenarları 40'a 60 kilometre olan bir alanın her 1000 metre karesine bir elma ağacı dikmek istiyoruz. Kaç ağaç gerekir?
Bu problemi kağıt kalemle çözünce sonucun 40000 çarpı 60000 bölü 1000 olarak 2.4 milyon olduğunu görürüz. Bunu hesaplayan bir programa bakalım:
import std.stdio; void main() { int en = 40000; int boy = 60000; int ağaç_başına_yer = 1000; int gereken_ağaç = en * boy / ağaç_başına_yer; writeln("Gereken elma ağacı: ", gereken_ağaç); }
Gereken elma ağacı: -1894967
Bırakın yakın olmayı, bu sonuç sıfırdan bile küçüktür! Bu sorunun nedeni, programdaki en * boy
alt işleminin bir int
'e sığamayacak kadar büyük olduğu için taşması, ve bu yüzden de geri kalan / ağaç_başına_yer
işleminin de yanlış çıkmasıdır.
Buradaki ara işlem sırasında oluşan taşmayı değişken sıralarını değiştirerek giderebiliriz:
int gereken_ağaç = en / ağaç_başına_yer * boy;
Şimdi hesap doğru çıkar:
Gereken elma ağacı: 2400000
Bu ifadenin doğru çalışmasının nedeni, şimdiki ara işlem olan en / ağaç_başına_yer
ifadesinin değerinin 40 olduğu için artık int
'ten taşmamasıdır.
Aslında böyle bir durumda en doğru çözüm; bir tamsayı türü değil, kesirli sayı türlerinden birisini kullanmaktır: float
, double
, veya real
.
Kırpılmaya karşı önlemler
Benzer şekilde, ara işlemlerin sırasını değiştirerek kırpılmanın da etkisini azaltabiliriz. Bunun ilginç bir örneğini, aynı sayıya bölüp yine aynı sayıyla çarptığımızda görebiliriz: 10/9*9 işleminin sonucunun 10 çıkmasını bekleriz. Oysa:
import std.stdio; void main() { writeln(10 / 9 * 9); }
9
Yine, işlemlerin sırasını değiştirince kırpılma olmayacağı için sonuç doğru çıkar:
writeln(10 * 9 / 9);
10
Burada da en iyi çözüm belki de bir kesirli sayı türü kullanmaktır.
Problemler
- Yazacağınız program kullanıcıdan iki tamsayı alsın ve birincinin içinde ikinciden kaç tane bulunduğunu ve artanını versin. Örneğin 7 ve 3 değerleri girilince çıkışa şunu yazsın:
7 = 3 * 2 + 1
- Aynı programı, kalan 0 olduğunda daha kısa sonuç verecek şekilde değiştirin. Örneğin 10 ve 5 verince gereksizce "10 = 5 * 2 + 0" yazmak yerine, yalnızca yeterli bilgiyi versin:
10 = 5 * 2
- Dört işlemi destekleyen basit bir hesap makinesi yazın. İşlemi bir menüden seçtirsin ve girilen iki değere o işlemi uygulasın. Bu programda taşma ve kırpılma sorunlarını gözardı edebilirsiniz.
- Yazacağınız program 1'den 10'a kadar bütün sayıları ayrı satırlarda olacak şekilde yazdırsın. Ama, bir istisna olarak 7 değerini yazdırmasın. Programda şu şekilde tekrarlanan
writeln
ifadeleri kullanmayın:import std.stdio; void main() { // Böyle yapmayın! writeln(1); writeln(2); writeln(3); writeln(4); writeln(5); writeln(6); writeln(8); writeln(9); writeln(10); }
Onun yerine, bir döngü içinde değeri arttırılan bir değişken düşünün ve 7'yi yazdırmama koşuluna da dikkat edin. Burada herhalde eşit olmama koşulunu denetleyen
!=
işlecini kullanmak zorunda kalacaksınız.