获取的64位整数乘法的高位部分 [英] Getting the high part of 64 bit integer multiplication

查看:329
本文介绍了获取的64位整数乘法的高位部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,说:

  uint64_t中我;
uint64_t中D];
 

然后 I *Ĵ将产生一个 uint64_t中具有的价值,倍增的下部之间Ĵ,即(I * j)条模2 ^ 64 。 现在,如果我想乘法较高的部分?我知道,存在一个汇编指令使用32位整数的时候做这样的事情,但我不熟悉在所有与装配,所以我希望寻求帮助。

什么是最有效的方法,使这样的:

  uint64_t中K = mulhi(I,J);
 

解决方案

如果你正在使用gcc,你拥有的版本支持128位数字(尝试使用__uint128_t)不是执行128乘法和提取的高64位的可能将得到的结果的最有效的方式。

如果你的编译器不支持128位的数字,然后Yakk的答案是正确的。然而,它可能是太短一般消耗。特别是,在实际的实现必须要小心溢出64位integars的。

的简单便携溶液他建议是将每个a和b打入2个32位数字,然后乘使用64位乘法运算的那些32位数字。如果我们写:

  uint64_t中a_lo =(uint32_t的)一个;
uint64_t中a_hi = a取代;> 32;
uint64_t中b_lo =(uint32_t的)B:
uint64_t中b_hi = B>> 32;
 

那么很明显的是:

  A =(a_hi<< 32)+ a_lo;
B =(b_hi&其中;&所述; 32)+ b_lo;
 

  A * B =((a_hi<< 32)+ a_lo)*((b_hi<< 32)+ b_lo)
      =((a_hi * b_hi)其中;&所述; 64)+
        ((a_hi * b_lo)其中;&所述; 32)+
        ((b_hi * a_lo)其中;&所述; 32)+
          a_lo * b_lo
 

提供使用128位(或更大)算术进行计算。

但这个问题需要我们进行全部采用64位运算的calculcations,所以我们不用担心溢出。

由于a_hi,a_lo,b_hi和b_lo都是32位无符号数,他们的产品将适合在一个无符号的64位数字,没有溢出。然而,上述的计算的中间结果不会

下面code将实现mulhi(A,B),当mathemetics必须执行模2 ^ 64:

  uint64_t中a_lo =(uint32_t的)一个;
uint64_t中a_hi = a取代;> 32;
uint64_t中b_lo =(uint32_t的)B:
uint64_t中b_hi = B>> 32;

uint64_t中a_x_b_hi = a_hi * b_hi;
uint64_t中a_x_b_mid = a_hi * b_lo;
uint64_t中b_x_a_mid = b_hi * a_lo;
uint64_t中a_x_b_lo = a_lo * b_lo;

uint64_t中carry_bit =((uint64_t中)(uint32_t的)a_x_b_mid +
                         (uint64_t中)(uint32_t的)b_x_a_mid +
                         (a_x_b_lo>> 32))>> 32;

uint64_t中multhi = a_x_b_hi +
                     (a_x_b_mid>> 32)+(b_x_a_mid>> 32)+
                     carry_bit;

返回multhi;
 

由于Yakk指出,如果你不介意由高64位+1被关闭,你可以省略进位的计算。

In C++, say that:

uint64_t i;
uint64_t j;

then i * j will yield an uint64_t that has as value the lower part of the multiplication between i and j, i.e., (i * j) mod 2^64. Now, what if I wanted the higher part of the multiplication? I know that there exists an assembly instruction do to something like that when using 32 bit integers, but I am not familiar at all with assembly, so I was hoping for help.

What is the most efficient way to make something like:

uint64_t k = mulhi(i, j);

解决方案

If you're using gcc and the version you have supports 128 bit numbers (try using __uint128_t) than performing the 128 multiply and extracting the upper 64 bits is likely to be the most efficient way of getting the result.

If your compiler doesn't support 128 bit numbers, then Yakk's answer is correct. However, it may be too brief for general consumption. In particular, an actual implementation has to be careful of overflowing 64 bit integars.

The simple and portable solution he proposes is to break each of a and b into 2 32-bit numbers and then multiply those 32 bit numbers using the 64 bit multiply operation. If we write:

uint64_t a_lo = (uint32_t)a;
uint64_t a_hi = a >> 32;
uint64_t b_lo = (uint32_t)b;
uint64_t b_hi = b >> 32;

then it is obvious that:

a = (a_hi << 32) + a_lo;
b = (b_hi << 32) + b_lo;

and:

a * b = ((a_hi << 32) + a_lo) * ((b_hi << 32) + b_lo)
      = ((a_hi * b_hi) << 64) +
        ((a_hi * b_lo) << 32) +
        ((b_hi * a_lo) << 32) +
          a_lo * b_lo

provided the calculation is performed using 128 bit (or greater) arithmetic.

But this problem requires that we perform all the calculcations using 64 bit arithmetic, so we have to worry about overflow.

Since a_hi, a_lo, b_hi, and b_lo are all unsigned 32 bit numbers, their product will fit in an unsigned 64 bit number without overflow. However, the intermediate results of the above calculation will not.

The following code will implement mulhi(a, b) when the mathemetics must be performed modulo 2^64:

uint64_t    a_lo = (uint32_t)a;
uint64_t    a_hi = a >> 32;
uint64_t    b_lo = (uint32_t)b;
uint64_t    b_hi = b >> 32;

uint64_t    a_x_b_hi =  a_hi * b_hi;
uint64_t    a_x_b_mid = a_hi * b_lo;
uint64_t    b_x_a_mid = b_hi * a_lo;
uint64_t    a_x_b_lo =  a_lo * b_lo;

uint64_t    carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
                         (uint64_t)(uint32_t)b_x_a_mid +
                         (a_x_b_lo >> 32) ) >> 32;

uint64_t    multhi = a_x_b_hi +
                     (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
                     carry_bit;

return multhi;

As Yakk points out, if you don't mind being off by +1 in the upper 64 bits, you can omit the calculation of the carry bit.

这篇关于获取的64位整数乘法的高位部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆