Forum: D Programlama Dili RSS
Aritmetik dönüşümler şaşırtıcı olabilir
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Aritmetik dönüşümler şaşırtıcı olabilir
Program şu:

import std.algorithm;
import std.stdio;
 
void main()
{
    // Boş bir satır
    char[10] satır = ' ';
 
    // Bir yazıyı, o satırın ilk çeyrek noktası etrafında ortalamak istiyoruz.
    int ortalanacakYer = satır.length / 4;
    string yazı = "0123456";
 
    // Eğer yazı yeterince uzunsa, çeyrek nokta etrafında ortalanırken başı
    // soldan taşabilir. Yani sıfırdan küçük bir indeks değeri hesaplanabilir. O
    // yüzden 'max(0' kullanarak indeksin en az 0 olmasını sağlamak istiyoruz.
    //
    // Eğer hesap sıfırdan küçükse, örneğin -1 ise, max(0, -1)'in değeri 0 olur
    // ve istediğimiz gerçekleşir.
    int başlangıç = max(0, ortalanacakYer - yazı.length / 2);
 
    // Ama bu denetimi geçemiyoruz! Nasıl olur?
    assert(başlangıç >= 0);      // <-- Çalışma zamanında HATA atılır
 
    // Sonra, yazıyı satıra şöyle yerleştirmek istiyoruz:
    foreach (i, harf; yazı) {
        satır[başlangıç + i] = harf;
    }
 
    writefln("|%s|", satır);
}

Şaşırtıcı bir şekilde, assert ifadesi doğru çıkmıyor. başlangıç'ın 0'dan küçük olmaMAsı gerekir. Ama öyle çıkmıyor!

Bu olay C++ ve C'de de vardır. Herhalde başka dillerde de olmalı. Nedeni, Tür Dönüşümleri dersinde kısacık değinmiş olduğum "Aritmetik dönüşümler":

  http://ddili.org/ders/d/tur_donusumleri.html

Tam olarak da o başlığın altındaki 4.4 numaralı madde ile ilgili.

Yukarıdaki açıklamalar yeterli oldu mu? ;)

Ali
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Belki bilmeyenler vardır diye: max, kendisine verilen parametreler içinden en büyük olanını verir. (min de en küçük olanını).

Şablonların çokuzlu parametre olanağı sayesinde de ikiden fazla parametre ile de kullanılabilir:

import std.algorithm;
 
void main()
{
    assert(max(0, 10, 42, 7) == 42);
}

Ali
canalpay (Moderatör) #3
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Ben olayı anlamadım. O yazdığınız kod büyük ihtimalle derleme CTFmi ne yüzünden  şu hale dönüşmez mi :

int başlangıç = max(0, -1);

ve başlangıç 0 olur. Ama -1 nasıl oluyor ?
Mengu (Moderatör) #4
Kullanıcı başlığı: NONSERVIAM
Üye Tem 2009 tarihinden beri · 347 mesaj · Konum: Dersaadet
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
ali hocam senden bir ricam var yanlis anlamazsan.

turkce konusundaki hassasiyetini anliyorum ve saygiyla karsiliyorum fakat her kavramin turkcelestirilmesini dogru bulmuyorum nitekim garip kelimeler cikiyor ortaya. dolayisiyla en kotu olarak turkcelestirdigin teknik terimleri parantez icinde orjinal olarak belirtirsen cok iyi olur. :)

saygilar.
http://www.mengu.net - some kind of monster
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Öncelikle, hayır, kesinlikle yanlış anlamam.  (Yazın görüşünce görürsün gününü! :-p)

Türkçeler konusunda bu forumda ve başka yerlerde çok kafa yorduk, çok tartıştık, ve sonuçta bazı sözcüklerde az ya da çok beğenerek karar kıldık. Örneğin 'gösterge'den bile hâlâ emin değilim. 'işaretçi' de olurdu, 'gösterici' de...

"Çokuzlu"yu (tuple) da yeterince tartıştıktan sonra yarım gönülle kabul etmiştik. (Hatta bazı yerlerde yanlışlıkla "çok uzlu" dediğimiz de oldu ama bence o "çok akıllı" anlamına gelir. :) )

Tabii "tuple" hiç olmaz, çünkü nasıl telaffuz edileceğini bilemeyiz: İngilizce'dekine yakın olarak "tupıl" mı, ses uyumu nedeniyle "tüple" mi? :)

Hiç olmazsa, bütün uydurma :) sözcükler sözlükte bulunuyor:

  http://ddili.org/sozluk.html

Yapıcı eleştirilere devam! :)

Ali

Not: "Çokuzlu parametreleri"ne şu derste değinmişim:

  http://ddili.org/ders/d/sablonlar_ayrintili.html
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Şimdi baktım: "çokuzlu"yu kabul eden başka yerler de var:

  http://bilisimsozlugu.net/n-tuple

Google'da tam *ooon* adet sayfa çıkıyor. :D

Ali
canalpay (Moderatör) #7
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
(Hatta bazı yerlerde yanlışlıkla "çok uzlu" dediğimiz de oldu ama bence o "çok akıllı" anlamına gelir. :) )


Yanılıyorsunuz. Çok uslu çok akıllı demek. Uz, us arasında çok fark var. Uz becerikli , işe yatkın demek.(Diğer anlamıda iyi güzelmiş.) Hatta uzman'da da uz becerikli anlamında man kişi anlamında. Bizim Türkçedeki man ingilizcedeki mandan alıntı değil.(Man'a örnek: Uzman, öğretmen(büyük ünlü uyumuna uydu.) sayman, seçmen...)

Çokuzlu sözcüğünü sözcüklerde de direk gösteriyorlar. Ama Mengü Beyin dediği yinede arada sırada parantez içinde ingilizcesinide söylemekte yarar var ki zaten dershane bölümünde de bunu yapıyorsunuz.
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #3
canalpay:
int başlangıç = max(0, -1);

ve başlangıç 0 olur. Ama -1 nasıl oluyor ?

Önce, hiç sorgulamadan kabul ettiğimiz aritmetik dönüşüm kavramını hatırlayalım.

Tür denetiminin derleme zamanında yapıldığı D gibi dillerde, eğer tam sağlamcı olunacaksa, short ve int'in uyumsuz oldukları düşünülebilir:

import std.stdio;
 
void main()
{
    short s = 7;
    int i = 42;
    writeln(typeid(s + i))// <-- uyumsuz türlerle işlem
}

Her ne kadar türleri uyumsuz olsa da, doğal olarak short ve int tamsayıların aritmetik işlemlerde kullanılabilmelerini bekleriz. Öyle de olur...

Ayrıca, yine doğal olarak, o işlemin daha büyük olan türde yapılmasını da isteriz. O yüzden yukarıdaki programın çıktısı "int" olur; çünkü s+i işleminin sonucunun türü int'tir. Buraya kadar güzel...

Böyle bütün dönüşüm kurallarının dilin standardı tarafından belirlenmiş olması gerekir. Standartlar iyidir... :)

D'nin C'den aldığı aritmetik dönüşüm kuralları gereği, bir int ve uint birlikte kullanıldıklarında, sonucun türü uint'tir. (Bu, bütün tamsayı türlerin işaretli ve işaretsiz olanları arasında da böyledir; örneğin long ve ulong'da da...)

O yüzden, aşağıdaki program "uint" yazar:

import std.stdio;
 
void main()
{
    uint u = 7;
    int i = 42;
    writeln(typeid(u + i));
}

(Bu kural garip gelebilir; ama öyle olmasının da geçerli nedenleri vardır. Şu anda nedenini hatırlamıyorum.)

Bizim hesaba geçmeden önce bir ayrıntıya daha değinmek gerek: dizilerin .length niteliklerinin (property) değeri, işaretsiz bir türdür. O yüzden bu program "uint" yazar:

import std.stdio;
 
void main()
{
    int[] dizi;
    writeln(typeid(dizi.length));
}

Bu da doğaldır; çünkü uzunluk sıfırdan küçük olamayacağına göre, .length uint olabilir. Bu C++ topluluklarındaki .size() üye işlevinde ve C'nin size_t türünde de böyledir: uzunluk türü hep işaretsiz bir türdür. (Bunu eleştirenler de vardır; çünkü uzunlukların farkları alınmak istendiğinde sonuç eksi olamaz.)

Artık bizim hesaba geçebiliriz:

ortalanacakYer - yazı.length / 2

yazı.length uint olduğu için, hesabın yukarıdaki parçasının türü uint'tir. Yani, -1 olmasını beklediğimiz değer, uint eksi değer tutamayacağı için 4 küsur milyar bir değer olur.

O yüzden, max(0, 4 küsur milyar)'ın sonucu 4 küsur milyar çıkar.

Daha bitmedi! :) max'ın 4 küsur milyar olan sonucu, daha sonra başlangıç'ı ilklemek için kullanılıyor:

int başlangıç = ...

Tamsayılar dersinde gördüğümüz gibi, 4 küsur milyar bir int'e sığamayacağı için taşar ve eksi bir değer olur.

İşte hikaye o... :)

Ali
acehreli (Moderatör) #9
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Buradaki temel sorun, işaretsiz türlerin çıkarma işleminde kullanılmaları ve sonucun eksi değer tutamadığı için beklenmedik şekilde çok büyük çıkmasıydı.

Bir öneri geldi: işaretsiz türlerin geçtiği ifadeyi çıkarma işlemi içermeyecek şekilde yazmak:

// SORUNLU!
int başlangıç = max(0, ortalanacakYer - yazı.length / 2);

// güzel
int başlangıç = ortalanacakYer - min(ortalanacakYer, yazı.length / 2);

Ali
acehreli (Moderatör) #10
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bir tane daha:

import std.stdio;
 
void main()
{
    uint sayı = 1;
    writeln("eksi işaretlisi: ", -sayı);
}

Çıktısı:

eksi işaretlisi: 4294967295

Nedeni, - işlecinin sonucunun türünün sağındaki ifade ile aynı olmasıymış. Türümüz uint olduğu için sonuç da -1'in uint'e atanması durumundaki gibi oluyor.

Bu bilgiyi de Aritmetik İşlemler dersine ekledim ama daha siteye koymadım.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-22, 05:00:17 (UTC -08:00)