我正在阅读CSAPP并尝试完成作业问题。假设w = 32,2.75是关于从两个32位无符号整数乘以高32位。给定函数int signed_high_prod(int x, int y)
,它计算x的高阶32位。 y表示x和y为二进制补码形式的情况。 int signed_high_prod(int x, int y)
应该用于实施unsigned int unsigned_high_prod(unsigned x, unsigned y)
。
通过谷歌搜索我发现x'.y' = x.y + x.y_31.2^32 + y.x_31.2^32 + x_31.y_31.2^64
,其中x'和y'分别是x和y的无符号形式。
我仍然无法理解答案。
unsigned unsigned_high_prod(unsigned x, unsigned y){
unsigned p = (unsigned) signed_high_prod((int) x, (int) y)
if((int) x < 0){
p += y;
}
if((int) y < 0){
p += x;
}
return p;
}
为什么最终用语对结果没有影响?为何x < 0
x_31 = 1
,加上y
?与y
相同。
答案 0 :(得分:2)
要执行位级乘法,我们必须首先扩展位,然后进行一系列的移位和加法。例如,假设w = 3,请x = [011]
和y = [101]
。 (即x = 3
和y = -3 (signed) or 5 (unsigned)
)
要执行未签名的产品,我们首先按如下方式进行零扩展:(忽略位6及以上)
000 011
* 000 101
--------
000 011
+ 001 100
--------
001 111
========
因此,无符号高位为[001]
要执行已签名的产品,我们首先按以下方式进行签名扩展:
000 011
* 111 101
--------
000 011
+ 001 100
+ 011 000 **
+ 110 000 **
+ 100 000 **
--------
110 111
========
因此,带符号的高位是[110]
注意,有符号和无符号高位之间的差异(如上面**所示)是我们在签名的情况下添加了[111] * [011]
。因此,我们必须减去此数量以获得无符号高位。
The unsigned high order bits = [110] - [111] * [011]
= [110] - [101]
= [110] + [011] ??
= [001] (as above)
由于[111] = -1
,更正金额- [111] * [011]
相当于- (-1 * x) = x
。
因此,当y
为负数时(如本例所示),我们必须通过添加x
来更正结果。同样地,当x
为否定时,我们必须通过添加y
来更正结果。
?? -[101] = ~[101] + 1 = [010] + [001] = [011]
答案 1 :(得分:1)
要将带符号,2的补码,32位整数转换为无符号的32位整数,如果它是负数,我们将其值加2³。
signed_high_prod
执行带符号的乘法并返回乘积的第63到32位。我们希望unsigned_high_prod
对无符号乘法执行相同操作并使用signed_high_prod
,然后补偿无符号和有符号乘法之间的差异。
Let N(i) = { 1, i < 0
{ 0, i >= 0
Let U(i) = i + N(i)·2³² { −2³¹ <= i < 2³¹ }
然后:
U(x)·U(y) = (x + N(x)·2³²)·(y + N(y)·2³²)
= x·y + x·N(y)·2³² + N(x)·2³²·y + N(x)·2³²·N(y)·2³²
= x·y + x·N(y)·2³² + y·N(x)·2³² + N(x)·N(y)·2⁶⁴
⌊U(x)·U(y)/2³²⌋ = ⌊x·y/2³²⌋ + x·N(y) + y·N(x) + N(x)·N(y)·2³²
由于对无符号32位整数的算术将以2 3 2为模进行,我们有:
⌊U(x)·U(y)/2³²⌋ mod 2³² = (⌊x·y/2³²⌋ + x·N(y) + y·N(x) + N(x)·N(y)·2³²) mod 2³²
= (⌊x·y/2³²⌋ + x·N(y) + y·N(x)) mod 2³²
我认为会考虑您的unsigned_high_prod
功能执行的计算。
答案 2 :(得分:1)
这是您应该了解的前提条件
x'和y'是无符号的,而x,y是有符号的
通过使用“ mod 2 ^ 32”获得x * y的低阶32位
通过使用“ / 2 ^ 32”来获得x * y的高阶32位
开始吧
要获取x'* y'的高32位,我们使用“ / 2 ^ 32”
x'.y' / 2^32=unsigned_high_prod(unsigned x,unsigned y)
=(x.y + x.y_31.2^32 + y.x_31.2^32 + x_31.y_31.2^64)/2^32
=x.y/2^32 + x.y_31 + y.x_31 + x_31.y_31.2^32
=signed_high_prod(int x, int y) + x.y_31 + y.x_31 + x_31.y_31.2^32
但是我们得到的不限于32位,显然结果y.x_31 + x_31.y_31.2 ^ 32溢出了,我们应该得到的只是32位数字。因此,我们使用mod 2 ^ 32来获得正确的答案。
(signed_high_prod(int x,int y)+ x.y_31 + y.x_31 + x_31.y_31.2 ^ 32)mod 2 ^ 32 = signed_high_prod(int x,int y)+ x.y_31 + y.x_31
其结尾为:
unsigned_high_prod(unsigned x,unsigned y)= Signed_high_prod(int x,int y)+ x.y_31 + y.x_31
因此很明显,代码是正确的。
因为如果int x <0,则意味着x_31 == 1,因此必须加y。
否则x_31 == 0,因为y.x_31 == 0,您无需做任何事情
与y相同