问题描述
如何安全地将一对uint64
值相乘以得到一对相同类型的LSB和MSB?
typedef struct uint128 {
uint64 lsb;
uint64 msb;
};
uint128 mul(uint64 x,uint64 y)
{
uint128 z = {0,0};
z.lsb = x * y;
if (z.lsb / x != y)
{
z.msb = ?
}
return z;
}
- 我可以正确计算LSB吗?
- 如何正确计算MSB?
谢谢!
解决方法
如评论中所述,最好的解决方案可能是使用为您执行此操作的库。但是我将解释没有图书馆怎么办,因为我认为您要求学习一些东西。这可能不是一种非常有效的方法,但是它可以工作。
当我们在学校里并且必须在没有计算器的情况下将2个数字相乘时,我们将2个数字相乘,结果得到1-2个数字,并将其写下来,最后我们将它们加起来。我们把乘法加起来,所以我们只需要一次计算一位数乘法。如果CPU上的数字更大,则可能发生类似的情况。但是这里我们不使用十进制数字,而是使用寄存器大小的一半作为数字。这样一来,我们就可以在一个寄存器中将2位数字乘以2位。十进制13 * 42可以计算为:
3* 2 = 0 6
10* 2 = 2 0
3*40 = 1 2 0
10*40 = 0 4 0 0
--------
0 5 4 6
使用整数可以完成类似的操作。为简单起见,我将2个8位数字乘以8位CPU上的16位数字,因为我一次只能将4位乘以4位。让我们将0x73与0x4F相乘。
0x03*0x0F = 0x002D
0x70*0x0F = 0x0690
0x03*0x40 = 0x00C0
0x70*0x40 = 0x1C00
-------
0x22BD
您基本上创建了一个由4个元素组成的数组,在这种情况下,每个元素的类型均为uint32_t
,如果结果为,则将单个乘法的结果存储或添加到数组的正确元素中。单个乘法对于单个元素而言太大,请将较高的位存储在较高的元素中。如果加法溢出,则将1携带到下一个元素。最后,您可以将数组的2个元素组合在一起,在您的情况下可以合并为两个uint64_t
。