Это работает точно так же, как математика в начальной школе, только намного проще, поскольку вам нужно только знать свою таблицу умножения единиц и помнить, что все, что умножено на ноль, равно нулю.
Возьму 1,5 * 3,0 с одинарной точностью.
0x3FC00000 1.5
0x40400000 3.0
0x40900000 1.5 * 3.0 = 4.5
расширять
0x3FC0
0011111111000000
0 01111111 1000000
0x4040
0100000001000000
0 10000000 1000000
поэтому в двоичном формате мы умножаем 1,1 на 1,1, как в начальной школе, только проще
11
* 11
======
11
+11
======
1001
тогда у нас было одно (не) десятичное (двоичное?) место от одного операнда и одно от другого, поэтому наша точка идет здесь двумя справа.
10.01
но нам нужно нормализовать это
1.001 with an increase in the exponent.
экспоненты
01111111 2^0
10000000 2^1
Как и в начальной школе, мы складываем показатели 2 ^ (0 + 1) = 2 ^ 1. Затем у нас есть нормализация добавления еще одного сдвига на единицу к показателю 2 ^ (1 + 1) = 2 ^ 2.
0 10000001 001000....
010000001001000....
0100 0000 1001 000....
дает результат, соответствующий тому, что произвел компьютер
0x40900000
В этом нет никакого волшебства.
Аппаратное умножение ничем не отличается от школьного, просто оно проще. Посмотрите на эти отдельные биты: a - это бит 0 или 1, b - это бит 0 или 1 и так далее.
ab
* cd
======
ef
gh
======
jklm
если d равно 0, то оба ef равны нулю, если d равно 1, то ef = ab, поэтому уравнения до сих пор имеют вид
e = a & d
f = b & d
g = a & c
h = b & c
все, что связано с 0, равно 0, все, что связано с 1, является само по себе.
затем делаем сложение
nop0
ef
+ gh
======
jklm
Я жестко жульничал здесь, сложение двух битов, выполнение и результат, таблица истинности
xy cr
00 00
01 01
10 01
11 10
результат - x или y, выполнение - x и y
m = f
p = 0 because f+0 cant have a carry bit.
l = e xor h
o = e & h
k = o xor g
n = o & g
j = n
замены и, надеюсь, я не допущу (больше) ошибок
m = f = b & d
l = e xor h = (a&d) xor (b&c)
k = o xor g = (e & h) xor (a&c) = ((a&d) & (b&c)) xor (a&c)
j = n = o & g = (e & h) & (a&c) = ((a&d) & (b&c)) & (a&c)
так что там, вероятно, есть некоторые оптимизации, но если вам нужно / вы хотите вычислить двухбитный множитель на два бита за один такт, есть ваши уравнения ввода и вывода. Сильный обман, потому что делайте 3x3, и сложение становится намного хуже. Работайте до 8 бит, умноженных на 8, или до 32 бит, умноженных на 32. Переносимые биты начинают рассылать спам поверх других переносимых бит, математика - это не то, что вы хотите пытаться вручную. Это возможно, но создает огромное количество логики, множители одиночных тактовых импульсов могут потреблять значительный процент вашего чипа, есть уловки, такие как ... использование более одного тактового сигнала и канала, создающего иллюзию одного тактового сигнала ...
Вернемся к прежним временам, когда мы просто не могли сжечь столько логики, мы бы сказали обнулить аккумулятор, затем взять биты ab И оба с d сдвигом влево до нуля и добавить к аккумулятору. Возьмите биты ab И оба с помощью c сдвиньте влево и сложите в аккумулятор ... Точно так же, как мы делаем умножение бумаги и карандаша. Если у вас 8 бит * 8 бит, то для умножения требуется не менее 8 тактов. Потом нормализация и тд и тп ...
В любом случае, вы можете видеть, что умножение в логике ничем не отличается от того, что мы узнали в начальной школе, только проще, поскольку мы умножаем только на 0 и 1. Вы либо пишете нули, либо копируете операнд как есть.
Короткий ответ, вы, вероятно, упустили тот момент, что есть скрытый / подразумеваемый бит, нет причин тратить немного на формат, который можно использовать для точности. IEEE 754 - это 1 мантисса в некоторой степени при нормализации.
двойная же история, подразумевается 1. мантисса:
0x3FF8000000000000 1.5
0x4008000000000000 3.0
0x4012000000000000 4.5
0011111111111000
0100000000001000
0100000000010010
0 01111111111 1000 1.1000...
0 10000000000 1000 1.1000...
0 10000000001 0010 1.0010....
Другой способ взглянуть на это без десятичных точек (или с их подразумеваемыми, и они не десятичные точки, а двоичные точки, я думаю).
Сверху 1.10000 ... * 1.10000 - это 0xC00000 * 0xC00000 = 0x900000000000, 48 бит. Мы убираем половину битов до 0x900000, потому что у нас есть 1 и 47 бит мантиссы, но есть только место для 23, поэтому мы отсекаем 24 младших бита, будь то нули или любое другое число. Не случайно получается, что мы оставляем половину битов и отбрасываем половину битов. Теперь, если бы это было 1.000 ... * 1.000 ... у нас было бы 0x400000000000 1 и 46 бит, разделенных на 23, а не на 24 бита. Вы можете провести несколько экспериментов с меньшим количеством битов, но помните, что в отличие от любых двух N-битных чисел, умноженных друг на друга, у нас есть подразумеваемая / фиксированная 1 вверху. Таким образом, (1 * 2 ^ 23) * (1 * 2 ^ 23) = (1 * 1) * (2 ^ (23 + 23) = 1 * 2 ^ 46 всегда присутствует, когда мантиссы умножаются (для нормального, не -нуль, числа).
Существуют и другие форматы с плавающей запятой, которые по большей части работают одинаково, они могут быть проще для отрицательных чисел и т. Д. (Поищите, например, формат ti DSP, если вы можете его найти, созданный для скорости, а не для угловых случаев).
person
old_timer
schedule
19.02.2018