Implémenter un nombre à virgule flottante binaire IEEE 754 64 bits par manipulation d'entiers

12

(J'ai marqué la question "C" pour le moment, mais si vous connaissez une autre langue qui prend en charge les syndicats, vous pouvez également l'utiliser.)

Votre tâche consiste à créer les quatre opérateurs mathématiques standard + - * /pour la structure suivante:

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

de sorte que les opérations elles-mêmes ne manipulent ou n'accèdent qu'à la partie entière (donc pas de comparaison avec le double à tout moment pendant l'opération), et le résultat est exactement le même (ou fonctionnellement équivalent, dans le cas de résultats non numériques tels que NaN) comme si l'opération mathématique correspondante avait été appliquée directement à la doubleplace.

Vous pouvez choisir quelle partie entière manipuler, peut-être même en utiliser différentes parmi différents opérateurs. (Vous pouvez également choisir de supprimer le "non signé" de l'un des champs de l'union, même si je ne suis pas sûr que vous souhaitiez le faire.)

Votre score est la somme de la longueur du code en caractères pour chacun des quatre opérateurs. Le score le plus bas l'emporte.

Pour ceux d'entre nous qui ne connaissent pas la spécification IEEE 754, voici un article à ce sujet sur Wikipedia.


Modifications:

03-06 08:47 Ajout de constructeurs à la structure intfloat. Vous êtes autorisé à les utiliser pour les tests, plutôt que de définir manuellement le double / etc.

Joe Z.
la source
1
Oui! Dites-moi que vous avez une solution.
dmckee --- chaton ex-modérateur
4
Hmmm ... il serait peut-être préférable de définir intstructen termes de uint8_8, uint16_tet ainsi de suite, car les tailles absolues de short, intet ainsi de suite ne sont pas définies par la norme (chaque type a une taille minimale et il existe un ordre de taille strict, mais c'est ça).
dmckee --- chaton ex-modérateur
1
Je suppose que c'est une excellente (et difficile) pratique même si elle n'est pas jouée
John Dvorak
3
Cette question pourrait utiliser la documentation sur la façon dont l'arrondi est géré et une bonne suite de tests.
Peter Taylor
4
Je suis sûr que c'est dans la spécification, mais la vraie spécification va coûter quelques centaines de dollars. Il existe probablement des descriptions qui sont disponibles gratuitement, mais l'OMI devrait être chargé de poser ce genre de détails (ou au moins un lien vers un site qui devrait encore exister dans quelques années). la question plutôt que sur les répondeurs d'aller chercher eux-mêmes le matériel nécessaire pour savoir ce que la question veut réellement.
Peter Taylor

Réponses:

11

C ++, ~ 1500 caractères

Développe les flotteurs en une représentation à virgule fixe à 8 000 chiffres binaires, effectue les opérations à ce sujet, puis reconvertit.

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

Je suis trop paresseux pour supprimer tous les espaces et les nouvelles lignes pour obtenir un nombre exact de golf, mais il s'agit d'environ 1 500 caractères.

Keith Randall
la source