2016-01-15 58 views
0

這裏是我的代碼:爲什麼移位負數不起作用?

long x1 = -123; 
    long y1 = -312; 
    long x2 = -111; 
    long y2 = -112; 
    long packed = x1 | y1 << 15 | x2 << 30 | y2 << 45; 
    Debug.log("x1:" + ((packed) & 0b111111111111111)); 
    Debug.log("y1:" + ((packed >> 15) & 0b111111111111111)); 
    Debug.log("x2:" + ((packed >> 30) & 0b111111111111111)); 
    Debug.log("y2:" + ((packed >> 45) & 0b111111111111111)); 

我需要X1,X2,X3,X4將上升到16384(2^14)。所以加上+ - 符號,總共15位。爲什麼我得到不正確的值?

+0

@AndrewMorton爲什麼不呢?他們有15個,因爲這個數字可以達到14位(+號+1) –

+0

Doh!也許我需要戴眼鏡。 –

回答

1

在將值組合在一起之前,您需要掩蓋您感興趣的位。 -111中的大部分位都被設置,並且它們正在與您打包的其他值進行比較。

使用位域可能會更適合你,你可以讓編譯器處理所有掩蔽和你移位:

struct packedCoords 
{ 
    long long x1 : 15; 
    long long y1 : 15; 
    long long x2 : 15; 
    long long y2 : 15; 
}; 

packedCoords test; 
test.x1 = -123; 
test.y1 = -312; 
test.x2 = -111; 
test.y2 = -112; 

printf("sizeof packedCoords = %d\n", sizeof(packedCoords)); 
printf("x1: %d\n", static_cast<int>(test.x1)); 
printf("y1: %d\n", static_cast<int>(test.y1)); 
printf("x2: %d\n", static_cast<int>(test.x2)); 
printf("y2: %d\n", static_cast<int>(test.y2)); 
+0

我實際上使用java ...我添加了標籤。而且我不需要結構,我需要位掩碼。 –

1

我設法解決這個問題是這樣的:

long packed = x1>0?x1:(-x1) | (x1>0?1:0) << 15; 
long decodedX1 = (((packed) & 0b11111111111111)); 
if(((packed >> 14) & 0b1) == 0) 
    decodedX1 = -decodedX1; 

我知道,看起來很討厭。我們強制它是積極的,然後手動設置一個符號位。

1

我看到你推斷(可能來自IronMensan的回答)額外設置位是問題,需要被掩蓋掉。

作爲對我的背對前評論的懺悔,我寫了一些代碼並對其進行了概括,以減少對「幻數」的使用。這是在C#中,但是這是相當類似Java用於此目的:

long x1 = -345; 
long y1 = 299; 
long x2 = -111; 
long y2 = -112; 

int bitLengthToPack = 15; 

long signBit = 1 << (bitLengthToPack - 1); 
long dataBits = (signBit << 1) - 1; 
long upperBits = ~dataBits; 

long packed = (x1 & dataBits) | (y1 & dataBits) << bitLengthToPack | (x2 & dataBits) << (bitLengthToPack * 2) | (y2 & dataBits) << (bitLengthToPack * 3); 

long x1e = packed & dataBits; 

if ((x1e & signBit) > 0) 
{ 
    x1e = x1e | upperBits; 
} 

Console.WriteLine("x1e: " + x1e); 

long y1e = (packed >> bitLengthToPack) & dataBits; 
if ((y1e & signBit) > 0) 
{ 
    y1e = y1e | upperBits; 
} 

Console.WriteLine("y1e: " + y1e); 

long x2e = (packed >> (bitLengthToPack * 2)) & dataBits; 
if ((x2e & signBit) > 0) 
{ 
    x2e = x2e | upperBits; 
} 

Console.WriteLine("x2e: " + x2e); 

long y2e = (packed >> (bitLengthToPack * 3)) & dataBits; 
if ((y2e & signBit) > 0) 
{ 
    y2e = y2e | upperBits; 
} 

Console.WriteLine("y2e: " + y2e); 

如果你有一個較小的範圍內的值,可以減少bitLengthToPack值。我想不出從解包中刪除條件的方法;也許有人比我更聰明。

1

試試這個

long pack(long v, int shift) { 
    return (v & 0b111111111111111) << (shift * 15); 
} 

long unpack(long v, int shift) { 
    long r = v >> (shift * 15) & 0b111111111111111; 
    if ((r & 0b100000000000000) != 0) 
     r |= ~0b111111111111111; 
    return r; 
} 

long x1 = -123; 
    long y1 = -312; 
    long x2 = -111; 
    long y2 = -112; 
    long packed = pack(x1, 0) | pack(y1, 1) | pack(x2, 2) | pack(y2, 3); 
    Debug.log("x1:" + unpack(packed, 0)); 
    Debug.log("y1:" + unpack(packed, 1)); 
    Debug.log("x2:" + unpack(packed, 2)); 
    Debug.log("y2:" + unpack(packed, 3)); 

廣義版本:

long pack(long v, int width, int shift) { 
    long mask = -1 >>> Long.SIZE - width; 
    return (v & mask) << (shift * width); 
} 

long unpack(long v, int width, int shift) { 
    long mask = -1 >>> Long.SIZE - width; 
    long r = v >> (shift * width) & mask; 
    if ((r & (1 << width - 1)) != 0) 
     r |= ~mask; 
    return r; 
} 

在這種情況下,參數width指定15。

+0

噢,我想出了一個更整潔的版本(我不是說你的答案是以我的方式得到的,我敢肯定它不是)。你是否想將它推廣到允許不同範圍的值,即去除像15這樣的幻數和那些二進制文字? –