Tamsayı manipülasyonu ile bir IEEE 754 64 bit ikili kayan nokta sayısı uygulama


12

(Şimdilik "C" sorusunu etiketledim, ancak sendikaları destekleyen başka bir dilin farkındaysanız, bunu da kullanabilirsiniz.)

Göreviniz + - * /, aşağıdaki yapı için dört standart matematiksel işleç oluşturmaktır:

union intfloat{
    double f;
    uint8_t h[8];
    uint16_t i[4];
    uint32_t j[2]; 
    uint64_t k;
    intfloat(double g){f = g;}
    intfloat(){k = 0;}
}

böylece operasyonların kendileri yalnızca tamsayı parçayı manipüle eder veya bunlara erişir (böylece işlem sırasında herhangi bir zamanda çiftle karşılaştırılmamalıdır) ve sonuç tam olarak aynıdır (veya sayısal olmayan sonuçlar durumunda işlevsel olarak eşdeğerdir NaN) karşılık gelen matematiksel işlem doğrudan doubleonun yerine uygulanmış gibi .

Hangi tamsayı bölümünün değiştirileceğini, hatta belki de farklı operatörler arasında farklı bölümleri kullanarak seçebilirsiniz. (Bunu yapmak isteyip istemediğinizden emin olmasam da, sendikadaki herhangi bir alandan "imzasız" ı kaldırmayı da seçebilirsiniz.)

Skorunuz, dört operatörün her biri için karakter cinsinden kod uzunluğunun toplamıdır. En düşük puan kazanır.

IEEE 754 şartname bilmeyen bizler için, burada Wikipedia'da bu konuda bir makale.


Düzenlemeler:

03-06 08:47 İç yapıya inşaatçılar eklendi. İkili / vb. Manuel olarak ayarlamak yerine bunları test için kullanmanıza izin verilir.


1
Olmadı! Bana bir çözümün olduğunu söyle.
dmckee --- eski moderatör yavru kedi

4
Hmmm ... belki de tanımlamak daha iyi olurdu intstructaçısından uint8_8, uint16_tve böylece mutlak büyüklükleri olarak short, intve benzeri standardında tanımlanmamıştır (her tip asgari boyutuna sahip ve boyut olarak sıkı bir sipariş var, ama bu kadar).
dmckee --- eski moderatör yavru kedi

1
Tahminsiz olsa bile bu harika (ve zorlu) bir uygulama sanırım
John Dvorak

3
Bu soruda, yuvarlamanın nasıl işlendiği ve iyi bir test paketi ile ilgili belgeler kullanılabilir.
Peter Taylor

4
Ben spec olduğunu eminim, ama gerçek spec birkaç yüz USD mal olacak. Muhtemelen ücretsiz olarak kullanılabilecek açıklamalar vardır, ancak IMO, bu tür ayrıntıları (veya en azından birkaç yıl içinde hala olması muhtemel bir siteye bağlantı) dahil etmek için soru-asker üzerinde olmalıdır. soruya cevap vermek yerine, sorunun gerçekte ne istediğini bilmek için gerekli malzemeleri aramaya gitmeleri.
Peter Taylor

Yanıtlar:


11

C ++, ~ 1500 karakter

Şamandıraları 8000 ikili basamaklı sabit nokta gösterimine genişletir, bunun üzerinde işlemleri yapar, sonra geri dönüşür.

// an "expanded" float.                                                                                                         
// n is nan, i is infinity, z is zero, s is sign.                                                                               
// nan overrides inf, inf overrides zero, zero overrides digits.                                                                
// sign is valid unless nan.                                                                                                    
// We store the number in fixed-point, little-endian.  Binary point is                                                          
// at N/2.  So 1.0 is N/2 zeros, one, N/2-1 zeros.                                                                              
#define N 8000
struct E {
  int n;
  int i;
  int z;
  long s;
  long d[N];
};
#define V if(r.n|r.i|r.z)return r
// Converts a regular floating-point number to an expanded one.                                                                 
E R(F x){
  long i,e=x.k<<1>>53,m=x.k<<12>>12;
  E r={e==2047&&m!=0,e==2047,e+m==0,x.k>>63};
  if(e)m+=1L<<52;else e++;
  for(i=0;i<53;i++)r.d[2925+e+i]=m>>i&1;
  return r;
}
E A(E x,E y){
  int i,c,v;
  if(x.s>y.s)return A(y,x);
  E r={x.n|y.n|x.i&y.i&(x.s^y.s),x.i|y.i,x.z&y.z,x.i&x.s|y.i&y.s|~x.i&~y.i&x.s&y.s};V;
  if(x.s^y.s){
    c=0;
    r.z=1;
    for(i=0;i<N;i++){
      v=x.d[i]-y.d[i]-c;
      r.d[i]=v&1;c=v<0;
      r.z&=~v&1;
    }
    if(c){x.s=1;y.s=0;r=A(y,x);r.s=1;}
  }else{
    c=0;
    for(i=0;i<N;i++){
      v=x.d[i]+y.d[i]+c;
      r.d[i]=v&1;c=v>1;
    }
  }
  return r;
}
E M(E x, E y){
  int i;
  E r={x.n|y.n|x.i&y.z|x.z&y.i,x.i|y.i,x.z|y.z,x.s^y.s};V;
  E s={0,0,1};
  for(i=0;i<6000;i++)y.d[i]=y.d[i+2000];
  for(i=0;i<4000;i++){
    if(x.d[i+2000])s=A(s,y);
    y=A(y,y);
  }
  s.s^=x.s;
  return s;
}
// 1/d using Newton-Raphson:                                                                                                    
// x <- x * (2 - d*x)                                                                                                           
E I(E d){
  int i;
  E r={d.n,d.z,d.i,d.s};V;
  E t={};t.d[4001]=1;
  for(i=N-1;i>0;i--)if(d.d[i])break;
  E x={0,0,0,d.s};x.d[N-i]=1;
  d.s^=1;
  for(i=0;i<10;i++)x=M(x,A(t,M(d,x)));
  return x;
}
// Convert expanded number back to regular floating point.                                                                      
F C(E x){
  long i,j,e,m=0;
  for(i=N-1;i>=0;i--)if(x.d[i])break;
  for(j=0;j<N;j++)if(x.d[j])break;
  if(i>0&x.d[i-53]&(j<i-53|x.d[i-52])){E y={0,0,0,x.s};y.d[i-53]=1;return C(A(x,y));}
  if(i<2978){e=0;for(j=0;j<52;j++)m+=x.d[j+2926]<<j;}
  else if(i<5024){e=i-2977;for(j=0;j<52;j++)m+=x.d[i+j-52]<<j;}
  else x.i=1;
  if(x.z)e=m=0;
  if(x.i){e=2047;m=0;}
  if(x.n)e=m=2047;
  F y;y.k=x.s<<63|e<<52|m;return y;
}
// expand, do op, unexpand                                                                                                      
F A(F x,F y){return C(A(R(x),R(y)));}
F S(F x,F y){y.k^=1L<<63;return A(x,y);}
F M(F x,F y){return C(M(R(x),R(y)));}
F D(F x,F y){return C(M(R(x),I(R(y))));}

Tam bir golf sayımı elde etmek için tüm alanları ve yeni satırları kaldırmak için çok tembelim, ancak yaklaşık 1500 karakter.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.