Implementieren Sie eine 64-Bit-Gleitkommazahl nach IEEE 754 durch ganzzahlige Manipulation

12

(Ich habe die Frage vorerst mit "C" markiert, aber wenn Sie eine andere Sprache kennen, die Gewerkschaften unterstützt, können Sie diese auch verwenden.)

Ihre Aufgabe ist es, die vier mathematischen Standardoperatoren + - * /für die folgende Struktur zu erstellen :

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

so, dass die Operationen selbst immer nur den ganzzahligen Teil manipulieren oder darauf zugreifen (so dass auch während der Operation kein Vergleich mit dem double möglich ist) und das Ergebnis genau dasselbe ist (oder funktional äquivalent bei nicht numerischen Ergebnissen wie NaN). als ob die entsprechende mathematische Operation direkt auf die angewendet worden wäre double.

Sie können auswählen, welcher ganzzahlige Teil bearbeitet werden soll, möglicherweise sogar unter Verwendung verschiedener Operatoren. (Sie können auch das "unsignierte" aus einem der Felder in der Union entfernen, obwohl ich nicht sicher bin, ob Sie das tun möchten.)

Ihre Punktzahl ist die Summe der Länge des Codes in Zeichen für jeden der vier Operatoren. Die niedrigste Punktzahl gewinnt.

Für diejenigen von uns, die mit der IEEE 754-Spezifikation nicht vertraut sind, ist hier ein Artikel darüber auf Wikipedia.


Bearbeitungen:

03-06 08:47 Konstruktoren zur Intfloat-Struktur hinzugefügt. Sie dürfen sie zum Testen verwenden, anstatt das double / etc. manuell einzustellen.

Joe Z.
quelle
1
Huch! Sag mir, dass du eine Lösung hast.
dmckee --- Ex-Moderator Kätzchen
4
Hmmm ... vielleicht wäre es besser, zu definieren , intstructin Bezug auf die uint8_8, uint16_tund so weiter , wie die absoluten Größen short, intund so weiter sind nicht durch den Standard definiert (jede Art hat eine Mindestgröße und es gibt eine strenge Ordnung in der Größe, aber das ist es).
dmckee --- Ex-Moderator Kätzchen
1
Ich denke, dass dies eine großartige (und herausfordernde) Übung ist, auch wenn sie nicht Golf spielt
John Dvorak,
3
Diese Frage könnte eine Dokumentation zum Umgang mit Rundungen und eine gute Testsuite enthalten.
Peter Taylor
4
Ich bin sicher, es ist in der Spezifikation, aber die echte Spezifikation wird ein paar hundert USD kosten. Es gibt wahrscheinlich Beschreibungen, die kostenlos zur Verfügung stehen, aber IMO sollte der Fragesteller diese Art von Details (oder zumindest einen Link zu einer Site, die wahrscheinlich in ein paar Jahren noch verfügbar sein wird) angeben die Frage, anstatt auf die Antwortenden zu gehen, um selbst nach den notwendigen Materialien zu suchen, um zu wissen, was die Frage tatsächlich will.
Peter Taylor

Antworten:

11

C ++, ~ 1500 Zeichen

Erweitert die Gleitkommazahlen zu einer 8000-Binärziffern-Festkommadarstellung, führt die entsprechenden Operationen aus und konvertiert sie anschließend zurück.

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

Ich bin zu faul, um alle Leerzeichen und Zeilenumbrüche zu entfernen, um eine genaue Golfzahl zu erhalten, aber es sind ungefähr 1500 Zeichen.

Keith Randall
quelle