Некоторые подводные камни о сложении с плавающей точкой в ​​двоичном - PullRequest
0 голосов
/ 14 апреля 2019

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

Ниже приведены два плавающих числа

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 Ответ

2 голосов
/ 16 апреля 2019

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

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

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

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

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

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

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

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

m=1.00100110101011001011001 exp=exp-1=11101101

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

So 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%x\n",c.i);
  // gives 0x76935659 = 0111 0110 1001 0011 0101 0110 0101 1001=0 11101101 00100110101011001011001
}
...