Реалізуйте 64-розрядний двійковий номер з плаваючою комою IEEE 754 через цілочисельну маніпуляцію


12

(Я поки що позначив питання "С", але якщо ви знаєте іншу мову, яка підтримує спілки, ви також можете використовувати це.)

Ваше завдання - побудувати чотири стандартних математичних операторів + - * /для наступної структури:

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. Ви можете використовувати їх для тестування, а не вручну встановлювати подвійний / і т.д.


1
Yikes! Скажіть, у вас є рішення.
dmckee --- кошеня колишнього модератора

4
Хм ... можливо , було б краще , щоб визначити intstructточки зору uint8_8, uint16_tі так далі , як абсолютних розмірів short, intі так далі не визначені стандартом (кожен тип має мінімальний розмір і існує строгий порядок в розмірах, але Це воно).
dmckee --- кошеня колишнього модератора

1
Я здогадуюсь, що це чудова (і складна) практика, навіть якщо без волі
Джон Дворак

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 символів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.