LINUX.ORG.RU

Битовый мультипликатор

 


0

1

Сап, ЛОР.

Как обычно занимаюсь извращенствами. Понадобилось расковырять битовый мультипликатор.

Значица пара вопросов по статье:
1.

 p0[7:0] = a[0] × b[7:0] = {8{a[0]}} & b[7:0]
 p1[7:0] = a[1] × b[7:0] = {8{a[1]}} & b[7:0]
 p2[7:0] = a[2] × b[7:0] = {8{a[2]}} & b[7:0]
Ну тут вроде бы все понятно:
p0 = 
   BYTE(a[0], a[0], a[0], a[0], a[0], a[0], a[0], a[0]) &
   BYTE(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7])
etc.
И дальше вроде все понятно для беззнаковой:

In other words, P[15:0] is produced by summing p0, p1 << 1, p2 << 2, and so forth, to produce our final unsigned 16-bit product.

Что дает (если я правильно понял && нафиг 16 бит, даешь 8)

R[0] = p0[0]
R[1] = p1[0] | p0[1]
R[2] = p2[0] | p1[1] | p0[2]
R[3] = p3[0] | p2[1] | p1[2] | p0[3]
R[4] = p4[0] | p3[1] | p2[2] | p1[3] | p0[4]
R[5] = p5[0] | p4[1] | p3[2] | p2[3] | p1[4] | p0[5]
R[6] = p6[0] | p5[1] | p4[2] | p3[4] | p2[4] | p1[5] | p0[6]
R[7] = p7[0] | p6[1] | p5[2] | p4[5] | p3[4] | p2[5] | p1[6] | p0[7]

Теперь, вопрос 2.

Что за байда там со знаковым?

If b had been a signed integer instead of an unsigned integer, then the partial products would need to have been sign-extended up to the width of the product before summing. If a had been a signed integer, then partial product p7 would need to be subtracted from the final sum, rather than added to it.

Окей, условимся, что у нас оба операнда знаковые. Тогда 1) the partial products would need to have been sign-extended up to the width of the product — Ммм.. Теперь должно быть p0:p15 или что? Мне нужен 8битный знаковый результат. 2) then partial product p7 would need to be subtracted from the final sum из какой final sum? Я тут дофига сумм вижу.

Вопрос 3. кусок таблицы:

   1  
 -----
P[15] 
Какого лешего у них всегда бит знака зашит на отрицательное число?

Вопрос 4
И, как я понимаю, получается следующее:

R[0] = p0[0]
R[1] = p1[0] | p0[1]
R[2] = p2[0] | p1[1] | p0[2]
R[3] = p3[0] | p2[1] | p1[2] | p0[3]
R[4] = p4[0] | p3[1] | p2[2] | p1[3] | p0[4]
R[5] = p5[0] | p4[1] | p3[2] | p2[3] | p1[4] | p0[5]
R[6] = p6[0] | p5[1] | p4[2] | p3[4] | p2[4] | p1[5] | p0[6]
R[7] = ???
Нельзя знаковый бит просто посчитать как a[7] ^ b[7]?

★★

Сишечка не работает

#include <stdio.h>
#include <stdint.h>

#define BYTE(a7, a6, a5, a4, a3, a2, a1, a0) ((a7 << 7) | (a6 << 6) | (a5 << 5) | (a4 << 4) | (a3 << 3) | (a2 << 2) | (a1 << 1) | (a0))
#define BIT(a, num) ( ((a) & ( 0x1 << (num) )) != 0 )

int main(void)
{
   typedef union 
   {
      uint8_t u;
      int8_t  i;
   } conv;

    conv aR;
    conv bR;

   int8_t a = 8;
   int8_t b = -21;
   
    aR.i = a;
    bR.i = b;
   
   // -168

   uint8_t p0 = BYTE(BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0), BIT(aR.u, 0)) & bR.u;
   uint8_t p1 = BYTE(BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1), BIT(aR.u, 1)) & bR.u;
   uint8_t p2 = BYTE(BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2), BIT(aR.u, 2)) & bR.u;
   uint8_t p3 = BYTE(BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3), BIT(aR.u, 3)) & bR.u;
   uint8_t p4 = BYTE(BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4), BIT(aR.u, 4)) & bR.u;
   uint8_t p5 = BYTE(BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5), BIT(aR.u, 5)) & bR.u;
   uint8_t p6 = BYTE(BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6), BIT(aR.u, 6)) & bR.u;
   uint8_t p7 = BYTE(BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7), BIT(aR.u, 7)) & bR.u;
   
   uint8_t r = BYTE(BIT(aR.u,7) ^ BIT(bR.u,7),
                    BIT(p6,0) | BIT(p5,1) | BIT(p4,2) | BIT(p3,4) | BIT(p2,4) | BIT(p1,5) | BIT(p0,6),
                    BIT(p5,0) | BIT(p4,1) | BIT(p3,2) | BIT(p2,3) | BIT(p1,4) | BIT(p0,5),
                    BIT(p4,0) | BIT(p3,1) | BIT(p2,2) | BIT(p1,3) | BIT(p0,4),
                    BIT(p3,0) | BIT(p2,1) | BIT(p1,2) | BIT(p0,3),
                    BIT(p2,0) | BIT(p1,1) | BIT(p0,2),
                    BIT(p1,0) | BIT(p0,1),
                    BIT(p0,0));
                    
   
   conv cR;
   
   cR.u = r;
   
   printf("%d\n", cR.i); // -127
}
sambist ★★
() автор топика
Последнее исправление: sambist (всего исправлений: 1)

Ну и что там такого сложного?

#include <stdio.h>

int
mult(int a, int b)
{
        int i, c = 0;

        for (i = 0; i < 8; i++)
                if ((a >> i) & 1)
                        c += b << i;

        return c;
}

int
main()
{
        int a = 11;
        int b = 14;

        printf("%d * %d = %d\n", a, b, mult(a, b));

        return 0;
}
beastie ★★★★★
()
Ответ на: комментарий от beastie

Мне нужно побитовое вычисление.

sambist ★★
() автор топика
Ответ на: комментарий от sambist

Какого лешего у них всегда бит знака зашит на отрицательное число?

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

BIT(p6,0) | BIT(p5,1)

Откуда битовое ИЛИ? Как оно переносы считать будет? Там суммирование. Т.е. для суммы однобитовых чисел это вроде такого (r — результат, c — перенос):

r[0] = a[0] ^ b[0];
с[0] = a[0] & b[0];
r[1] = c[0];
Рекомендую для начала поумножать числа совсем малой разрядности на бумажке и осознать процесс, так сказать (и можно поискать материалы каких-нибудь университетских лекций по теме).

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Т.е. для суммы однобитовых чисел это вроде такого

Я знаю что такое сумматор.

Откуда битовое ИЛИ? Как оно переносы считать будет?

А как они предполагают запихнуть в один бит сумму 7-8 операндов?

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

Поясни, пожалуйста.

sambist ★★
() автор топика
Последнее исправление: sambist (всего исправлений: 1)
Ответ на: комментарий от sambist

А как они предполагают запихнуть в один бит сумму 7-8 операндов?

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

Поясни, пожалуйста.

Я такого хака не помню, но в тексте:

The sequences of one complemented bit followed by noncomplemented bits are implementing a two's complement trick to avoid sign extension.
Смутно догадываюсь, что те единицы должны переносами обнулиться для положительного результата и остаться для отрицательного, но это надо смотреть детальнее на отдельные случаи знаков операндов.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Тут вроде описан способ без таких заморочек с инверсиями для знаковых чисел. А это может быть патентом на «хитрый способ».

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.