32位有符号整数乘法,不使用64位数据类型

时间:2014-04-03 18:20:03

标签: c integer bit-manipulation multiplication signed

我想在不使用64位数据类型的情况下进行32位有符号整数乘法。我的输入是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 个答案:

答案 0 :(得分:8)

签名的Q1.31格式是一种完全分数格式,能够表示-1和几乎+1之间的操作数。比例因子是2 31 。这意味着当每个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));
}

我将请求解释为&#34;离开溢出案例&#34;意味着忽略溢出。因此,将-1(0x80000000)乘以-1(0x80000000)与mul_q_1_31()将返回-1(0x80000000)。

答案 1 :(得分:0)

以下网站旨在提供一个ANSI-C库的32位实现,以便通常使用Q值进行操作:http://www.ti.com/tool/sprc542

我没有尝试过这个,也无法保证它会为您做什么或不做什么,但在该网站上有一个链接可以请求源代码。