比较两个没有溢出的整数产品

Som*_*ium 5 c++

我需要找出是否a*b >= c*da,b,c,d32位整数上签名(我机器上的'int').

是否可以仅使用32位有符号整数来比较那些没有溢出的产品,这样结果对于所有可能的值都是正确的?

我想过a/d >= c/b.

然而,它在'2*7> = 3*5'(假)上失败,因为'2/5> = 3/7'('0> = 0')为真.

Jer*_*fin 6

目前,我将假设输入是有符号整数.

在这种情况下,我们想从检查标志开始.如果一方是负面的而另一方是正面的,这足以告诉我们结果(负面明显小于正面),所以我们已经完成了.

如果等式的两边都是正的或者都是负的,我们缓存结果的符号,然后去除符号,这样我们就可以处理乘法本身的无符号数.

一旦我们有无符号数,我们可以通过将每个32位整数视为两个不同数字的总和来进行乘法,一个表示输入数字的低位和一个高位.所以,你的每一个转换a,b,cd两个数字只有16显著位.所以,对于左侧,我们有:

al = a & 0xffff;
au = a >> 16;

bl = b & 0xffff;
bu = b >> 16;
Run Code Online (Sandbox Code Playgroud)

所以:

a * b 
Run Code Online (Sandbox Code Playgroud)

...是相同的:

(al + au << 16) * (bl + bu << 16)
Run Code Online (Sandbox Code Playgroud)

并使用分配属性,我们可以将其转换为:

al * bl + au<<16 * bl + al * bu<<16 + au<<16 * bu<<16
Run Code Online (Sandbox Code Playgroud)

a * (b * c)=开始(a * b) * c,我们可以在进行其他乘法完成所有的位移,因此变为:

al * bl +            // we'll call this intermediate result "lower"
(au * bl) << 16 +
(al * bu) << 16 +    // we'll call the sum of these two "mid" 
(au * bu) << 32      // we'll call this one "upper"
Run Code Online (Sandbox Code Playgroud)

现在重要一点:我们的位掩码确保每个乘法步骤的输入只有16个有效位,因此每个中间结果只有32个有效位,因此每个都将适合单个32位整数而不会溢出.

从那里,我们必须总结条款.这有点不重要,但仍然相当容易处理.首先,我们必须弄清楚一个术语的总和是否会产生一个进位.一种方法是这样的:

bool carry(unsigned a, unsigned b) { 
    return a > (std::number_limits<unsigned>::max() - b);
}
Run Code Online (Sandbox Code Playgroud)

然后我们的结果是低+中<< 16 +上<< 32.因为我们处理的是32位整数,所以最简单的方法就是把mid它分成上半部分和下半部分.它的下半部分将被添加到lower其上半部分upper.然后,我们的结果将分布在两个(无符号)32位整数中,一个包含lower + mid_lower,另一个包含upper + mid_upper + carries.

从那里可以很简单地恢复我们在开始时存储的标志,然后比较上半部分,当且仅当它们相等时,比较下半部分.

如果你的号码开头是无符号的,那么你可以稍微跳过涉及标志的部分.

  • @KlamerSchutte:是的,您可以通过首先查看高位字来优化,如果它足够不同,那么无需进一步计算即可得到答案. (2认同)
  • 可能不是最佳甚至是正确的,但我写了一些代码.http://coliru.stacked-crooked.com/a/54ff50837882c950 (2认同)