Некоторые подводные камни сложения с плавающей запятой в двоичном коде

#cpu-architecture

#cpu-architecture

Вопрос:

У меня есть вопрос о добавлении двух чисел с плавающей запятой в двоичном коде. Кто-нибудь может сказать мне, какой шаг я сделал неправильно?

Ниже приведены два числа с плавающей запятой

 sign  exponent    fraction
1     11101101   10000001101000011010011
0     11101110   01010100001001110010110
  

Первый шаг. выровнять показатель степени (необходимо выровнять по большому)

 1     11101110   11000000110100001101001  (exponet   1 and shift right)
0     11101110   01010100001001110010110
  

Второй шаг. округление (потому что я сдвигаю вправо и игнорирую число = 1/2, а младший значащий бит равен 1, поэтому нам нужно добавить 1)

PS: это правило округления находится на видео https://www.youtube.com/watch?v=wbxSTxhTmrs когда 9:33

Третий шаг. сложение (для дробной части)

   1.01010100001001110010110
- 0.11000000110100001101010 (add 1 for rounding up)
-------------------------------------------
  1.00100110101011001011000
  

Последние

потому 1.00100110101011001011000 что нормализовано, поэтому дробь 00100110101011001011000 равна, а показатель равен 11101110

но ответ в экспоненте 11101101 равен, а дробь равна 00100110101011001011001

есть ли какие-либо ошибки в каждом моем шаге? Спасибо.

Комментарии:

1. Не являются ли оба показателя отрицательными — поэтому второй должен быть выровнен с первым (т. Е. Который является наибольшим / наименьшим отрицательным)?

Ответ №1:

В ваших вычислениях есть несколько ошибок, в основном из-за забывания скрытых битов и выполнения вычислений с неправильным количеством битов.

 A:1     11101101   (1).10000001101000011010011  
B:0     11101110   (1).01010100001001110010110
  

Шаг 1:
Добавить скрытые биты
Выравнивание показателей
Переход к представлению дополнения two

Обратите внимание, что при замене абсолютного значения знака на дополнение 2 вам понадобится один дополнительный бит.

 A=exp(11101110)   -(00.110000001101000011010011)  
 =exp(11101110)     11.001111110010111100101101  
B=exp(11101110)     01.01010100001001110010110
  

Шаг 2: выполните сложение
Поскольку у вас может быть результат> 1 (или (<-2), это должно быть сделано с дополнительным битом со знаком расширения операндов. Вы не должны выполнять округление операнда раньше. Если операнды близки и имеют разный знак, вы можете потерять бит (ы) точности.

 (ca)  11  11111    1 1111  1 11
      111.001111110010111100101101  
      001.01010100001001110010110
      -----------------------------
      000.100100110101011001011001
  

Шаг 3: перенормируйте, чтобы получить число от 1 до 2, отрегулируйте показатель степени и преобразуйте число в знак абсолютного представления.

 m=1.00100110101011001011001 exp=exp-1=11101101
  

Шаг 4: Округлите результат и перенормируйте, если требуется.
(здесь нечего делать).

Итак, m = (1) .00100110101011001011001 exp = 11101101

Это дает ожидаемый результат. И можно перепроверить.

 #include <stdio.h>
int main(){
  union floatint {
    int i;
    float f;
  };
  union floatint a;
  a.i=0xf6C0D0D3;// 1111 0110 1100 0000 1101 0000 1101 0011
  union floatint b;
  b.i=0x772A1396;// 0111 0111 0010 1010 0001 0011 1001 0110
  union floatint c;
  c.f=a.f b.f;
  printf("0x%xn",c.i);
  // gives 0x76935659 = 0111 0110 1001 0011 0101 0110 0101 1001=0 11101101 00100110101011001011001
}