【问题标题】:get the 32 high bits of multiplying two unsigned integers (HW)获得两个无符号整数(HW)相乘的高 32 位
【发布时间】:2016-05-03 13:24:04
【问题描述】:

我正在阅读 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 &lt; 0 所以x_31 = 1,再加上y?和y一样。

【问题讨论】:

    标签: c bits


    【解决方案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³² 为模,因此我们有:

    ⌊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³²,会丢失一些位吗?
    • @user2018791 在这种情况下不是。乘法的结果适合 64 位。除以 2³²,四舍五入到负无穷大(“地板”)为我们提供了前 32 位。 32 位无符号数上的 mod 2³² 对其没有影响。
    • @user2018791 最后的 mod 2³² 步骤主要是为了表明 unsigned_high_prod 函数不需要考虑涉及 N(x)·N(y)·2³² 的项,因为它是 2³² 的倍数,因此等于 0 mod 2³²。请注意,(A mod N) + (B mod N) 与 (A + B) mod N 相同,因此 mod 2³² 可以在每个术语上单独完成,并且不会有任何区别。 IE。 (⌊x·y/2³²⌋ + x·N(y) + y·N(x) + N(x)·N(y)·2³²) mod 2³² 等于 ⌊x·y/2³²⌋ mod 2³² + x·N(y) mod 2³² + y·N(x) mod 2³² + N(x)·N(y)·2³² mod 2³²
    【解决方案2】:

    要执行位级乘法,我们必须首先扩展位,然后进行一系列移位和加法。例如,假设 w = 3,让x = [011]y = [101]。 (即x = 3y = -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]

    【讨论】:

    • 这个例子解释了问题中的代码并说明了@Ian Abbot 的很好的证明。
    【解决方案3】:
    • x'.y' = x.y + x.y_31.2^32 + y.x_31.2^32 + x_31.y_31.2^64

    这里是你应该知道的先决条件

    1. x' 和 y' 是无符号的,x,y 是有符号的

    2. 使用“mod 2^32”获取x*y的低32位

    3. 使用“/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

    否则x_31 == 0,因为y.x_31 == 0,你什么都懒得做

    和y一样

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      相关资源
      最近更新 更多