Алгоритм сложения с плавающей точкой
Я пытаюсь написать двоичный 8-битный алгоритм сложения с плавающей запятой для микроконтроллера picoblaze (1 знаковый бит, 4 экспонентных бита и 3 мантиссовых бита)
Я заставил его работать с положительными числами, но я не могу понять, как это сделать, когда есть и отрицательные числа.
Моя основная проблема - установить знаковый бит результата, кто-то может объяснить, как правильно его установить?
Моя идея состояла в том, чтобы проверить знак обоих чисел; затем, если они оба положительные, установите знак в 0, если они оба отрицательные, установите знак в 1 и используйте те же методы, что и раньше для сложения, и если один отрицательный, а другой положительный, сравните числа и используйте немного больше, но я не уверен, как сравнить два числа, и код становится немного загроможденным, есть ли лучший способ сделать это?
3 ответа
Вам не нужно заботиться о знаке операндов, если вы превратите их в дополнение к двум.
сравните показатели и выровняйте соответственно мантиссу числа с наименьшим показателем, добавив скрытый бит
превратить числа в дополнение к двум. Для этого требуется дополнительный бит слева от мантиссы, чтобы учесть знаковый бит, и еще один бит, чтобы справиться с дополнительными переполнениями. В результате отрицательные числа будут представлены числом $gt; 2, это дополнение их абсолютного значения к 2^3. Обратите внимание, что два старших значащих бита всегда равны.
Выполните сложение.
обнаружить переполнения. Если два старших значащих бита результата не равны, происходит переполнение. В этом случае вы должны сделать арифметическое смещение вправо результата и увеличить экспоненту.
обнаружить недолеты. Если три цифры слева от точки равны, это означает, что имеется недостаток. В этом случае выполните сдвиг влево до тех пор, пока эти три цифры не станут разными или все биты справа от точки не будут равны нулю, и отрегулируйте соответственно показатель степени.
округление
вернитесь от дополнения до двух к знако-абсолютному значению и определите знак результата из его MSB.
Пример:
A=1.1 B=-1.1 2^-1
1. alignment. Numbers are extended to 6 bits right of point.
A=+1.100000
B=-0.110000
2. two's complement
A=001.100000
B=2C(000.110000)=111.010000
3 addition
A 001.100000
+B 111.010000
= 000.110000
4 overflows none
5 underflows: shift result left 1 step and decrement exponent
001.100000 2^-1
6 rounding
001.100 2^-1
6 back to sign absolute value
+ (1.)100 2^-1
Еще один пример с отрицательным результатом
A=1.01 B=-1.1
1. alignment. Numbers are extended to 6 bits right of point.
A=+1.010000
B=-1.100000
2. two's complement
A=001.010000
B=2C(001.100000)=110.100000
3 addition
A 001.010000
+B 110.100000
= 111.110000
4 overflows none (none overflow can happen if signs are different)
5 underflows: shift result left 2 steps and decrement exponent by 2
111.000000 2^-2
6 rounding
111.000 2^-2 (<0)
6 back to sign absolute value
-(1.)000 2^-2
В общем (игнорируя такие вещи, как NaN), для A = B + C
:
если
C
имеет большую величину, чемB
, поменять местамиB
а такжеC
чтобы ты знал чтоB
должен иметь "большую или равную" величину. Примечание: величина игнорирует знаковые биты (например, -6 имеет большую величину, чем +4, потому что 6 > 4).если
B
а такжеC
есть разные признаки, отрицаниеC
и делайsubtract_internal
; еще сделатьadd_internal
,за
subtract_internal
, игнорировать знак биты, вычесть величины (не забывая, чтоB
должен иметь "большую или равную" величину), затем установить знакA
равно знаку либоB
или жеC
(у них все равно будет одинаковый знак).за
add_internal
, проигнорируйте биты знака, добавьте величины, затем установите знакA
равно знаку либоB
или жеC
(у них все равно будет одинаковый знак).
Кроме того, в целом (игнорируя такие вещи, как NaN), для A = B - C
:
если
C
имеет большую величину, чемB
, поменять местамиB
а такжеC
и отрицать их обоих (например,A - C == (-C) - (-A)
) чтобы ты знал чтоB
должен иметь "большую или равную" величину.если
B
а такжеC
есть разные признаки, отрицаниеC
и делайadd_internal
; еще сделатьsubtract_internal
,
Тебе повезло. Предполагая, что вы используете представление, подобное IEEE754 (т. Е. Экспонента хранится с соответствующим смещением), вы можете просто сравнить строки битов лексикографически после небольшого массажа. Обратите внимание, что это предполагает, что вы уже правильно обработали значения NaN, поскольку значения NaN должны просто распространяться через ваш сумматор.
Хитрость заключается в следующем:
- Вы игнорируете знак -0 (то есть, если у вас есть 10000000, то рассматривайте его как 00000000.)
- Если бит знака равен 1, тогда перевернуть все биты (включая бит знака)
- Если бит знака равен 0, переверните бит знака (оставьте остальные так же)
Теперь вы можете сравнить эти две битовые строки лексикографически, та, которая находится раньше в порядке словаря, меньше. Возможно, вам придется тщательно организовать, как вы обрабатываете -0
, но я подозреваю, что это не очень большая проблема для вас.
Фактически, это именно та причина, по которой показатели хранятся с предвзятостью, так что вы можете сравнивать числа с плавающей запятой, просто обрабатывая их как числа без знака, после выполнения трюка с переворотом, о котором я упоминал выше.