Menerapkan nomor titik mengambang biner IEEE 754 64-bit melalui manipulasi integer

12

(Saya telah menandai pertanyaan "C" untuk saat ini, tetapi jika Anda mengetahui bahasa lain yang mendukung serikat pekerja, Anda juga dapat menggunakannya.)

Tugas Anda adalah membangun empat operator matematika standar + - * /untuk struct berikut:

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;}
}

sedemikian rupa sehingga operasi itu sendiri hanya pernah memanipulasi atau mengakses bagian integer (jadi tidak ada perbandingan dengan ganda kapan saja selama operasi baik), dan hasilnya persis sama (atau secara fungsional setara, dalam hal hasil non-numerik seperti NaN) seolah-olah operasi matematika yang sesuai telah diterapkan langsung ke doublegantinya.

Anda dapat memilih bagian integer mana yang akan dimanipulasi, bahkan mungkin menggunakan yang berbeda di antara operator yang berbeda. (Anda juga dapat memilih untuk menghapus "unsigned" dari salah satu bidang di serikat, meskipun saya tidak yakin apakah Anda ingin melakukannya.)

Skor Anda adalah jumlah dari panjang kode dalam karakter untuk masing-masing dari empat operator. Skor terendah menang.

Bagi kita yang tidak terbiasa dengan spesifikasi IEEE 754, berikut adalah artikel tentang itu di Wikipedia.


Suntingan:

03-06 08:47 Menambahkan konstruktor ke struct intfloat. Anda diizinkan untuk menggunakannya untuk pengujian, daripada mengatur secara manual ganda / dll.

Joe Z.
sumber
1
Astaga! Katakan kamu punya solusinya.
dmckee --- ex-moderator kitten
4
Hmmm ... mungkin akan lebih baik untuk mendefinisikan intstructdalam hal uint8_8, uint16_tdan seterusnya sebagai ukuran absolut short, intdan sebagainya tidak ditentukan oleh standar (setiap jenis memiliki ukuran minimum dan ada pemesanan yang ketat dalam ukuran, tetapi itu dia).
dmckee --- ex-moderator kitten
1
Saya kira ini adalah latihan yang hebat (dan menantang) bahkan jika tidak ungolfed
John Dvorak
3
Pertanyaan ini dapat menggunakan dokumentasi tentang bagaimana pembulatan ditangani dan ruang uji yang baik.
Peter Taylor
4
Saya yakin itu ada dalam spek, tetapi spek sebenarnya akan menelan biaya beberapa ratus USD. Mungkin ada uraian yang tersedia secara gratis, tetapi IMO yang bertanggung jawab harus ada pada penanya untuk memasukkan perincian semacam itu (atau setidaknya tautan ke situs yang kemungkinan masih ada dalam beberapa tahun) di dalam pertanyaan dan bukan pada penjawab untuk mencari sendiri bahan yang diperlukan untuk mengetahui apa yang sebenarnya diinginkan.
Peter Taylor

Jawaban:

11

C ++, ~ 1500 karakter

Perluas float ke representasi titik tetap 8000-biner, lakukan operasi itu, lalu konversikan kembali.

// 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))));}

Saya terlalu malas untuk menghapus semua spasi dan baris baru untuk mendapatkan jumlah golf yang tepat, tetapi sekitar 1500 karakter.

Keith Randall
sumber