簡體   English   中英

確定32位int的符號

[英]Determine the sign of a 32 bit int

僅使用:

〜&^ | + << >>

沒有LOOPS

我需要確定32位整數的符號,如果為正則需要返回1,如果為0則返回0,如果為負則返回-1。

有任何想法嗎? 我首先考慮轉移31位,然后看着那個標志,但顯然不會工作,現在我有點卡住了。

試試這個:

(x >> 31) | (((0 - x) >> 31) & 1)

這個怎么樣:

(x >> 31) | (((~x + 1) >> 31) & 1)

編輯2:

回應評論中提出的問題(或者說是挑選)

這些解決方案的假設是有效的:

  1. x是32位有符號整數類型。
  2. 在這個系統上,帶符號的32位整數是兩個補碼。 (右移算術)
  3. 算術溢出的環繞。
  4. 對於第一個解決方案,文字0與x的類型相同。

如果條件表達式(不if語句)和減法是允許的,最簡單和清晰的解決方案(IMO)是:

int sign = (v > 0) - (v < 0);

不使用減法(假設int是32位):

#include <stdio.h>
#include <assert.h>
#include <limits.h>

int process(int v) {
    int is_negative = (unsigned int)v >> 31; // or sizeof(int) * CHAR_BIT - 1
    int is_zero = !v;
    int is_positive = !is_negative & !is_zero;
    int sign = (is_positive + ~is_negative) + 1;
    return sign;
}

int main() {
    assert(process(0) == 0);
    printf("passed the zero test\n");
    for (int v = INT_MIN; v < 0; v++) {
        assert(process(v) == -1);
    }
    printf("passed all negative tests\n");
    for (int v = 1; v < INT_MAX; v++) {
        assert(process(v) == +1);
    }
    printf("passed all positive tests\n");
    return 0;
}

結果如下:

$ gcc -o test test.c -Wall -Wextra -O3 -std=c99 && ./test && echo $#
passed zero test
passed all negative tests
passed all positive tests
0

為什么需要使用按位運算符?

int get_sign(int value)
{
    return (value < 0) ? -1 : (int)(value != 0);
}

如果您必須使用按位運算符,則可以使用&運算符檢查負值,無需轉換:

int get_sign(int value)
{
    return (value & 0x80000000) ? -1 : (int)(value != 0);
}

如果你想轉移:

int get_sign(int value)
{
    return ((value >> 31) & 1) ? -1 : (int)(value != 0);
}

有點復雜,但有這樣的:

(~((x >> 31) & 1) + 1) | (((~x + 1) >> 31) & 1)

這應該考慮到班次是填寫1還是0的模糊性

對於細分,我們有這個構造的任何地方:

(z >> 31) & 1

當否定時將導致1,否則將導致0。

我們有的地方:

(~z + 1)

我們得到否定的數字(-z)

因此,如果x為負,則前半部分將產生0xFFFFFFFF(-1)的結果,如果x為正,則后半部分將產生0x00000001(1)。 如果兩者都不為真,則按位或將它們組合在一起將產生0x00000000(0)。

我不確定這是絕對理想的做事方式,但我認為這是合理的便攜性,至少比你的方式簡單:

#define INT_BITS 32

int sign(int v) { 
    return (!!v) | -(int)((unsigned int)v >> (INT_BITS-1));
}

關於什么:

int getsign(int n)
{
  return (!!n) + (~((n >> 30) & 2) + 1);
}

..對於32位signed int,僅限2的補碼。

!!n如果n非零,則!!n給出1。 ((n >> 30) & 2)如果設置了高位(符號)則給出2。 按位NOT和+1取2的補碼,給出-2或0.對於負值,加法給出-1(1 + -2),對於零,給出0(0 + 0),+1(1 + 0)為正值。

假設實現定義了算術右移:

(x>>31) | !!x

與Mystical的答案不同,沒有UB。

並且,如果您還想支持將右移定義為算術移位的系統:

~!(x>>31)+1 | !!x

編輯:對不起,我省略了! 在第二個版本。 它應該是:

~!!(x>>31)+1 | !!x

這個版本仍然是依賴於實現是二進制補碼和具有或者算術邏輯右移,即如果實現定義的行為是別的東西完全可能打破。 但是,如果將類型更改為無符號類型,則所有實現定義的行為都將消失,結果為-1U0U1U具體取決於x的“符號”(高位和零/非零狀態)。

迪米特里的想法可以簡化為(!! x) - ((x >> 30)&2)

而且只是提出一個更神秘的解決方案:

~!x & ((-((unsigned) x >> 31)) | !!x)

暫無
暫無

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

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