簡體   English   中英

大於C中的功能

[英]Greater than function in C

我知道這是一個古老的問題,你可能也遇到過這個問題,但我的解決方案中有一個錯誤,我不知道如何解決它。 我需要編寫一個比較兩個整數的函數。 我只允許使用操作(!,〜,&,^,|,+,>>,<<),也沒有控制結構(if,else循環等)。

isGreater(int x, int y) {
    //returns 1 if x > y.
      return ((y+(~x+1))>>31)&1;
}

我的想法很簡單,我們計算yx,我們移動31得到符號位,如果它是負數,那么我們返回零,否則我們返回1.當x為負時失敗而falsly返回1雖然它應該返回零。 我被困在這里,不知道該怎么辦。

我們假設整數是32位並使用二進制補碼表示。 這個問題與可移植性無關。 一些幫助將非常感激。

提前致謝

Hacker's Delight有一章比較謂詞,這正是我們在這里所需要的。

它寫的一件事是:

x < y: (x - y) ^ ((x ^ y) & ((x - y) ^ x))

我們幾乎可以直接使用,除了交換xy之外,減法必須用合法的東西替換,結果出現在最高位而不是最低位。 幸運的是a - b == ~(~a + b)因此不太難。 首先應用這些轉換:

// swap x <-> y
(y - x) ^ ((y ^ x) & ((y - x) ^ y))
// rewrite subtraction
~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))
// get answer in lsb
((~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))) >> 31) & 1

這里有一個網站說它有效。

如果允許局部變量,可以通過分解子表達式來簡化一點
~(~y + x)

int diff = ~(~y + x);
return ((diff ^ ((y ^ x) & (diff ^ y))) >> 31) & 1;

首先讓我們澄清一下我們假設:

  • 負整數用2的補碼表示
  • int正好是32位寬, long long正好是64位寬
  • 右移一個負數是算術移位

解決方案中的(~x+1)部分存在問題,該部分應返回-x 的問題是,的絕對值INT_MIN比的絕對值大INT_MAX ,從而當X是INT_MIN然后(~x+1)產生INT_MIN代替-INT_MIN如你預期。

在解決方案的y+(-x)部分也存在溢出問題(第二步)。

現在,如果允許使用除int之外的其他類型,我們可以通過在轉換之前將值轉換為long long來解決這兩個問題,假設它是64位類型,這樣(~x+1)將返回預期的結果-xy+(-x)不會導致任何溢出。 那么,顯然,我們必須將>>31位更改為>>63

最終解決方案如下:

static bool isGreater(int x, int y)  {
    long long llx = x;
    long long lly = y;
    long long result = ((lly+(~llx+1))>>63)&1;
    return result;
}

用一些角點測試它是可行的,例如x == INT_MINx == 0x == INT_MAX

int main(void) {
    int x = INT_MIN;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
    x = INT_MAX;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
    x = 0;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
}

這在我的特定機器上使用我的特定編譯器是成功的。 測試耗時163秒。

但同樣,這取決於能否使用除int之外的其他類型(但是再次使用更多的工作,您可以使用int模擬long long )。

如果您使用int32_tint64_t而不是intlong long ,那么整個事情可以更加可移植。 但是,它仍然不可移植:

ISO / IEC 9899:2011§6.5.7按位移位算子

5 E1 >> E2的結果右移E2位位置。 如果E1具有無符號類型或者E1具有有符號類型和非負值,則結果的值是E1 / 2E2的商的整數部分。 如果E1具有帶符號類型和負值,則結果值是實現定義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM