【问题标题】:Signed 64 by 32 integer division有符号 64 x 32 整数除法
【发布时间】:2009-07-06 21:18:20
【问题描述】:

假设您有一个机器指令 udive,它通过(32 位被除数

// assume: a / b guaranteed not to overflow
a = 64bit dividend, a.h & a.l are hi & lo 32bits respectively
b = 32bit divisor

q1 = udive(a.h, b)  // (a.h << 32) / b
r1 = -(q1 * b)      // remainder of the above, shortcut since a.h & 0xffffffff == 0
q2 = a.l / b        // a.l / b using regular unsigned division
r2 = a.l - (q2 * b) // remainder of the above
q = q1 + q2
r = r1 + r2

// r < r2, r overflowed and is >32bits, implies r > b since b is 32bits
// r >= b, quotient too small by 1, adjust
if (r < r2) or (r >= b)
    q = q + 1
return q

但是,签署的案例给我带来了问题。假设一个等效的 sdive 指令执行 udive 的签名版本,我无法完全弄清楚如何处理余数等等。

【问题讨论】:

  • 本能地这感觉像是一个二进制补码问题。由于我不是这方面的专家,我无法进一步建议您,但也许这是一个线索。

标签: integer precision division signed


【解决方案1】:

我认为,如果明确说明哪些变量是 32 位、哪些是 64 位以及比较是有符号还是无符号,那么您的无符号代码会更容易阅读。

Hacker's Delight 一书通常适用于这类低级算术知识。我目前手头没有副本,但它的代码 64/64->64 给定 64/32->32 在线:http://www.hackersdelight.org/HDcode/newCode/divDouble.c

通过简单地获取输入的绝对值,进行无符号除法,然后在输入具有不同符号时翻转结果位的符号来实现有符号情况。这向我表明这可能是最好的方法(证明正确肯定比替代方法更容易)。您可能需要将除数作为可能的最小整数的特殊情况,如果它不只是被淘汰的话。

【讨论】:

    【解决方案2】:

    感谢您的回答。我看过Hacker's Delight。如果您查看 HD 中的 divdi3 函数,则会调用 DIVS,即 64/32->32 指令,当除数为 32 位并且已知结果不会溢出时。我所在的机器没有通用的 64/32->32 指令,它有上面提到的特殊情况。上面的 64/32->32 函数是我在未签名情况下对 DIVU 的实现,所以我正在尝试为 DIVS 制定类似的方法。

    我可以忘记 DIVS 路径,但这是最常见的情况,我想尽可能多地使用它,这只是一个棘手的实现。

    抱歉,伪代码不清楚,但所有内容都是无符号的,并且大部分是 32 位的。

    DIVU(uint64 a, uint32 b) {
    // assume: a / b guaranteed not to overflow
    // a = 64bit dividend, a.h & a.l are hi & lo 32bits respectively
    // b = 32bit divisor
    
    uint32 q1 = udive(a.h, b)      // (a.h << 32) / b
    uint32 r1 = -(q1 * b)          // remainder of the above, shortcut for (a.h << 32) - (q1 * b) since (a.h << 32) & 0xffffffff == 0
    uint32 q2 = a.l / b            // a.l / b using regular unsigned division
    uint32 r2 = a.l - (q2 * b)     // remainder of the above
    uint32 q = q1 + q2
    uint32 r = r1 + r2
    
    // r < r2, r overflowed and is >32bits, implies r > b since b is 32bits
    // r >= b, quotient too small by 1, adjust
    if (r < r2) or (r >= b)
            q = q + 1
    return q
    }
    

    【讨论】:

      【解决方案3】:

      可以忽略divdi3调用div的特殊优化案例;我想提请注意的是,当 divdi3 需要进行全强度除法时,它通过调用 udivdi3 而不是通过等效于 udivdi3 算法的有符号除法来实现。

      查看 Knuth vol 2,我看到他基本上还说,您通过获取绝对值、进行无符号除法然后修复符号位的过程来进行有符号除法。这对我来说很直观,因为有符号的 2s 补码没有 a == (a.h * 2^32) + a.l 那样的无符号数所具有的便利属性,因此通过操作来组装 64 位操作并不容易两半分开。

      前后摆弄不应该是无符号除法上的那么多额外循环......

      PS:这到底是什么奇怪的 CPU? :-)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-15
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 2018-11-05
        • 2013-12-22
        • 1970-01-01
        相关资源
        最近更新 更多