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

jos*_*eph 1 c signed integer bit-manipulation multiplication

我想在不使用64位数据类型的情况下进行32位有符号整数乘法.我的输入是Q1.31(两种)格式.

input1 = A32 (Ah Al) - higher, lower half's of A32
input2 = B32 (Bh Bl) - higher, lower half's of B32
Run Code Online (Sandbox Code Playgroud)

结果应为Q1.31格式,保留溢出情况.

我需要C代码.请提供格式说明.

nju*_*ffa 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));
}
Run Code Online (Sandbox Code Playgroud)

我将请求解释为"保留溢出情况"意味着忽略溢出.因此,将-1(0x80000000)乘以-1(0x80000000)mul_q_1_31()将返回-1(0x80000000).

  • 您的回答救了我!/ sf / ask / 2016513901 /#28827013我希望我能再次支持你。您如何得出公式“ hi-=((x &lt;0)?y:0)+((y &lt;0)?x:0)”? (2认同)
  • @Zboson:它直接来自二进制补码表示.例如,32位整数-n和-m表示为无符号数`x = 2**32-n`,`y = 2**32-m`.如果你乘以'x*y = 2**64-2*32*n - 2**32*m + n*m`.中间术语表示对产品上半部分的必要更正.使用-1*-1来完成一个简单的例子应该证明是非常有益的. (2认同)