整数操作によりIEEE 754 64ビットのバイナリ浮動小数点数を実装します


12

(とりあえず質問「C」にタグを付けましたが、共用体をサポートする別の言語を知っている場合は、それも使用できます。)

あなたの仕事は+ - * /、次の構造体の4つの標準的な数学演算子を作成することです。

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

演算自体は整数部分のみを操作またはアクセスするため(演算中にdoubleと比較することはありません)、結果はまったく同じです(またはのような非数値の結果の場合は機能的に同等ですNaN)対応する数学演算がdouble代わりに直接適用されたかのように。

操作する整数部分を選択できます。おそらく、異なる演算子間で異なる部分を使用することもできます。(ユニオンのフィールドのいずれかから「unsigned」を削除することもできますが、それを実行するかどうかはわかりません。)

スコアは、4つの演算子のそれぞれの文字のコードの長さの合計です。最低スコアが勝ちます。

IEEE 754規格に慣れていない私たちの人のために、ここではウィキペディアにそれについての記事です。


編集:

03-06 08:47 intfloat構造体にコンストラクタを追加しました。double /などを手動で設定するのではなく、テストに使用できます。


1
うわぁ!解決策があると教えてください。
dmckee ---元モデレーターの子猫

4
うーん...おそらくそれを定義する方がよいであろうintstructという点でuint8_8uint16_tそのための絶対的な大きさなどにshortintというように規格によって定義されていない(各タイプは、最小のサイズを有し、サイズは厳密な順序付けがあるが、それでおしまい)。
dmckee ---元モデレーター子猫

1
私は、これは、もしゴルフをしなくても素晴らしい(そしてやりがいのある)練習だと思う
ジョン・ドヴォルザーク

3
この質問では、丸めの処理方法のドキュメントと優れたテストスイートを使用できます。
ピーターテイラー

4
私はそれが仕様にあると確信していますが、実際の仕様には数百ドルの費用がかかります。おそらく無料で利用可能な説明がありますが、IMOはその種の詳細(または、少なくとも数年後にまだ存在する可能性が高いサイトへのリンク)を含めるために質問者にあるべきです。質問が実際に何を望んでいるかを知るために必要な資料を自分で探しに行くのではなく、回答者に質問します。
ピーターテイラー

回答:


11

C ++、最大1500文字

浮動小数点数を8000 2進数の固定小数点表現に展開し、その操作を実行してから、元に戻します。

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

正確にゴルフのカウントを取得するためにすべてのスペースと改行を削除するのは面倒ですが、約1500文字です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.