Forum: Ders Arası RSS
Universal Type
Sadece bir deneme...
Sayfa:  1  2  sonraki 
Avatar
Salih Dinçer #1
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Universal Type
Yakında örneklere değineceğim...
struct Tx(T) {
  auto türAdı = typeid(T)// auto = TypeInfo
 
  private:     
    union parçala {
      T data;
      ubyte[T.sizeof] part;
    }
    
    size_t index;
    auto veri = parçala(T.min);
    
    alias front this/* <-- DMD 2.6x'den öncesi
    alias this = front; //*     için satırı açın */
 
  public:
    this(T değeri)
    {
     this.veri.data = değeri;
    }
 
    void popFront()
    {
      index = empty() ? 0 : index + 1;
    }
    
    //enum empty = false; /*
    //@disable
    bool empty() const @property
    {
      return (index > T.sizeof);
    }//*/
    
    T front() const @property
    {
      return index ? part(index) : veri.data;
    }
 
    T part(size_t i) const @property
    // in { assert(i < T.sizeof); } body
    {
      return i > T.sizeof ? 0 : veri.part[i - 1];
    }
 
} unittest {
 
  auto int16Türü = 
       Tx!ushort(0b0000_0010_0000_0001);
  
  assert(int16Türü == 513);
  assert(int16Türü.part(1) == 1);
  assert(int16Türü.part(2) == 2);
  assert(int16Türü.türAdı is typeid(ushort));
}
 
void main()
{
    
}
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
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ı
Gözüme çarpanlar:

  • Daha önce de öyle yazmıştın ama dmd'nin sürümü 2.6x değil de 2.06x olmalı, değil mi? :)

  • Tam amacını bilmiyorum ama boş olan bir topluluğa popFront() yapmak hata kabul edilmeli. Kullanıcılara bir yararı olsun diye index'i 0 yapmak istiyorsun ama ileride kendini bile yanıltabilirsin. empty() true döndürdüğü halde popFront()'u çağıran kod hata yapmış demek olmalıdır. En iyisi hemen o an bu hatayı bildirmek olmalı.

Ali
Avatar
Salih Dinçer #3
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ali hocam, bunun çok eksiği var ve ayak üstü yazılmış kadar basit bir deneme oldu...

Tabii ki oturarak yazdım ve hatta çok düşündüm...:)

Muhtemelen kimse benim ne yapmak istediğimi anlamamıştır. Gerçi anlaşılsa bile omayacak gibi çünkü şablon kullanıyorum. Amacım herhangi bir türü, taşıyıcı yapı (container) ile taşımak. Taşırken kendisi ve türün ismi (string bile olabilir) gelecek. Elbette yanında union ile parçalara bölmek ve aralıklar ile kullanmak da BONUS'u olacak...

İşte asıl sorun:

Bir tür, işleve girerken, hangi isimde olduğunun bilinmesi gerekmekte. Yani T veya auto gibi şeyler, derleme zamanında yerlerine yerleştirmekte. Oysa yapmak istediğim çalışma zamanında türleri serbestçe kullanabilmek. Evet, ütopik görünüyor!
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #4
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ı
Parametrenin hangi tür olduğu bilinmeyince kod derlenemiyor tabii. Örneğin yerel bir değişken olsa, program yığıtında ne kadar yer tutacağının derleme zamanında bilinmesi ve kodun ona göre derlenmesi gerekiyor.

Anladığım kadarıyla ona en yakın kavram std.variant modülünde var:

  http://dlang.org/phobos/std_variant.html

Ali
Avatar
Salih Dinçer #5
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Merhaba Ali hocam,

Variant modülünü şuradaki bağlantıda inceledim ama sanki tam olarak yapmak istediğimi karşılamıyor. Bit'lere erişim konusunda da başka bir modüle ihtiyaç bırakıyor. Belki de ütopik bir şey istiyorumdur diye düşünürken....:)

İşte 1-2 düzenleme ile son bulduğum çözüm:
module sdb.utype;
 
struct Tx {
    union parçala {
      ulong data;
      ubyte[8] part;
    }
 
    parçala veri;
    size_t dizin;
 
    TypeInfo tür;
    
    this(T)(T değeri) {
      this.dizin = 1// artık ilk eleman 1...:)
      this.veri = parçala(
              cast(ulong)değeri);
      this.tür = typeid(T);
    }
    
    void popFront() {
      dizin = empty() ? 0 : dizin + 1;
    }
    
    @property
    bool empty() const {
      return (dizin > tür.tsize());
    }
 
    @property
    ulong front() const {
      return dizin ? part(dizin) : veri.data;
    }
    
    @property
    ubyte part(size_t i) const
    in { assert(i, "0 alamaz!"); } body {
      return i > tür.tsize() ? 0 : veri.part[i - 1];
    }
}
Bu yapıda tek yaptığım, veri uzunluğunu olabilecek en büyük veri türüne (parçala.data: ulong) kayıt ediyorum ve uzunluğunu bayt cinsinden dizin'e kayıt ediyorum. Dilersem part() işlevi ile 1 ila 8. parçaları (0 ilktir geleneğinden uzaklaşarak) talep edebiliyorum. İstersem bunu, aralıklar ile sıralı bir şekilde gelmesini sağlayabiliyorum.

Ancak önemli bir sorun var ve belki de bit'ler ile uğraşacağımdan gerekmiyor ama yapılabilirliğini sorgulamalıyım. Gelen veri türünün ismini ve boyutunu öğrenebildiğime göre o türde bir değişkene aktarabilir miyim?
import std.stdio;
 
void main() {
   uint data = 513;
   auto test = Tx(data);
        test.veri.part.writeln(": ", test.tür);
       
   writefln("%-(%s, %)", test);
  
  /* Bu: 
   * uint veri = cast(test.tür)test.veri.data;
   * olmuyor çünkü türü toString ile döndürüyor...
   */
   
   /* TypeInfo veri; türünde bir şey oluyor herhalde */ 
   typeof(test.tür) veri;
   writeln(typeid(veri)); /*<-- bu satırda
   Parçalama arızası (core dumped) hatası veriyor... */
 
}/*
[1, 2, 0, 0, 0, 0, 0, 0]: uint
1, 2, 0, 0
Parçalama arızası (core dumped)
*/
Sorunları çözmek için TypeInfo yapısını incelemeye karar verdim ama bulabildiğim yer, sanki sadece object modünün eski bir kopyasıydı, anlayamadım: https://github.com/D-Programming-Language/druntime/blob/ma…

Yine de iyi bir başlangıç yaptığımı ve/veya başarılı bir adım attığımı zannediyorum...:D
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2013-02-20, 10:11.
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ı
Eğer asıl türü şablon olarak yazarsan bir alias ile çok kolay:
import std.stdio;
 
struct Tx(T)
{
    union
    {
        T veri;
        ubyte[T.sizeof] parçalar;
    }
 
    alias Tür = T;
}
 
Tx!T tx(T)(T veri)
{
    return Tx!T(veri);
}
 
void main()
{
    auto t = tx(0x12345678);
    writefln("%(0x%02x %)", t.parçalar);
 
    t.Tür değişken;
}
Ali
Avatar
Salih Dinçer #7
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Bu da çok leziz görünüyor, teşekkürler. Ancak dikkat edersen şablon kullanımından vazgeçtim. Çünkü farklı türleri aynı anda taşıyamıyorum. Bilemiyorum, belki de çokuz olaylarına girmenin vakti gelmiştir. Peki çokuzlar, derleme anındaki şablon olanaklarından değil mi? Sanki bir ara yapmaya (kırmaya) çalıştığımız, dizi içinde dizi (farklı tür) çıkmazına girdim yine...:)

Yine de son yapıyı her halükarda denemeliydim. Şu kodların bir ekran görüntüsünü aldım:
void main() {
    auto t = Tx(0x12345678);
    writefln("%(0x%02x %)", t.parçalar);
 
    t.Tür değişken;
    
    "Yapının gerçekteki aldığı ismi: ".writeln(typeid(t));
    "Yeniden oluşturulan değişken  : ".writeln(typeid(değişken));
  
    auto başkaBirTür = Tx('A');
    "Aynı yapının başka türü: ".writeln(typeid(başkaBirTür));
}
ÇIKTISI:
0x78 0x56 0x34 0x12
Yapının gerçekteki aldığı ismi: rasgeleveri.Tx!(int).Tx
Yeniden oluşturulan değişken  : int
Aynı yapının başka türü: rasgeleveri.Tx!(char).Tx
Yukarıda görüldüğü gibi, şablon ile birlikte gelen tür isminden dolayı; aynı kapta durması tehlikeli gazlar gibi (yanıcı/yakıcı) illegal bir durum oluşturuyor. Zaten bu başlıkta işlemeye/aşmaya çalıştığım sorun da bu. Sanki aştım gibi!

Şöyle bir test kodumuz olsun:
import std.stdio, std.random, sdb.utype; /* <-- utype modülü bulunmayanlar,
yukarıda son naklettiğim Tx yapısını aynı dosyada kullanabilirler... */
 
char rasgeleSeç(string seçenekler) {
  auto rasgeleSayı = uniform(0, size_t.max);
  auto aralıkOranı = size_t.max / seçenekler.length;
  size_t biriniSeç = rasgeleSayı / aralıkOranı;
 
  return seçenekler[biriniSeç];
}
 
auto rasgeleTür(size_t adedi) {
  Tx[] sonuç;
 
  while(adedi--) {
    final switch(rasgeleSeç("LISB")) {
      case 'L': ulong s7 = uniform(ulong.min, ulong.max);
                sonuç ~= Tx(s7); break;
      case 'I': uint s5 = uniform(uint.min, uint.max);
                sonuç ~= Tx(s5); break;
      case 'S': ushort s3 = uniform(ushort.min, ushort.max);
                sonuç ~= Tx(s3); break;
      case 'B': ubyte s1 = uniform(ubyte.min, ubyte.max);
                sonuç ~= Tx(s1); break;
    }
  }
  return sonuç;
}
 
 
void main() {
    foreach(r; rasgeleTür(3)) {
      r.veri.data.writeln(": ", r.tür);
    }
}
ÇIKTISI:
1539812105: uint
17258: ushort
1025021539: uint
Anlaşılacağı üzere, artık Tx'in taşıcılığında farklı türden verileri bir işleve sokabilir veya çıkarabilirim. Ancak bu türün içindeki veriyi basit bir eşitleme ile uyumlu olduğu türe aktaramıyorum. Her ne kadar TypeInfo sınıfını kullanmış olsam da, döndürdüğü türün ismi aslında bir dizge ya da ben bir şeyleri yanlış yapıyorum... :scared:
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
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ı
Bir yapı tanımlamak istiyorsun. Bu yapının öyle bir üyesi olsun ki, her türe dönüşebilsin istiyorsun:
r0.tür değişken0;    // belki int
// daha sonra ...
r1.tür değişken1;    // belki başka bir şey 
Derleyici bu satırlar için kod üretebilmek için r0.tür'ün ve r1.tür'ün ne oldukalrını bilmek zorundadır. Hangi genişlikte yazmaç kullansın? Yığıttan kaç bayt ayırsın? vs. Derlemeli bir dilde olanaksızdır.

Her ne kadar Variant'ın doğru çözüm olmadığını düşünsen de bence onların bu sorunu nasıl çözdüklerine bakmalısın. Aynı yöntemler senin yapıda da kullanılabilir.

Ali
Avatar
Salih Dinçer #9
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
std.variant, bana sanki tür dönüşümlerini güvenli bir şekilde otomatikleştiren bir modül gibi geldi. Doğru mu anlamışım?

Bunu düşünürken, benim de artık bir to(T) üyesine ihtiyacım olduğun farkettim ve önce union'ı şu hale getirdim:
    union parçala {
      ulong data;
      ubyte[8] b8x;
      ushort[4] s4x;
      uint[2] i2x;
    }
Sonra bu basit çözüm için şu işlevi patırdanak bir şekilde yazmak kaldı...:)
    T to(T)() {
      switch(T.sizeof) {
        case 1: return cast(T)veri.b8x[0];
        case 2: return cast(T)veri.s4x[0];
        case 4: return cast(T)veri.i2x[0];
        default:
      }
      return cast(T)veri.data;
    }
Aşağıdak kod ile denemek istediğimde başarılı sonuç elde ettim:
   uint data = 153;
   auto test = Tx(data);
        test.veri.b8x.writeln(": ", test.tür);
 
   data = 0;
   data.writeln;
   
   data = test.to!uint();
   data.writeln(": uint");
   
   ubyte veri = test.to!ubyte();
   veri.writeln(": ubyte");
ÇIKTISI:
[153, 0, 0, 0, 0, 0, 0, 0]: uint
0
153: uint
153: ubyte
Şimdi sıra, olası illegal durumları tespit edip invirant, in/out kümelerini icra etmeye geldi. Ancak işaretli türlerde ciddi bir başarısızlık içerisindeyim. Sanırım şu Big-Endian/Little-Endian olaylarına takıldım. Bu eksiğimi gidermek için biraz okuma yapmam gerekecek...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
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ı
Salih Dinçer:
std.variant, bana sanki tür dönüşümlerini güvenli bir şekilde otomatikleştiren bir modül gibi geldi. Doğru mu anlamışım?

Değil. Variant, içinde her türü barındırabilen bir türdür. Her Variant'ın içinde farklı bir tür bile olsa dışarıdan bakıldığında hep Variant göründüğü için Variant dizileri oluşturarak farklı türden değerleri bir arada tutabiliriz:
import std.variant;
 
void main()
{
    Variant[] değerler;
    değerler ~= Variant(42);
    değerler ~= Variant("merhaba");
 
    assert(değerler[0] == 42);
    assert(değerler[1] == "merhaba");
}
Sonuçta tek dizi içine int ve string yerleştirebilmiş olduk. Tabii kullanım aşamasında her elemanın asıl türünü bilerek ona göre davranma gibi bir sorun ortaya çıkıyor. "merhaba"ya bir int ekleyemeyiz.

Böyle sorunların bir çözümü ziyaretçi örüntüsüdür (visitor pattern). Variant bunu destekler ve bizden her veriyi işleyecek olan işlevler (veya temsilciler, vs.) alır:
import std.variant;
import std.stdio;
 
alias KısıtlıTür = Algebraic!(int, string);
 
void foo(KısıtlıTür[] değerler)
{
    // Bunlar visit'e lambda olarak da verilebilir
 
    void stringİşlevi(string s)
    {
        writeln(s ~ " dünya");
    }
 
    void intİşlevi(int i)
    {
        writeln(i + 7);
    }
 
    foreach (değer; değerler) {
        değer.visit!(stringİşlevi, intİşlevi);
    }
}
 
void main()
{
    KısıtlıTür[] değerler;
    değerler ~= KısıtlıTür(42);
    değerler ~= KısıtlıTür("merhaba");
 
    assert(değerler[0] == 42);
    assert(değerler[1] == "merhaba");
 
    foo(değerler);
}
int' ve string'e uygun olan işlev otomatik olarak seçilir:

49
merhaba dünya


std.variant çok daha kapsamlı; bakmanı öneririm. Senin burada yapmaya çalıştığın Variant ile ilgili.

Ali
Avatar
Salih Dinçer #11
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Merhaba,

Yaklaşık 1,5 haftadır, projeyi kısmen rafa kaldırmıştım ve haftasonu (yani dün, pazar günü) yeniden başladım. Rafdan indirdim demiyorum çünkü önemli sayfaları kafamda uçuşuyorlardı...:)

Neyse, şimdi bitirdim ama henüz yeni bir başlık açıp nakletmeden evvel iyice test etmeliyim. O zamana kadar, hemen test kodlarını vermeliyim. Bunu öylesine çok yapmak istiyorum ki "işte D'nin gücü" dermişcesine, bu büyük mutluluğu armağan etmeyi arzuluyorum:
  union parçala {
    ulong data;
    ubyte[8] p8b;
    ushort[4] p4s;
    uint[2] p2i;
  }
 
  struct Tx {
    parçala veri;
    size_t dizin;
 
    TypeInfo tür = typeid(ulong); // fixed a
    
    this(T)(T değeri) {
      this.dizin = 1// artık ilk eleman 1...:)
      this.veri = parçala(
              cast(ulong)değeri); 
      this.tür = typeid(T); // boş kurulmamalı (a)
    }
    
    void popFront() {
      dizin = empty() ? 0 : dizin + 1;
    }
    
    @property
    bool empty() const {
      return (dizin > tür.tsize());
    }
 
    @property
    ulong front() const {
      return dizin ? part(dizin) : veri.data;
    }
    
    @property
    ubyte part(size_t i) const
    in { assert(i, "0 alamaz!"); } body {
      return i > tür.tsize() ? 0 : veri.p8b[i - 1];
    }
 
    T to(T)() {
      switch(T.sizeof) {
        case 1: return cast(T)veri.p8b[0];
        case 2: return cast(T)veri.p4s[0];
        case 4: return cast(T)veri.p2i[0];
        default:
      }
      return cast(T)veri.data;
    }
  }
 
import std.stdio, std.conv, std.random;
 
char rasgeleSeç(string seçenekler) {
  auto rasgeleSayı = uniform(0, size_t.max);
  auto aralıkOranı = size_t.max / seçenekler.length;
  size_t biriniSeç = rasgeleSayı / aralıkOranı;
 
  return seçenekler[biriniSeç];
}
 
auto rasgeleTür(size_t adedi) {
  Tx[] sonuç;
 
  while(adedi--) {
    final switch(rasgeleSeç("LISB10")) {
      case 'L': ulong s7 = uniform(ulong.min, ulong.max);
                sonuç ~= Tx(s7); break;
      case 'I': uint s5 = uniform(uint.min, uint.max);
                sonuç ~= Tx(s5); break;
      case 'S': ushort s3 = uniform(ushort.min, ushort.max);
                sonuç ~= Tx(s3); break;
      case 'B': ubyte s1 = uniform(ubyte.min, ubyte.max);
                sonuç ~= Tx(s1); break;
      case '1': sonuç ~= Tx(true); break;
      case '0': sonuç ~= Tx(false);
    }
  }
  return sonuç;
}
 
void main() {
    auto test = rasgeleTür(10);
 
    foreach(t; test) {
        //t.veri.data.writeln(": ", t.tür);/*
        size_t adedi = t.tür is typeid(bool) ? 1 : t.tür.tsize() * 8;
        string düzen = "%." ~ to!string(adedi) ~ "b";
        writefln(düzen, t.veri.data);//*/
    }
}
Son bir söz: Bu basit, rasgele veri türü seçen ve bunun içini yine rasgele veriler ile dolduran kodları C'de yapamazsınız demeyeceğim ama zorlanacağınız aşikar! Çünkü aynı dizi içinde farklı veri yapılarını başka bir yere aktarabiliyor, bunları istediğiniz esneklikte ekrana yazabiliyor ve/veya kullanabiliyorsunuz.

Örnek bir ekran çıktı...:
0011101101011110010011010110000010011111100000100011010110000010
0
1
0
0
1101111111100101100100010100001000111101110010100110011011010111
1101101111010111
10000010
1011110100001111
1

Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #12
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ı
Salih Dinçer:
      dizin = empty() ? 0 : dizin + 1;

Orada herhalde == olmalı.

char rasgeleSeç(string seçenekler) {
  auto rasgeleSayı = uniform(0, size_t.max);
  auto aralıkOranı = size_t.max / seçenekler.length;
  size_t biriniSeç = rasgeleSayı / aralıkOranı;
 
  return seçenekler[biriniSeç];
}

Uzun yoldan yapmışsın çünkü uniform zaten eşit dağılımlı rasgele sayılar üretir (adı üstünde). :)
char rasgeleSeç(string seçenekler) {
    return seçenekler[uniform(0 .. $)];
}
Tekrar hatırlatma: string'i bayt deposu olarak kullanmış oluyoruz. Umarız birisi bu işlevi rasgele harf amacıyla çağırmaz çünkü ancak bir UTF-8 kod birimi seçme amacıyla kullanılabiliyor.

Üstelik, bilmiyorum senin için önemli mi ama seçenekler arasında bulunmayan bir indeks döndürme tehliken de var.

Bunun etkisini görmek için şöyle değerler uyduralım: size_t.max 100 olsun; seçenekler.length de 3... Bu durumda aralıkOranı==33 olur. uniform 99 döndürmüşse bu işlev 99/33 sonucunda 3 döndürür. O da seçenekler'in yasal bir indeksi değil.

Ali
Avatar
Salih Dinçer #13
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
Salih Dinçer:
      dizin = empty() ? 0 : dizin + 1;

Orada herhalde == olmalı.
Burada amacım dizin sınıra eriştiyse başa dönmesini (0 olmasını) sağlamak değilse kendisini bir arttırmak. Bir nevi dizin.max'ı belirleyebildiğim işaretsiz bir tür gibi. Sınırına geldiğinde başa sarıyor...

acehreli:
char rasgeleSeç(string seçenekler) {
  auto rasgeleSayı = uniform(0, size_t.max);
  auto aralıkOranı = size_t.max / seçenekler.length;
  size_t biriniSeç = rasgeleSayı / aralıkOranı;
 
  return seçenekler[biriniSeç];
}
Uzun yoldan yapmışsın çünkü uniform zaten eşit dağılımlı rasgele sayılar üretir (adı üstünde). :)
char rasgeleSeç(string seçenekler) {
    return seçenekler[uniform(0 .. $)];
}
Bu yöntemi bilmiyordum ama sanırım şu şekilde seçenekler[uniform(0, $)]; arada virgül olacak değil mi? Yine de uniform'a çok güvenmiyorum. Ardı ardına daha çok benzer seçim yapacakmış gibi geliyor bana. O yüzde algoritmanın frekansını size_t.max'a kadar yükselttim ya; yine de denemeli.

acehreli:
... bilmiyorum senin için önemli mi ama seçenekler arasında bulunmayan bir indeks döndürme tehliken de var.

Bunun etkisini görmek için şöyle değerler uyduralım: size_t.max 100 olsun; seçenekler.length de 3... Bu durumda aralıkOranı==33 olur. uniform 99 döndürmüşse bu işlev 99/33 sonucunda 3 döndürür. O da seçenekler'in yasal bir indeksi değil.
Sanırım 32bit ve 64bit sistemlerde size_t.max çok büyük bir sayı olacağı için ve seçenekler de bu sayının yanında çok küçük kalacağından böyle bir tehlike görünmüyor. Tabi yukarıdaki kolay yöntem gibi her ikisini de denemek lazım. Örneğin 1 milyar seçim arasında seçeneklerini dağılım oranına basit bir eşleme tablosu ile bakılabilir.

Katkılar için teşekkür ederim...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #14
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Denedim sanki fark yok gibi, herhalde Ali hocamın ki daha hızlı olsa gerek:
import std.stdio, std.random;
 
char r1() {
    string seçenekler = "ABC";
    auto rasgeleSayı = uniform(0, size_t.max);
    auto aralıkOranı = size_t.max / seçenekler.length;
    size_t biriniSeç = rasgeleSayı / aralıkOranı;
   
    return seçenekler[biriniSeç];
}
 
char r2() {
    string seçenekler = "ABC";
    return seçenekler[uniform(0, $)];
}
 
void main() {
  int[char] R1 = [ 'A': 0, 'B': 0, 'C': 0 ];
  int[char] R2 = [ 'A': 0, 'B': 0, 'C': 0 ];
 
  size_t adedi = 1000_000_000;
  while(adedi--) {
    R1[r1]++;
    R2[r2]++;
  }
  R1.writeln(": uzun");
  R2.writeln(": kısa");
}/* Çıktısı:
['A':333347757, 'B':333326399, 'C':333325844]: uzun
['A':333334064, 'B':333331179, 'C':333334757]: kısa
*/
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #15
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 #13
Salih Dinçer:
Burada amacım dizin sınıra eriştiyse başa dönmesini (0 olmasını) sağlamak değilse kendisini bir arttırmak. Bir nevi dizin.max'ı belirleyebildiğim işaretsiz bir tür gibi. Sınırına geldiğinde başa sarıyor...

Ben de amacının o olduğunu farketmiştim ama if deyimlerinde bazen == yerine = kullanılmasına benzeyen hataya düştüğünü sanmıştım. Değilmiş tabii ki çünkü = işlecinin önceliği üçlü işleçten daha düşük. Ben bu gibi yanılgılar nedeniyle gereksiz ;) parantezler kullanmayı seviyorum:
      dizin = (empty() ? 0 : dizin + 1);
sanırım şu şekilde seçenekler[uniform(0, $)]; arada virgül olacak değil mi?

Doğru. :blush:

Sanırım 32bit ve 64bit sistemlerde size_t.max çok büyük bir sayı olacağı için ve seçenekler de bu sayının yanında çok küçük kalacağından böyle bir tehlike görünmüyor.

Hayır, tehlike geçerli. uniform'un size_t.max-1 döndürdüğünü varsayalım (bu örnekte -5'e kadar aynı durum var):
import std.stdio;
 
void main()
{
    char[] seçenekler;
    seçenekler.length = 10;
 
    auto rasgeleSayı = (size_t.max - 1); // uniform(0, size_t.max);
    writeln("rasgeleSayı: ", rasgeleSayı);
    auto aralıkOranı = size_t.max / seçenekler.length;
    writeln("aralıkOranı: ", aralıkOranı);
    size_t biriniSeç = rasgeleSayı / aralıkOranı;
    writeln("biriniSeç: ", biriniSeç);
}
Çıktısı:

rasgeleSayı: 18446744073709551614
aralıkOranı: 1844674407370955161
biriniSeç: 10

Seçilen indeks 10 elemanlı dizi için yasal değil.

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:
Sayfa:  1  2  sonraki 
Forum: Ders Arası RSS
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-18, 07:46:29 (UTC -08:00)