如何在不使用long long的情况下将64位无符号整数乘以C上的32位无符号整数?

时间:2018-04-04 00:47:14

标签: c arrays 64-bit

如何在不使用long long的情况下将64位无符号整数与32位无符号整数相乘。 64位数字存储为两个32位数字的数组。

换句话说,我如何从efa获得bc给出以下内容:

( a * 2^32 + b ) * c = e * 2^32 + f

abcef都是32位无符号整数,只有32位数学运算可用。

1 个答案:

答案 0 :(得分:3)

首先要意识到的是,我们将获得一个96位数字,如下所示:

(2 64 - 1)×(2 32 - 1)
= 2 64 ×2 32 - 2 64 - 2 32 + 1
= 2 96 - 2 64 - 2 32 + 1
< 2 96

接下来要认识到的是我们不能使用32位乘法。即使没有携带,结果也太大了。

(2 32 - 1)×(2 32 - 1)
= 2 32 ×2 32 - 2 32 - 2 32 + 1
= 2 64 - 2 33 + 1
≥2 32

我们需要执行16位乘法运算。即使使用16位进位,也可以使用32位数进行16位乘法,而不会发生溢出。

FFFF 16 ×FFFF 16 + FFFF 16
= FFFF_0000 16
< 2 32

如果我们将数字视为16位值,则乘法如下:

                  +-----+-----+-----+-----+
                  | ahi | alo | bhi | blo |
                  +-----+-----+-----+-----+

                              +-----+-----+
                           ×  | chi | clo |
                              +-----+-----+

===========================================

      +-----+-----+-----+-----+-----+-----+
      | dhi | dlo | ehi | elo | fhi | flo |
      +-----+-----+-----+-----+-----+-----+

我们都知道如何从小学进行上述乘法,对吗?

      +-----+-----+-----+-----+     +-----+
      | ahi | alo | bhi | blo |  ×  | clo |
      +-----+-----+-----+-----+     +-----+

      +-----+-----+-----+-----+-----+     +-----+
   +  | ahi | alo | bhi | blo |  0  |  ×  | chi |
      +-----+-----+-----+-----+-----+     +-----+

以下是我们需要的所有工具:

void mul16c(
   uint16_t i, uint16_t j, uint16_t cin,
   uint16_t *prod_ptr, uint16_t *cout_ptr
) {
   uint32_t prod = i * j + cin;
   *prod_ptr = prod & 0xFFFF:
   *cout_ptr = prod >> 16;
}

void add16c(
   uint16_t i, uint16_t j, uint16_t cin,
   uint16_t *sum_ptr, uint16_t* cout_ptr
) {
   uint32_t sum = i + j + cin;
   *sum_ptr = sum & 0xFFFF:
   *cout_ptr = sum >> 16;
}

我们可以按如下方式使用它们:

void mul64x32(
   uint32_t i[2], uint32_t j,
   uint32_t (*prod_ptr)[2], uint32_t *cout_ptr
) {
   uint16_t i16[4];
   i16[3] = i[1] >> 16;
   i16[2] = i[1] & 0xFFFF;
   i16[1] = i[0] >> 16;
   i16[0] = i[0] & 0xFFFF;

   uint16_t j16[2];
   j16[1] = j[0] >> 16;
   j16[0] = j[0] & 0xFFFF;

   uint16_t p[6];
   {
      uint16_t carry = 0;
      mul16c(i16[0], j16[0], carry, &(p[0]), &carry);
      mul16c(i16[1], j16[0], carry, &(p[1]), &carry);
      mul16c(i16[2], j16[0], carry, &(p[2]), &carry);
      mul16c(i16[3], j16[0], carry, &(p[3]), &carry);
      p[4] = carry;
      p[5] = 0;
   }

   uint16_t q[6];
   {
      uint16_t carry = 0;
      q[0] = 0;
      mul16c(i16[0], j16[1], carry, &(q[1]), &carry);
      mul16c(i16[1], j16[1], carry, &(q[2]), &carry);
      mul16c(i16[2], j16[1], carry, &(q[3]), &carry);
      mul16c(i16[3], j16[1], carry, &(q[4]), &carry);
      q[5] = carry;
   }

   uint16_t product[6];
   {
      uint16_t carry = 0;
      add16c(p[0], q[0], carry, &(product[0]), &carry);
      add16c(p[1], q[1], carry, &(product[1]), &carry);
      add16c(p[2], q[2], carry, &(product[2]), &carry);
      add16c(p[3], q[3], carry, &(product[3]), &carry);
      add16c(p[4], q[4], carry, &(product[4]), &carry);
      add16c(p[5], q[5], carry, &(product[5]), &carry);
   }

   (*prod_ptr)[0] = ( product[1] << 16 ) | product[0];
   (*prod_ptr)[1] = ( product[3] << 16 ) | product[2];
   *cout_ptr      = ( product[5] << 16 ) | product[4];
}

每个数组的元素零预计是该数字中最不重要的部分。