Thread overview
GBS-6: Statik Üyeye Sahip Yapı
Feb 04, 2022
Salih Dincer
Feb 04, 2022
Ali Çehreli
Feb 04, 2022
Salih Dincer
Feb 04, 2022
Salih Dincer
Feb 04, 2022
Ali Çehreli
Feb 04, 2022
Ali Çehreli
February 04, 2022

Merhaba,

Yeni bir lezzetli örnek (bir o kadar da Gereksiz Bilgi Serisi) aşağıdadır:

(Ancak hala real sayılar üzerinden neden assert( a == b) eşitliğini kullanamadığımı anlamadım. Bilen varsa (sanırım kayan nokta olayları?) ve izah ederse sevinirim!)

// eSAYI'sı 41'in karaköküdür:
enum real eSAYI = 6.40312423743;

// Bu derleme zamanında eSAYI'sının karesini alabilir:
enum Karesi(real n) = n * n;

// Aynı sayı statik bir forma bürünüyor!
static real sSAYI = eSAYI;

struct Foo
{
    static real sRl;
    //* Eğer static bir eleman varsa, kurucu this() olmalı ->
    this(real sayı)
    {
        this.sRl = sayı;
    }//*/

    static real Pow()
    {
        return sRl^^2;
    }

    real rPow2(real base)
    {
      import std.math : pow;
      return pow(base, 2);
    }

    string toString() const
    {
      import std.conv;
      return to!string(sRl);
    }
}
import
std.stdio;
void main()
{
          /** 1. TEST: static üye **/

  auto foo = Foo(sSAYI);
  writeln(" - Yapı kurulurken sRl eşitliği = ", foo.sRl, " <-n²+1");

  foo.sRl = foo.Pow + 1;// 42 (2. aldığı değer)
  writeln(" - Karesi alınıp +1 ekli değeri = ", foo.sRl, " <-n²");// 42
  write(" - Tekrar karesi hesaplatılırsa = ", foo.Pow, " n->  "); // 1764

  auto bar = Foo();
       bar.writeln;// 42 (ana! 42 2. aldığı değer hala burda)

          /** 2. TEST: assert eşitliği **/

  //assert(bar.sRl == 42.0L); /** Neden eşit olmaz **/
  //assert(bar.rPow2(sSAYI) == 41.0L);

  bar.rPow2(sSAYI).writeln;// 41
  writeln(Karesi!eSAYI);// 41

  //static assert(Karesi!eSAYI == 41.0L); /** Bu da eşit değilmiş! **/
}

Açıklama: Klasik bir n²+1 hesaplaması ile kod, karşınızda. Özelliği, statik elemanlı Foo(), bar olarak tekrar vücut bulduğunda 42'nin, "ben burdayım kardeşim" demesi :)

assert olayları ise bonus diyelim ve çalışmaması muhtemelen kayan nokta ile alakalı, ne dersiniz?

Sevgiler, saygılar...

February 03, 2022
On 2/3/22 17:31, Salih Dincer wrote:
>
> *(Ancak hala real sayılar üzerinden neden ```assert( a == b)```
> eşitliğini kullanamadığımı anlamadım. Bilen varsa (sanırım kayan nokta
> olayları?) ve izah ederse sevinirim!)*

Evet. Bu konuyu anlamada bana en çok yardımı olan bilgi, kayan noktalı türlerin bitlerinin ancak tam sayıları ve ikinin negatif kuvvetlerini tam olarak ifade edebildikleridir.

Yani, 1, 42, vs. gibi tamsayılar ve 0.5, 0.25, 0.125 gibi 1'in ikinin katlarına bölünmüş değerler. Buna göre, bunların toplamı olan bir sayı tam olarak ifade edilebilir:

Örneğin, 42 + 0.5 + (0.125 / 16) bir kaç tane bit ile ve tam olarak ifade edilir.

Bunun dışındaki değerler ifade edilemez. Örneğin, 0.1 değeri yukarıdaki gibi parçalardan oluşamaz.

Ek olarak, derleyiciler derleme zamanındaki hesaplarda örneğin 'real' kullanabilirler ve derleme zamanıyla çalışma zamanı arasına bir de öyle bir fark girer.

> ```d
> // eSAYI'sı 41'in karaköküdür:

Daha doğru olarak, 41'in kareköküne yakın bir değerdir.

> enum real eSAYI = 6.40312423743;
>
> // Bu derleme zamanında eSAYI'sının karesini alabilir:
> enum Karesi(real n) = n * n;
>
> // Aynı sayı statik bir forma bürünüyor!
> static real sSAYI = eSAYI;
>
> struct Foo
> {
>      static real sRl;
>      //* Eğer static bir eleman varsa, kurucu this() olmalı ->
>      this(real sayı)
>      {
>          this.sRl = sayı;

O biraz garip olmuş çünkü Foo türünün paylaştığı tek değişken, Foo türünden her nesne oluşturulduğunda atanıyor. Belki anlamlıdır ama yapıların static değişkenleri normalde başka bir yolla ilklenir.

>    //static assert(Karesi!eSAYI == 41.0L); /** Bu da eşit değilmiş! **/

Tesadüyen bitleri tuttuğunda bazen eşit de olabilir.

D'nin bitleri tam gösteren olanağını biliyorsun. Onunla bakınca eşit olmadıkları görülür. Ben bunu yakalamak için hem 'float' seçiyorum hem de başka rasgele bir değer:

import std.stdio;
import std.math;

void main() {
  float sayı = 413;         // Tam olarak ifade edilebilir
  float kökü = sqrt(sayı);   // Bu edilemez
  float belki = kökü * kökü;  // Bu belki

  writefln!" sayı: %a"(sayı);
  writefln!" kökü: %a"(kökü);
  writefln!"belki: %a"(belki);
}

Çıktısı:

 sayı: 0x1.9dp+8
 kökü: 0x1.45288ep+4
belki: 0x1.9cfffep+8

Neredeyse eşit ama gördüğüm kadarıyla 1.9d ile 1.9cfffe arasında 2 bit fark var (onaltılı düzendedir).

Ali

February 04, 2022

On Friday, 4 February 2022 at 05:57:28 UTC, Ali Çehreli wrote:

>

Evet. Bu konuyu anlamada bana en çok yardımı olan bilgi, kayan noktalı türlerin bitlerinin ancak tam sayıları ve ikinin negatif kuvvetlerini tam olarak ifade edebildikleridir.

Hocam, dediğin gibi assert() haklıymış. Çünkü şart işleçlerini, küçükEşit(<=)'e çevirdiğimde hiç itiraz etmiyor ve gerek derleyici gerekse pek kıymetlimiz assert görevini yapıyor.

Az önce tüm real'leri çift hassasiyet (double)'a çevirdim ve virgülden sonra basamak sayısını 16'ya çıkarınca, iddia ediyorum eşittir (==)'e hiçbir itiraz yükselmedi :)

writefln!"%.16f"(sSAYI); // 6.4031242374328485

Tek bir şey dışında; o da benim gördüğüm birşey: Yukarda, ekrana yazılan sayı gerçekte (enum kod satırında) ...8481 diye bitiyor. Yani writefln için hassasiyetİ 16 digit yapmama rağmen 15. basamaktan sonra sallıyor 😀

Bu durumla bir kere daha (aralıklar ile Pi sayısını hesaplattığım sırada) karşılaşmıştım.

İyi hafta sonları...

February 04, 2022

On Friday, 4 February 2022 at 06:38:59 UTC, Salih Dincer wrote:

>
writefln!"%.16f"(sSAYI); // 6.4031242374328485

Sıcağı, sıcağına çok ilginç (belki de ilginç olmayan!) bir şey :)

  enum Karesi(double n) = n * n;

  enum double eSAYI = 6.4031242374328481;
static double sSAYI = eSAYI;

void main() {
  import std.stdio;

  // Test1:
  writefln!"sSAYI² = %a"(sSAYI * sSAYI);// 41: sSAYI² = 0x1.48p+5

  // Test2:
  writefln!"eSAYI² = %a"(Karesi!eSAYI); // 41: eSAYI² = 0x1.47fffffffffffp+5

  immutable double Test3 = Karesi!eSAYI;
  // static assert(Test3 == 41.0L); /** Bu hala itiraz ediyor! **/
}

Yukardaki kodda, ekrana yazanları assert() ile denetlediğimde, sonuçlardan anlayacağınız üzere biri geçemez! O da belli ki 2. test ve sanırım 1 bit ile kaybetmekte. Yani derleme zamanında enum ile oluşturduğum anonim işlev cast(double)'a rağmen görevini tam yapamamış olabilir.

3.testte ise şu aşağıdaki hatayı derlerken veriyor ama ayrıntısını bize vermiyor. Programcı tahmin etmeli, oysa 41.0L == 41.0L sonucu false değildir! Sizce static assert() için bir bugZilla case açsam mı?

staticStruct.d(61): Error: static assert: `41.0L == 41.0L` is false

Önce biraz okuma yapmam lazım. Şurada (19.22) CTFE konusuna örnek ile değinilmiş: https://dlang.org/spec/function.html#interpretation

Özetle 2 sorun var:
1.'si neden enum ile anonymous function oluşturunca değerler tam taşınmıyor?
2.'si static assert'in verdiği uyarı kendiyle çelişiyor. Acaba daha ayrıntı verebilir mi?

Sevgiler, saygılar...

February 04, 2022
On 2/3/22 22:38, Salih Dincer wrote:

> Hocam, dediğin gibi assert() haklıymış. Çünkü şart işleçlerini,
> küçükEşit(<=)'e çevirdiğimde

Başka ifadelerde belki de >='e çevirdiğinde işe yarayacaktır. Hesapların sonunda hangi ifadenin bir kaç bit fazlası olduğuna bakar.

> hiç itiraz etmiyor ve gerek derleyici
> gerekse pek kıymetlimiz assert görevini yapıyor.

assert başta da görevini yapıyordu. O yalnızca ifadenin true olup olmadığına bakar.

> Az önce tüm real'leri çift hassasiyet (double)'a çevirdim ve virgülden
> sonra basamak sayısını 16'ya çıkarınca, iddia ediyorum eşittir (==)'e
> hiçbir itiraz yükselmedi :)

Bu ifadelerde öyleymiş demek ki. Yapacak bir şey yok: Sonsuz bit olmadığı sürece örneğin 0.1'i IEEE düzeninde ifade edemeyiz.

> hassasiyetİ 16 digit yapmama rağmen 15. basamaktan sonra sallıyor 😀

Türlerin hassasiyetiyle ilgili olmalı. .dig, ondalık olarak kaç hane duyarlı olduklarını bildirir:

pragma(msg, float.dig);
pragma(msg, double.dig);
pragma(msg, real.dig);

Çıktısı:

6
15
18

(real başka sistemlerde 15 de bildirebilir çünkü double ile aynı da olabilir. D'nin büyüklüğü kesin olmayan tek türüdür.)

Ali

February 04, 2022
On 2/3/22 23:43, Salih Dincer wrote:

>    enum double eSAYI = 6.4031242374328481;

O, 41'in kare kökü değil. (Ona yakın bir değer.)

>    immutable double Test3 = Karesi!eSAYI;

Dolayısıyla o, 41 değil.

> ```staticStruct.d(61): Error: static assert:  `41.0L == 41.0L` is false```

Evet, hata mesajı geliştirilebilir. (Benim işimde yazdığım bir program parantez içinde %a olarak da gösterir.)

> 1.'si neden enum ile anonymous function oluşturunca değerler tam
> taşınmıyor?

Tam konumuz değil ama o tanım "enum ile anonymous function" değil, şablon gerçeklemesi olarak ilklenmiş bir değişken. Yani, senin gösterdiğin kısa söz dizimi, aşağıdaki "eponymous" şablonla eşdeğer:

template Karesi(double n) {
  enum double Karesi = n * n;
}

Yani aslında bir işlev yok ama gerektiği kadar hazır değer (manifest constant) var. Örneğin Karesi!2 için sanki aşağıdaki yazılmış gibi bir değer oluşturulur:

enum double Karesi_2 = 2 * 2;

Önemli bir konu değil ama function olmadığını ve yalnızca bir ilk değer olduğunu hatırlatmak istedim.

> 2.'si static assert'in verdiği uyarı kendiyle çelişiyor. Acaba daha
> ayrıntı verebilir mi?

Evet, herhalde parantez içinde %a ile de yazdırılabilir.

Kesirli sayı sorunları konuşulurken hep "What Every Computer Scientist Should Know About Floating-Point Arithmetic" makalesinin okunması gerektiği söylenir:

  https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Bana çok zor gelmişti. Onun yerine, ben bir DConf 2016 sunumunu öneririm:

  https://dconf.org/2016/talks/clugston.html

O sunum bana çok zevkli ve eğitici gelmişti. :)

Ali