Implement an IEEE 754 64-bit binary floating point number through integer manipulation (I've tagged the question "C" for the time being, but if you're aware of another language that supports unions, you can also use that.)

Your task is to build the four standard mathematical operators + - * / for the following struct:

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


such that the operations themselves only ever manipulate or access the integer part (so no comparing with the double anytime during the operation either), and the result is exactly the same (or functionally equivalent, in the case of non-numeric results such as NaN) as if the corresponding mathematical operation had been applied straight to the double instead.

You may choose which integer part to manipulate, perhaps even using different ones among different operators. (You can also choose to remove the "unsigned" from any of the fields in the union, although I'm not sure whether you'd want to do that.)

Your score is the sum of the length of code in characters for each of the four operators. Lowest score wins.

For those of us unfamiliar with the IEEE 754 specification, here is an article about it on Wikipedia.



Edits:

03-06 08:47 Added constructors to the intfloat struct. You are allowed to use them for testing, rather than manually setting the double / etc.
C++, ~1500 chars

Expands the floats into an 8000-binary-digit fixed-point representation, does the operations on that, then converts back.

// 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&lt;&lt;1&gt;&gt;53,m=x.k&lt;&lt;12&gt;&gt;12;
  E r={e==2047&amp;&amp;m!=0,e==2047,e+m==0,x.k&gt;&gt;63};
  if(e)m+=1L&lt;&lt;52;else e++;
  for(i=0;i&lt;53;i++)r.d[2925+e+i]=m&gt;&gt;i&amp;1;
  return r;
}
E A(E x,E y){
  int i,c,v;
  if(x.s&gt;y.s)return A(y,x);
  E r={x.n|y.n|x.i&amp;y.i&amp;(x.s^y.s),x.i|y.i,x.z&amp;y.z,x.i&amp;x.s|y.i&amp;y.s|~x.i&amp;~y.i&amp;x.s&amp;y.s};V;
  if(x.s^y.s){
    c=0;
    r.z=1;
    for(i=0;i&lt;N;i++){
      v=x.d[i]-y.d[i]-c;
      r.d[i]=v&amp;1;c=v&lt;0;
      r.z&amp;=~v&amp;1;
    }
    if(c){x.s=1;y.s=0;r=A(y,x);r.s=1;}
  }else{
    c=0;
    for(i=0;i&lt;N;i++){
      v=x.d[i]+y.d[i]+c;
      r.d[i]=v&amp;1;c=v&gt;1;
    }
  }
  return r;
}
E M(E x, E y){
  int i;
  E r={x.n|y.n|x.i&amp;y.z|x.z&amp;y.i,x.i|y.i,x.z|y.z,x.s^y.s};V;
  E s={0,0,1};
  for(i=0;i&lt;6000;i++)y.d[i]=y.d[i+2000];
  for(i=0;i&lt;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 &lt;- 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&gt;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&lt;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&gt;=0;i--)if(x.d[i])break;
  for(j=0;j&lt;N;j++)if(x.d[j])break;
  if(i&gt;0&amp;x.d[i-53]&amp;(j&lt;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&lt;2978){e=0;for(j=0;j&lt;52;j++)m+=x.d[j+2926]&lt;&lt;j;}
  else if(i&lt;5024){e=i-2977;for(j=0;j&lt;52;j++)m+=x.d[i+j-52]&lt;&lt;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&lt;&lt;63|e&lt;&lt;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&lt;&lt;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))));}


I'm too lazy to remove all the spaces and newlines to get an exact golfed count, but it is about 1500 characters.