정수 조작을 통해 IEEE 754 64 비트 이진 부동 소수점 수 구현


12

(당분간 "C"라는 질문에 태그를 달았습니다. 그러나 공용체를 지원하는 다른 언어를 알고 있다면 사용할 수도 있습니다.)

당신의 임무는 + - * /다음 구조체에 대한 네 가지 표준 수학 연산자 를 작성하는 것입니다.

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

연산 자체는 항상 정수 부분을 조작하거나 액세스하므로 (연산 중 언제든지 더블과 비교하지 않음) 결과는 정확히 동일합니다 (또는 숫자가 아닌 결과와 같은 경우 기능적으로 동일 NaN) 해당 수학적 연산이 double대신 에 바로 적용된 것처럼 .

조작 할 정수 부분을 선택할 수 있습니다 (아마도 다른 연산자 중 하나를 사용하여). (내가 원하는지 확실하지 않지만 조합의 모든 필드에서 "서명되지 않은"을 제거하도록 선택할 수도 있습니다.)

점수는 네 개의 연산자 각각에 대한 문자 길이의 문자 길이를 합한 것입니다. 최저 점수가 이깁니다.

는 IEEE 754 규격에 익숙하지 않은 우리의 사람들을 위해, 여기 위키 백과에 대한 기사입니다.


편집 :

03-06 08:47 intfloat 구조체에 생성자를 추가했습니다. double / etc를 수동으로 설정하는 대신 테스트에 사용할 수 있습니다.


1
이케 스! 해결책이 있다고 말해주세요.
dmckee --- 전 운영자 고양이 4

4
음 ... 아마도 정의하는 것이 좋습니다 것 intstruct의 관점에서 uint8_8, uint16_t등의 절대 크기로에 short, int등등 표준에 의해 정의되지 않은 (각 유형의 최소 크기를 가지며, 크기에있어서 엄격한 순서가 있지만, 그게 다야).
dmckee --- ex-moderator 고양이

1
나는 이것이 ungolfed 경우에도 훌륭한 (그리고 도전적인) 연습 같아요
John Dvorak

3
이 질문에는 반올림 처리 방법과 좋은 테스트 스위트에 대한 문서가 사용될 수 있습니다.
피터 테일러

4
나는 그것이 사양에 있다고 확신하지만 실제 사양은 수백 달러가 될 것입니다. 무료로 제공되는 설명이있을 수 있지만, IMO는 질문자에게 그러한 종류의 세부 정보 (또는 적어도 몇 년 안에있을 가능성이있는 사이트에 대한 링크)를 포함시켜야합니다. 질문이 실제로 원하는 것을 알기 위해 필요한 자료를 스스로 찾아 가야합니다.
피터 테일러

답변:


11

C ++, ~ 1500 자

부동 소수점을 8000 이진수 고정 소수점 표현으로 확장하고 그에 대한 작업을 수행 한 다음 다시 변환합니다.

// 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.