Реализация 64-разрядного двоичного числа IEEE 754 с помощью целочисленных манипуляций

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вместо.

Вы можете выбрать, какой целочисленной частью манипулировать, возможно, даже используя разные операторы. (Вы также можете удалить «unsigned» из любого поля объединения, хотя я не уверен, что вы захотите это сделать.)

Ваша оценка - это сумма длины кода в символах для каждого из четырех операторов. Самый низкий балл побеждает.

Для тех из нас, кто не знаком со спецификацией IEEE 754, вот статья об этом в Википедии.


Редактирование:

03-06 08:47 Добавлены конструкторы в структуру intfloat. Вы можете использовать их для тестирования, а не вручную устанавливать двойной / и т. Д.

Джо З.
источник
1
Хлоп! Скажи мне, что у тебя есть решение.
dmckee --- котенок экс-модератора
4
Хм ... возможно , было бы лучше , чтобы определить intstructточки зрения uint8_8, uint16_tи так далее , как абсолютных размеров short, intи так далее не определены стандартом (каждый тип имеет минимальный размер и существует строгий порядок в размерах, но Это оно).
dmckee --- котенок экс-модератора
1
Я предполагаю, что это отличная (и сложная) практика, даже если она не одурачена
Джон Дворжак
3
Этот вопрос может использовать документацию о том, как обрабатывается округление, и хороший набор тестов.
Питер Тейлор
4
Я уверен, что это в спецификации, но реальная спецификация будет стоить несколько сотен долларов. Вероятно, есть описания, которые можно получить бесплатно, но ИМО должна нести ответственность за вопрос, чтобы включить такие подробности (или, по крайней мере, ссылку на сайт, который, вероятно, будет еще через пару лет) в пределах вопрос, а не на тех, кто отвечает, чтобы начать искать необходимые материалы, чтобы узнать, чего на самом деле хочет этот вопрос.
Питер Тейлор

Ответы:

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

Кит Рэндалл
источник