Thread overview
IEEE 754
Oct 25, 2012
Salih Dinçer
Oct 27, 2012
Salih Dinçer
October 26, 2012

Merhaba,

Bu konuda şurada (http://tr.wikipedia.org/wiki/IEEE_754-2008) bazı bilgiler mevcut. Bir yerde aşağıdaki gibi union ve bir takım işlevler ile karşılaştım. Her ne kadar aynısını D'ye uyarlayamasam da (çünkü union için bir struct var!) yakın bir şeyler yapmaya çalıştım...:)
Alıntı:

>
> typedef union
> {
>     double value;
>     struct
>     {
>         u_int32_t msw;
>         u_int32_t lsw;
>     } parts;
> } ieee_double_shape_type;
> double fabs(double x)
> {
>     u_int32_t high;
>     GET_HIGH_WORD(high, x);
>     SET_HIGH_WORD(x, high & 0x7fffffff);
>     return x;
> }
> ```

>

Burada üst bitleri (MSB) 0x7fffffff ile AND'liyor. Nedenini bilmediğim bir sebepten kısmen doğru çalışıyor ama büyük sayılarda sayı değerini bozuyor. Oysa çift duyarlılıklı (double) sayıları incelediğimizde son biti (soldaki ilk bit) 0 yapmak yetiyor. Bunun için de sırasıyla 1 bit sola ve sağa kaydırmak veya sayıyı 0x7fffffff_ffffffff ile AND'lemek gerekiyor.

Belki bu tür (double) sayılara müdahale etmek isterseniz aşağıdakine benzer bir örnek işinize yarayabilir:

union IEEE754
{
double value;
uint[2] parts;
}

double fabs(double x)
{
auto FP = IEEE754(x);
uint i = FP.parts[1] << 1;
FP.parts[1] = i >> 1;
return FP.value;
}

void main() {
double test = -1234567890.123;
assert(fabs(test) == std.math.fabs(test));
}


Başarılar...

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
October 26, 2012
  1. union içinde her tür eleman bulunabilir. C söz dizimi D'den biraz farklı. Öncelikle, o yapının bir yerde tanımlanmış olması gerekiyor. D'de isimsiz yapı olmadığı için isimle tanımlamak gerekiyor ve tabii bir de o türden bir üye:
union U
{
   double d;

   struct S    // <-- tür tanımı
   {}

   S s;        // <-- o türden üye
}
  1. C kodundaki GET_HIGH_WORD ve SET_HIGH_WORD makroları herhalde sistemin sonculluğunu da hesaba katıyor olmalılar. Yoksa, double'ın IEEE düzeninde üst bit olarak geçen bitleri msw'ya da rastlayabilir lsw'ya da. Onun için std.system.endian'ın değerinden yararlanmamız gerekiyor.

  2. C ve C++'ın tersine, üçlü işleç (?:) D'de sol değer (lvalue) üretir (o dillerde sağ değer (rvalue) üretir). O yüzden aşağıdaki kodda eşitliğin sol tarafında da kullanabildim.

  3. Sonculluk karşılaştırmasını çalışma zamanında yapmak yerine, kodu bir 'static if' ile farklı da oluşturabilirdim. O zaman çalışma zamanındaki karşılaştırmalar ortadan kalkmış olacağından kod daha hızlı olurdu:

   static if (endian == Endian.littleEndian)
   {
       // ...

   } else {
       // ...
   }
  1. Deneme kodlarında kesirli değer kullanırken ikiye tam bölünmüş olan kesirli değerler kullanmanı öneririm. Örneğin sıfırdan sonra .5, .25, .125, vs. iyidir. Yoksa assert() ifadesindeki == işleci yanlış da çıkabilirdi.

Bütün bunları uygulayınca şu kod çalışıyor:

import std.conv;
import std.math;
import std.system;

union ieee_double_shape_type
{
   double value;

   struct Parts
   {
       uint msw;
       uint lsw;
   }

   Parts parts;

   uint highWord() const @property
   {
       return (endian == Endian.littleEndian) ? parts.lsw : parts.msw;
   }

   void highWord(uint değer) @property
   {
       ((endian == Endian.littleEndian) ? parts.lsw : parts.msw) = değer;
   }

   double opCast(T : double)() const
   {
       return value;
   }
}

double fabs(double x)
{
   auto ieee = ieee_double_shape_type(x);
   ieee.highWord = (ieee.highWord & 0x7fffffff);
   return to!double(ieee);
}

void main()
{
   double test = -1234567890.125;
   assert(fabs(test) == std.math.fabs(test));
}

Not: Yukarıdaki kodda daha temiz olarak aşağıdaki ifadeyi yazabilmek isterdik ama D'nin nitelikleri henüz aşağıdaki kodu otomatik olarak yukarıdaki koda dönüştürmeyi bilmiyor:

   ieee.highWord &= 0x7fffffff;

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 27, 2012

Ali hocam eline sağlık, harika olmuş...:D

Alıntı (acehreli):

>
  1. union içinde her tür eleman bulunabilir. C söz dizimi D'den biraz farklı. Öncelikle, o yapının bir yerde tanımlanmış olması gerekiyor. D'de isimsiz yapı olmadığı için isimle tanımlamak gerekiyor ve tabii bir de o türden bir üye:

Dahili yapı tanımlamasını denedim ve hatta bir ara align ile de bir şeyler yapmaya çalıştım. Ancak üyeler aynı bellek alanını paylaştırmayı beceremeyince belki desteklemiyordur dedim ve fazla uğraşmadım. Yine de align olayını bilinçsizce kullandığımı ve halen anlayamadığımı belirtir saygılarımı sunarım...:)

Alıntı (acehreli):

>
  1. C kodundaki GET_HIGH_WORD ve SET_HIGH_WORD makroları herhalde sistemin sonculluğunu da hesaba katıyor olmalılar. Yoksa, double'ın IEEE düzeninde üst bit olarak geçen bitleri msw'ya da rastlayabilir lsw'ya da. Onun için std.system.endian'ın değerinden yararlanmamız gerekiyor.

Evet, kodlar içinde (-bknz. şurada (http://www.libsdl.org/tmp/SDL/src/libm/math_private.h)) endian olayı macro if()'i ve bir bayrak ile denetlenmiş. Neticede iki farklı union ama yapı içindeki üyelerin yer değiştirilmesi ile çözüm üretilmeye çalışmış. Ne yalan söyleyeyim; D'nin çözümü ve dolayısıyla Ali hocamın emeği çok daha lezzetli gözüküyor... :cool:

Alıntı (acehreli):

>
  1. C ve C++'ın tersine, üçlü işleç (?:) D'de sol değer (lvalue) üretir (o dillerde sağ değer (rvalue) üretir). O yüzden aşağıdaki kodda eşitliğin sol tarafında da kullanabildim.

Bunu bilmiyordum! Genelde else özellikli ve değişken eşitlemeli durumlarda hemen tek satırda işi halletmek için tercih ettiğim ve çok sevdiğim bir işleç. Bir de duruma göre else özelliği (: işaret) olmadan da kullanabilseydik çok güzel olurdu. Tabi o zaman üçlü işleç denmezdi. N'apalım, bu gibi durumlarda da sahici if() var...:)

Sevgiler, saygılar...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 27, 2012

Alıntı (Salih Dinçer):

>

D'nin çözümü ve dolayısıyla Ali hocamın emeği çok daha lezzetli gözüküyor

Ama dediğim gibi daha yavaştır çünkü her işlemde endian karşılaştırması yapıyor. Ben de 'static if' ile zaten tam da onların yaptığını kasdetmiştim:

   struct Parts
   {
       static if (endian == Endian.littleEndian) {
           uint lsw;
           uint msw;

       } else {
           uint msw;
           uint lsw;
       }
   }

Ondan sonra highWord() işlevlerinde artık karşılaştırma gerekmez.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]