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

Я хочу сделать 32-разрядное целочисленное умножение со знаком без использования 64-разрядного типа данных. Мои входные данные в формате Q1.31 (оба).

input1 = A32 (Ah Al) - higher, lower half's of A32
input2 = B32 (Bh Bl) - higher, lower half's of B32

Результат должен быть в формате Q1.31, оставьте случай переполнения.

Мне нужен код C Пожалуйста, предоставьте объяснение с форматами также.

2 ответа

Решение

Знаковый формат Q1.31 - это полностью дробный формат, способный представлять операнды от -1 до почти +1. Коэффициент масштабирования составляет 231. Это означает, что когда каждый операнд Q1.31 хранится в 32-разрядном целом числе со знаком, мы можем сгенерировать произведение Q1.31, вычислив полное произведение двойной ширины целых чисел со знаком, а затем сдвинув результат вправо на 31 бит. Сдвиг вправо необходим, потому что продукт включает масштабный коэффициент дважды, а сдвиг действует как деление, которое удаляет один экземпляр масштабного коэффициента.

Мы можем вычислить произведение двойной ширины двух 32-разрядных целых чисел, отдельно вычислив старшие и младшие 32 бита полного произведения. Младшие 32 бита вычисляются тривиально как обычное произведение двух входов. Чтобы вычислить старшие 32 бита, нам нужно написать функцию mul32hi(), Чтобы не использовать более широкий тип (т. Е. Тот, который использует более 32 бит) в промежуточных вычислениях, нам нужно разбить исходные операнды на две половины, вычислить их частичные произведения, а затем соответствующим образом сложить эти частичные произведения.

Обратите внимание, что различные процессоры предоставляют аппаратную инструкцию, которая реализует функциональность mul32hi(), В этом случае можно использовать соответствующий встроенный код или немного встроенного ассемблерного кода, если встроенного кода не существует, вместо использования кода эмуляции, представленного здесь.

Это помогает свести проблему сначала к соответствующему умножению без знака, umul32hi()затем извлеките подписанный результат из этого путем определения представления дополнения 2 (что предполагается в следующем коде C):

#include <stdint.h>

/* compute the upper 32 bits of the product of two unsigned 32-bit integers */
uint32_t umul32hi (uint32_t a, uint32_t b)
{
    /* split operands into halves */
    uint32_t al = (uint16_t)a;
    uint32_t ah = a >> 16;
    uint32_t bl = (uint16_t)b;
    uint32_t bh = b >> 16;
    /* compute partial products */
    uint32_t p0 = al * bl;
    uint32_t p1 = al * bh;
    uint32_t p2 = ah * bl;
    uint32_t p3 = ah * bh;
    /* sum partial products */
    uint32_t cy = ((p0 >> 16) + (uint16_t)p1 + (uint16_t)p2) >> 16;
    return p3 + (p2 >> 16) + (p1 >> 16) + cy;
}

/* compute the upper 32 bits of the product of two signed 32-bit integers */
int32_t mul32hi (int32_t a, int32_t b)
{
    return umul32hi (a, b) - ((a < 0) ? b : 0) - ((b < 0) ? a : 0);
}

/* compute the full 64-bit product of two signed 32-bit integers */
void mul32wide (int32_t a, int32_t b, int32_t *rhi, int32_t *rlo)
{
    *rlo = a * b;           /* bits <31:0> of the product a * b */
    *rhi = mul32hi (a, b);  /* bits <63:32> of the product a * b */
}

/* compute the product of two signed Q1.31 fixed-point numbers */    
int32_t mul_q_1_31 (int32_t a, int32_t b)
{
    int32_t hi, lo;
    mul32wide (a, b, &hi, &lo);
    /* Q1.31 is scaled by 2**31, trim out scale factor */
    return (int32_t)(((uint32_t)hi << 1) | ((uint32_t)lo >> 31));
}

Я интерпретировал запрос "оставить случай переполнения", чтобы означать игнорирование переполнения. Как следствие, умножение -1 (0x80000000) на -1 (0x80000000) с mul_q_1_31() вернет -1 (0x80000000).

На следующем сайте предлагается 32-разрядная реализация библиотеки ANSI-C для работы с Q-числами в целом: http://www.ti.com/tool/sprc542

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

Другие вопросы по тегам