Implementar um número de ponto flutuante binário IEEE 754 de 64 bits através da manipulação de números inteiros

12

(Eu marquei a pergunta "C" por enquanto, mas se você souber de outro idioma que suporte sindicatos, também poderá usá-lo.)

Sua tarefa é criar os quatro operadores matemáticos padrão + - * /para a seguinte estrutura:

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 modo que as próprias operações apenas manipulem ou acessem a parte inteira (portanto, não há comparação com o dobro a qualquer momento durante a operação), e o resultado é exatamente o mesmo (ou funcionalmente equivalente, no caso de resultados não numéricos como NaN) como se a operação matemática correspondente tivesse sido aplicada diretamente ao doubleinvés.

Você pode escolher qual parte inteira manipular, talvez até usando diferentes entre operadores diferentes. (Você também pode optar por remover o "não assinado" de qualquer um dos campos da união, embora não tenha certeza se deseja fazer isso.)

Sua pontuação é a soma do comprimento do código em caracteres para cada um dos quatro operadores. Menor pontuação ganha.

Para aqueles que não estão familiarizados com a especificação IEEE 754, aqui está um artigo sobre ela na Wikipedia.


Editar% s:

03-06 08:47 Adicionados construtores à estrutura intfloat. Você pode usá-los para testes, em vez de definir manualmente o dobro / etc.

Joe Z.
fonte
1
Caramba! Diga-me que você tem uma solução.
dmckee --- ex-moderador gatinho
4
Hmmm ... talvez seja melhor definir intstructem termos de uint8_8, uint16_te assim por diante, como os tamanhos absolutos de short, inte assim por diante, não são definidos pelo padrão (cada tipo tem um tamanho mínimo e há uma ordem estrita de tamanho, mas é isso aí).
dmckee --- gatinho ex-moderador 01/03
1
Eu acho que esta é uma grande (e desafiar) a prática, mesmo se ungolfed
John Dvorak
3
Esta pergunta pode usar a documentação de como o arredondamento é tratado e um bom conjunto de testes.
Peter Taylor
4
Tenho certeza de que está na especificação, mas a especificação real vai custar algumas centenas de dólares. Provavelmente, há descrições disponíveis gratuitamente, mas, na OMI, o ônus deve estar no questionador para incluir esse tipo de detalhes (ou pelo menos um link para um site que provavelmente ainda estará disponível em alguns anos) dentro de alguns anos. a pergunta, e não nos respondentes, procurando os materiais necessários para saber o que a pergunta realmente deseja.
Peter Taylor

Respostas:

11

C ++, ~ 1500 caracteres

Expande os flutuadores em uma representação de ponto fixo de 8000 dígitos binários, realiza as operações e depois converte novamente.

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

Estou com preguiça de remover todos os espaços e novas linhas para obter uma contagem exata do golfe, mas são cerca de 1500 caracteres.

Keith Randall
fonte