Умножение двух 32-битных чисел без использования 64-битного целого

Мы делаем 32-битное * 32-битное умножение, используя следующий алгоритм.

Допустим, мы хотим умножить a (32 бита) на b (32 бита), оба со знаком,

a = ah * 2^16 + al [ah — старшие 16 бит, al — младшие 16 бит]

b = bh * 2^16 + bl [bh — старшие 16 бит, bl — младшие 16 бит]

Мы эффективно делаем

Результат = (al * bl) + (((ah * bl) + (al * bh)) * 2^16) + ((ah * bh) * 2 ^ 32) ~~~


Мой вопрос,

Есть ли лучший способ сделать это?


person Alphaneo    schedule 31.08.2009    source источник
comment
На каком процессоре? Например, в x86, когда вы умножаете два 32-битных числа, старшие 32 бита результата сохраняются в EDX, а младшие биты — в EAX. Аналогично с 16 бит.   -  person David    schedule 31.08.2009
comment
Нам нужно спроектировать это для 32-битного процессора, а процессор может быть любым, например ARM, MIPS или любым другим, в зависимости от заказчика ...   -  person Alphaneo    schedule 31.08.2009
comment
Используйте int64_t, и пусть генератор кода компилятора позаботится о том, как его реализовать. Вручную делать что-то нужно только в том случае, если кодеген плохой, что маловероятно для такого простого случая.   -  person Stephen Canon    schedule 18.11.2009


Ответы (4)


В любом обычном компиляторе эмуляция 64-битных целых чисел на 32-битной платформе будет примерно такой же эффективной, как и самостоятельное выполнение многошаговой математики. Но это будет гораздо надежнее правильно.

При выполнении простых арифметических операций со значениями, достаточно большими для переполнения, даже самая хорошо настроенная математическая библиотека, которую я видел, просто использует int64.

person Alan    schedule 31.08.2009

Погуглите "умножение Карацубы".

OIh, а в своем коде измените константу 2^15 (она появляется дважды) на 2^16.

person Robert L    schedule 04.09.2009

Ответ заключается в том, что нет лучшего способа сделать что-то, кроме использования смещения битов и масок вместо 2 ^ n. А именно:

a * 2^n <=> a << n

Во-вторых, ваши целые числа подписаны или не подписаны? Если они подписаны, это меняет дело.

В-третьих, я не уверен, что ваши 2 ^ 15 верны. Если он по крайней мере без знака, вы хотите сдвинуть биты на 16, а не на 15.

Наконец, вы должны остерегаться целочисленного переполнения в int младшего разряда. Если вы складываете числа в младшем разряде int, которые переполняют его емкость, вам необходимо правильно увеличить старший разряд int.

person cletus    schedule 31.08.2009
comment
+1 Я думаю, 2 ^ 15 - это ошибка. Печально, что это лучший метод~~~ - person Alphaneo; 31.08.2009

Вам нужно знать (указать), как должно храниться 64-битное значение - предположительно, это пара 32-битных значений, возможно, два элемента массива или два элемента структуры. Вам также необходимо учитывать, как информация о знаке будет храниться в результате.

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

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

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

person Jonathan Leffler    schedule 31.08.2009